Quickstart
Prerequisites
Before you get started, make sure you have the following installed:
- Node.js v18.17 or later
- npm v9 or later
- git v2.14.1 or later
- You will also need to create an AWS Account. Note that AWS Amplify is part of the AWS Free Tier.
- Configure your AWS account to use with Amplify instructions.
This Quickstart guide will walk you through how to build a Todo application for Android or iOS using Expo's TypeScript template.
npx create-expo-app my_amplify_app -t expo-template-blank-typescriptcd my_amplify_app
Create Backend
The easiest way to get started with AWS Amplify is through npm with create-amplify
command. You can run it from your base project directory.
cd my-appnpm create amplify@latest? Where should we create your project? (.) # press enter
Running this command will scaffold Amplify backend files in your current project with the following files added:
├── amplify/│ ├── auth/│ │ └── resource.ts│ ├── data/│ │ └── resource.ts│ ├── backend.ts│ └── package.json├── node_modules/├── .gitignore├── package-lock.json├── package.json└── tsconfig.json
To deploy your backend use Amplify's per-developer cloud sandbox. This feature provides a separate backend environment for every developer on a team, ideal for local development and testing. To run your application with a sandbox environment, you can run the following command:
npx ampx sandbox
Adding Authentication
The initial scaffolding already has a pre-configured auth backend defined in the amplify/auth/resource
.ts file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
The fastest way to get your login experience up and running is to use our Authenticator UI component available in the Amplify UI library.
To use the Authenticator, you need to add the following dependencies to your project:
npm add \ @aws-amplify/ui-react-native \ @aws-amplify/react-native \ aws-amplify \ @react-native-community/netinfo \ @react-native-async-storage/async-storage \ react-native-safe-area-context \ react-native-get-random-values \ react-native-url-polyfill
Then install the iOS cocoapods for targeting iOS by running:
npx pod-install
Next, update the App.tsx
file with the following:
import React from "react";import { Button, View, StyleSheet, SafeAreaView } from "react-native";
import { Amplify } from "aws-amplify";import { Authenticator, useAuthenticator } from "@aws-amplify/ui-react-native";
import outputs from "./amplify_outputs.json";
Amplify.configure(outputs);
const SignOutButton = () => { const { signOut } = useAuthenticator();
return ( <View style={styles.signOutButton}> <Button title="Sign Out" onPress={signOut} /> </View> );};
const App = () => { return ( <Authenticator.Provider> <Authenticator> <SafeAreaView> <SignOutButton /> </SafeAreaView> </Authenticator> </Authenticator.Provider> );};
const styles = StyleSheet.create({ signOutButton: { alignSelf: "flex-end", },});
export default App;
The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
Run your application in your local environment again. You should be presented with a login experience now.
Adding Data
The initial scaffolding already has a pre-configured data backend defined in the amplify/data/resource.ts
file. The default example will create a Todo model with content
field.
Let's modify this to add the following:
- A boolean
isDone
field. - An authorization rules specifying owners, authenticated via your Auth resource can "create", "read", "update", and "delete" their own records.
- Update the
defaultAuthorizationMode
to sign API requests with the user authentication token.
import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
const schema = a.schema({ Todo: a .model({ content: a.string(), isDone: a.boolean() }) .authorization(allow => [allow.owner()])});
export type Schema = ClientSchema<typeof schema>;
export const data = defineData({ schema, authorizationModes: { defaultAuthorizationMode: 'userPool' }});
Next, let's implement UI to create, list, and delete the to-do items. Create a src
folder, and within the folder, create a new file called TodoList.tsx
. This page will contain information about creating, reading, updating, and deleting Todo items.
Copy and paste the following code into the file:
import { useState, useEffect } from "react";import { View, Button, Text, StyleSheet, FlatList } from "react-native";
import { generateClient } from "aws-amplify/data";import type { Schema } from "../amplify/data/resource";import { GraphQLError } from "graphql";const client = generateClient<Schema>();
const TodoList = () => { const dateTimeNow = new Date(); const [todos, setTodos] = useState<Schema["Todo"]["type"][]>([]); const [errors, setErrors] = useState<GraphQLError>();
useEffect(() => { const sub = client.models.Todo.observeQuery().subscribe({ next: ({ items }) => { setTodos([...items]); }, });
return () => sub.unsubscribe(); }, []);
const createTodo = async () => { try { await client.models.Todo.create({ content: `${dateTimeNow.getUTCMilliseconds()}`, }); } catch (error: unknown) { if (error instanceof GraphQLError) { setErrors(error); } else { throw error; } } };
if (errors) { return <Text>{errors.message}</Text>; }
const renderItem = ({ item }: { item: Schema["Todo"]["type"] }) => ( <TodoItem {...item} /> ); return ( <View style={{ flex: 1 }}> <FlatList data={todos} renderItem={renderItem} keyExtractor={(item) => item.id} ItemSeparatorComponent={() => ( <View style={styles.listItemSeparator} /> )} ListEmptyComponent={() => <Text>The todo list is empty.</Text>} style={styles.listContainer} ></FlatList> <Button onPress={createTodo} title="Create Todo" /> </View> );};
const TodoItem = (todo: Schema["Todo"]["type"]) => ( <View style={styles.todoItemContainer} key={todo.id}> <Text style={{ ...styles.todoItemText, textDecorationLine: todo.isDone ? "line-through" : "none", textDecorationColor: todo.isDone ? "red" : "black", }} > {todo.content} </Text> <Button onPress={async () => { await client.models.Todo.delete(todo); }} title="Delete" /> <Button onPress={() => { client.models.Todo.update({ id: todo.id, isDone: !todo.isDone, }); }} title={todo.isDone ? "Undo" : "Done"} /> </View>);
const styles = StyleSheet.create({ todoItemContainer: { flexDirection: "row", alignItems: "center", padding: 8 }, todoItemText: { flex: 1, textAlign: "center" }, listContainer: { flex: 1, alignSelf: "stretch", padding:8 }, listItemSeparator: { backgroundColor: "lightgrey", height: 2 },});
export default TodoList;
With the code above, you can create a random todo item and display todo items in a list. You can mark them as done, update the list, or revert that operation. You can also delete the items. Each change in the list is listened to with the subscription and immediately shown on the screen.
If we take a closer look at the code:
generateClient
generates the necessary files and folders for models.TodoList
component includes the subscription, creation operations, and a list to hold created items.TodoItem
holds the information about each todo item.
Lastly, update the App
component in App.tsx
as follows:
const App = () => { return ( <Authenticator.Provider> <Authenticator> <SafeAreaView style={styles.container}> <SignOutButton /> <TodoList /> </SafeAreaView> </Authenticator> </Authenticator.Provider> );};
const styles = StyleSheet.create({ container: { flex: 1, padding: 8, }, signOutButton: { alignSelf: "flex-end", },});
If you run the application now, you should see the following behavior:
You can terminate the sandbox environment now to clean up the project.
Publishing changes to cloud
Publishing changes to the cloud requires a remote git repository. Amplify offers fullstack branch deployments that allow you to automatically deploy infrastructure and application code changes from feature branches. To learn more, visit the fullstack branch deployments guide.
🥳 Success
That's it! You have successfully built a fullstack app on AWS Amplify. If you want to learn more about how to work with Amplify, here's the conceptual guide for how Amplify works.