Connect API and database to the app
Now that you’ve created and configured your application and initialized a new Amplify project, you can add a feature. The first feature you will add is an API.
The Amplify CLI supports creating and interacting with two types of API categories: REST and GraphQL.
The API you will be creating in this step is a GraphQL API using AWS AppSync (a managed GraphQL service) and the database will be Amazon DynamoDB (a NoSQL database).
Create a GraphQL API and database
Add a GraphQL API to your app and automatically provision a database by running the following command from the root of your application directory:
amplify add api
Accept the default values which are highlighted below:
? Select from one of the below mentioned services: GraphQL? Here is the GraphQL API that we will create. Select a setting to edit or continue Continue? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)
The CLI will prompt you to open this GraphQL schema in your text editor.
amplify/backend/api/your-api-name/schema.graphql
# This "input" configures a global authorization rule to enable public access to# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/react/build-a-backend/graphqlapi/customize-authorization-rules/
input AMPLIFY { globalAuthRule: AuthRule = { allow: public }} # FOR TESTING ONLY!type Todo @model { id: ID! name: String! description: String}
The schema generated is for a Todo app. You'll notice a @model
directive on the Todo
type. This directive is part of the Amplify GraphQL API category.
Amplify GraphQL API provides custom GraphQL directives that allow you to define data models, set up authorization rules, configure serverless functions as resolvers, and more.
A GraphQL type decorated with the @model
directive will scaffold out the database table for the type (Todo table), the schema for CRUD (create, read, update, delete) and list operations, and the GraphQL resolvers needed to make everything work together.
From the command line, press enter to accept the schema and continue to the next steps.
Deploying the API
To deploy this backend, run the push
command:
amplify push
Choose the following values for each prompt:
✔ Are you sure you want to continue? (Y/n) · yes...? Do you want to generate code for your newly created GraphQL API: Yes? Choose the code generation language target: typescript? Enter the file name pattern of graphql queries, mutations and subscriptions: src/graphql/**/*.ts? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions: Yes? Enter maximum statement depth [increase from default if your schema is deeply nested]: 2? Enter the file name for the generated code: src/API.ts
✔ Are you sure you want to continue? (Y/n) · yes...? Do you want to generate code for your newly created GraphQL API Yes? Choose the code generation language target javascript? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes? Enter maximum statement depth [increase from default if your schema is deeply nested] 2? Enter the file name for the generated code src/API.js
Now the API is live and you can start interacting with it! The API you have deployed includes operations for creating, reading, updating, deleting, and listing posts.
Review deployment status
Next, run the following command to check Amplify's status:
amplify status
This will give us the current status of the Amplify project, including the current environment, any categories that have been created, and what state those categories are in. It should look similar to this:
Current Environment: dev
┌──────────┬───────────────────────┬───────────┬───────────────────┐│ Category │ Resource name │ Operation │ Provider plugin │├──────────┼───────────────────────┼───────────┼───────────────────┤│ Api │ your-api-name │ No Change │ awscloudformation │└──────────┴───────────────────────┴───────────┴───────────────────┘
Review deployed API in AWS console
To view the GraphQL API in the AppSync console at any time, run the following command:
amplify console api
To view your entire app in the Amplify console at any time, run the following command:
amplify console
Test API with local mocking
To test this out locally, you can run the mock
command. Note: Refer to the instructions to setup mocking.
If you'd like to go ahead and connect the front end, you can jump to the next step.
amplify mock api
Note: amplify mock api
requires Java.
# If you have not already deployed your API, you will be walked through the following steps for GraphQL code generation? Choose the code generation language target: javascript (or preferred target)? Enter the file name pattern of graphql queries, mutations and subscriptions: src/graphql/**/*.js? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions: Yes? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
This will open the GraphiQL explorer on a local port. From the test environment you can try out different operations locally, like queries and mutations.
In the GraphiQL toolbar, select Use: User Pool and try creating a todo:
mutation CreateTodo { createTodo(input: { name: "Test Todo", description: "Todo description" }) { id owner name updatedAt createdAt description }}
Next, update auth to Use: API Key and try querying the list of todos:
query ListTodos { listTodos { items { description createdAt id owner name } }}
Connect frontend to API
In this section you will create a way to list and create todos from the React application. To do this, you will create a form with a button to create todos as well as a way to fetch and render the list of todos.
Open App.js and replace it with the following code:
import React, { useEffect, useState } from 'react';import { StyleSheet, Text, View, TextInput, Pressable, SafeAreaView} from 'react-native';import { generateClient } from 'aws-amplify/api';import { createTodo } from './src/graphql/mutations';import { listTodos } from './src/graphql/queries';
import { Amplify } from 'aws-amplify';import amplifyconfig from './src/amplifyconfiguration.json';Amplify.configure(amplifyconfig);
const initialState = { name: '', description: '' };const client = generateClient();
const App = () => { const [formState, setFormState] = useState(initialState); const [todos, setTodos] = useState([]);
useEffect(() => { fetchTodos(); }, []);
function setInput(key, value) { setFormState({ ...formState, [key]: value }); }
async function fetchTodos() { try { const todoData = await client.graphql({ query: listTodos }); const todos = todoData.data.listTodos.items; setTodos(todos); } catch (err) { console.log('error fetching todos'); } }
async function addTodo() { try { if (!formState.name || !formState.description) return; const todo = { ...formState }; setTodos([...todos, todo]); setFormState(initialState); await client.graphql({ query: createTodo, variables: { input: todo } }); } catch (err) { console.log('error creating todo:', err); } }
return ( <SafeAreaView style={styles.container}> <View style={styles.container}> <TextInput onChangeText={(value) => setInput('name', value)} style={styles.input} value={formState.name} placeholder="Name" /> <TextInput onChangeText={(value) => setInput('description', value)} style={styles.input} value={formState.description} placeholder="Description" /> <Pressable onPress={addTodo} style={styles.buttonContainer}> <Text style={styles.buttonText}>Create todo</Text> </Pressable> {todos.map((todo, index) => ( <View key={todo.id ? todo.id : index} style={styles.todo}> <Text style={styles.todoName}>{todo.name}</Text> <Text style={styles.todoDescription}>{todo.description}</Text> </View> ))} </View> </SafeAreaView> );};
export default App;
const styles = StyleSheet.create({ container: { width: 400, flex: 1, padding: 20, alignSelf: 'center' }, todo: { marginBottom: 15 }, input: { backgroundColor: '#ddd', marginBottom: 10, padding: 8, fontSize: 18 }, todoName: { fontSize: 20, fontWeight: 'bold' }, buttonContainer: { alignSelf: 'center', backgroundColor: 'black', paddingHorizontal: 8 }, buttonText: { color: 'white', padding: 16, fontSize: 18 }});
Open App.tsx and replace it with the following code:
import React, { useEffect, useState } from 'react';import { StyleSheet, Text, View, TextInput, Pressable, SafeAreaView} from 'react-native';import { generateClient } from 'aws-amplify/api';import { createTodo } from './src/graphql/mutations';import { listTodos } from './src/graphql/queries';
const initialState = { name: '', description: '' };const client = generateClient();
const App = () => { const [formState, setFormState] = useState(initialState); const [todos, setTodos] = useState([]);
useEffect(() => { fetchTodos(); }, []);
function setInput(key, value) { setFormState({ ...formState, [key]: value }); }
async function fetchTodos() { try { const todoData = await client.graphql({ query: listTodos }); const todos = todoData.data.listTodos.items; setTodos(todos); } catch (err) { console.log('error fetching todos'); } }
async function addTodo() { try { if (!formState.name || !formState.description) return; const todo = { ...formState }; setTodos([...todos, todo]); setFormState(initialState); await client.graphql({ query: createTodo, variables: { input: todo } }); } catch (err) { console.log('error creating todo:', err); } }
return ( <SafeAreaView style={styles.container}> <View style={styles.container}> <TextInput onChangeText={(value) => setInput('name', value)} style={styles.input} value={formState.name} placeholder="Name" /> <TextInput onChangeText={(value) => setInput('description', value)} style={styles.input} value={formState.description} placeholder="Description" /> <Pressable onPress={addTodo} style={styles.buttonContainer}> <Text style={styles.buttonText}>Create todo</Text> </Pressable> {todos.map((todo, index) => ( <View key={todo.id ? todo.id : index} style={styles.todo}> <Text style={styles.todoName}>{todo.name}</Text> <Text style={styles.todoDescription}>{todo.description}</Text> </View> ))} </View> </SafeAreaView> );};
export default App;
const styles = StyleSheet.create({ container: { width: 400, flex: 1, padding: 20, alignSelf: 'center' }, todo: { marginBottom: 15 }, input: { backgroundColor: '#ddd', marginBottom: 10, padding: 8, fontSize: 18 }, todoName: { fontSize: 20, fontWeight: 'bold' }, buttonContainer: { alignSelf: 'center', backgroundColor: 'black', paddingHorizontal: 8 }, buttonText: { color: 'white', padding: 16, fontSize: 18 }});
Let's walk through some of the functions:
useEffect - After the component renders, the useEffect
hook is called and it invokes the fetchTodos
function.
fetchTodos - Uses the Amplify API client
created by generateClient()
to call the AppSync GraphQL API with the listTodos
query. Once the data is returned, the items array is passed in to the setTodos
function to update the local state.
addTodo - Uses the Amplify API client
created by generateClient()
to call the AppSync GraphQL API with the createTodo
mutation. A difference between the listTodos
query and the createTodo
mutation is that createTodo
accepts an argument containing the variables needed for the mutation.
Run locally
Next, run the app and you should see the updated UI with the ability to create and view the list of todos:
Start the app with the following command:
For Android:
npx expo run:android
For iOS:
npx expo run:ios
npm start
You have successfully deployed your API and connected it to your app!