Now that you’ve created and configured a React app 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](https://docs.aws.amazon.com/appsync/latest/devguide/designing-a-graphql-api.html) to your app and automatically provision a database by running the following command from the root of your application directory: ```bash amplify add api ``` Accept the **default values** which are highlighted below: ```console ? 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 should open this GraphQL schema in your text editor. __amplify/backend/api/myapi/schema.graphql__ ```graphql type Todo @model { id: ID! name: String! description: String } ``` The schema generated is for a Todo app. You'll notice a directive on the `Todo` type of `@model`. This directive is part of the [GraphQL transform](/cli/graphql/data-modeling) library of Amplify. The GraphQL Transform Library provides custom directives you can use in your schema that allow you to do things like define data models, set up authentication and authorization rules, configure serverless functions as resolvers, and more. A 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: ```bash amplify push ``` ```console ? Are you sure you want to continue? 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 ``` Now the API is live and you can start interacting with it! The API you have deployed is for a Todo app, including operations for creating, reading, updating, deleting, and listing todos. Next, run the following command to check Amplify's status: ```bash 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: ```console Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | ------------- | --------- | ----------------- | | Api | myapi | No Change | awscloudformation | ``` To view the GraphQL API in the AppSync console at any time, run the following command: ```bash amplify console api ``` To view your entire app in the Amplify console at any time, run the following command: ```bash amplify console ``` ### (Optional) Test your API To test this out locally, you can run the `mock` command. > If you'd like to go ahead and connect the frontend, you can [jump to the next step](#connect-frontend-to-api). ```bash amplify mock api ``` *Note:* `amplify mock api` requires Java. If you have not already deployed your API with `amplify push`, you will be walked through the following steps for GraphQL code generation. ```console ? 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 ``` This will open the GraphiQL explorer on a local port. Navigate to the address shown in the terminal to use the test environment. From here, you can try out different operations locally, like queries and mutations. Try running a couple of mutations locally and then querying for the todos: ```graphql mutation createTodo { createTodo(input: { name: "Build an API" description: "Build a serverless API with Amplify and GraphQL" }) { id name description } } query listTodos { listTodos { items { id description 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: ```javascript import React, {useEffect, useState} from 'react'; import { StyleSheet, Text, View, TextInput, Pressable, SafeAreaView, } from 'react-native'; import {API, graphqlOperation} from 'aws-amplify'; import {createTodo} from './src/graphql/mutations'; import {listTodos} from './src/graphql/queries'; import { Amplify } from 'aws-amplify'; import awsExports from './src/aws-exports'; Amplify.configure(awsExports); const initialState = {name: '', description: ''}; 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 API.graphql(graphqlOperation(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 API.graphql(graphqlOperation(createTodo, {input: todo})); } catch (err) { console.log('error creating todo:', err); } } return ( setInput('name', value)} style={styles.input} value={formState.name} placeholder="Name" /> setInput('description', value)} style={styles.input} value={formState.description} placeholder="Description" /> Create todo {todos.map((todo, index) => ( {todo.name} {todo.description} ))} ); }; 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: ```javascript import React, {useEffect, useState} from 'react'; import { StyleSheet, Text, View, TextInput, Pressable, SafeAreaView, } from 'react-native'; import {API, graphqlOperation} from 'aws-amplify'; import {createTodo} from './src/graphql/mutations'; import {listTodos} from './src/graphql/queries'; const initialState = {name: '', description: ''}; 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 API.graphql(graphqlOperation(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 API.graphql(graphqlOperation(createTodo, {input: todo})); } catch (err) { console.log('error creating todo:', err); } } return ( setInput('name', value)} style={styles.input} value={formState.name} placeholder="Name" /> setInput('description', value)} style={styles.input} value={formState.description} placeholder="Description" /> Create todo {todos.map((todo, index) => ( {todo.name} {todo.description} ))} ); }; 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` category 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` category 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 If your app is already running you should see the form rendered to the screen and be able to create and view the list of todos. If your app is not already running, start it by running the following command: ```bash npm start ```