Page updated Jan 16, 2024

Set up Amplify GraphQL API

Prerequisite: Install, configure and init an Amplify project with Amplify CLI

In this section, you'll learn how to deploy an AWS AppSync GraphQL API and connect to it from a JavaScript client application.

Create the GraphQL API

To create a GraphQL API, use the Amplify add command:

amplify add api
1amplify add api
? Please 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) ? Do you want to edit the schema now? > Yes
1? Please select from one of the below mentioned services:
2 > GraphQL
3? Here is the GraphQL API that we will create. Select a setting to edit or continue:
4 > Continue
5? Choose a schema template:
6 > Single object with fields (e.g., “Todo” with ID, name, description)
7? Do you want to edit the schema now?
8 > Yes

The CLI should open this GraphQL schema in your text editor.

amplify/backend/api/myapi/schema.graphql

type Todo @model { id: ID! name: String! description: String }
1type Todo @model {
2 id: ID!
3 name: String!
4 description: String
5}

To deploy the API, you can use the Amplify push command:

amplify push
1amplify push
? Are you sure you want to continue? Y ? Do you want to generate code for your newly created GraphQL API? Y ? Choose the code generation language target: javascript (or your preferred language 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? Y ? Enter maximum statement depth [increase from default if your schema is deeply nested]: 2
1? Are you sure you want to continue? Y
2
3? Do you want to generate code for your newly created GraphQL API? Y
4? Choose the code generation language target: javascript (or your preferred language target)
5? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js
6? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions? Y
7? Enter maximum statement depth [increase from default if your schema is deeply nested]: 2

Now the API has been deployed and you can start using it.

Because the Todo type was decorated with an @model directive of the GraphQL Transform library, the CLI created the additional schema and resolvers for queries, mutations, and subscriptions as well as a DynamoDB table to hold the Todos.

To view the deployed services in your project at any time, go to Amplify Console by running the Amplify console command:

amplify console
1amplify console

Configure your application

Add Amplify to your app with yarn or npm:

npm install aws-amplify
1npm install aws-amplify

In your app's entry point i.e. App.ts or App.js, import and load the configuration file:

import { Amplify, API, graphqlOperation } from 'aws-amplify'; import awsconfig from './aws-exports'; Amplify.configure(awsconfig);
1import { Amplify, API, graphqlOperation } from 'aws-amplify';
2import awsconfig from './aws-exports';
3Amplify.configure(awsconfig);

Enable queries, mutations, and subscriptions

Now that the GraphQL API has deployed, it’s time to learn how to interact with it from a JavaScript client application. With GraphQL, you typically have the following types of operations:

  • Mutations - write data to the API (create, update, delete operations)
import { API, graphqlOperation } from 'aws-amplify'; import { createTodo, updateTodo, deleteTodo } from './graphql/mutations'; import { GraphQLQuery } from '@aws-amplify/api'; import { CreateTodoInput, CreateTodoMutation, UpdateTodoMutation, DeleteTodoMutation } from './API'; const todo: CreateTodoInput = { name: 'My first todo', description: 'Hello world!' }; /* create a todo */ await API.graphql<GraphQLQuery<CreateTodoMutation>>( graphqlOperation(createTodo, { input: todo }) ); /* update a todo */ await API.graphql<GraphQLQuery<UpdateTodoMutation>>( graphqlOperation(updateTodo, { input: { id: todoId, name: 'Updated todo info' } }) ); /* delete a todo */ await API.graphql<GraphQLQuery<DeleteTodoMutation>>( graphqlOperation(deleteTodo, { input: { id: todoId } }) );
1import { API, graphqlOperation } from 'aws-amplify';
2import { createTodo, updateTodo, deleteTodo } from './graphql/mutations';
3import { GraphQLQuery } from '@aws-amplify/api';
4import {
5 CreateTodoInput,
6 CreateTodoMutation,
7 UpdateTodoMutation,
8 DeleteTodoMutation
9} from './API';
10
11const todo: CreateTodoInput = {
12 name: 'My first todo',
13 description: 'Hello world!'
14};
15
16/* create a todo */
17await API.graphql<GraphQLQuery<CreateTodoMutation>>(
18 graphqlOperation(createTodo, { input: todo })
19);
20
21/* update a todo */
22await API.graphql<GraphQLQuery<UpdateTodoMutation>>(
23 graphqlOperation(updateTodo, {
24 input: { id: todoId, name: 'Updated todo info' }
25 })
26);
27
28/* delete a todo */
29await API.graphql<GraphQLQuery<DeleteTodoMutation>>(
30 graphqlOperation(deleteTodo, { input: { id: todoId } })
31);
import { API, graphqlOperation } from 'aws-amplify'; import { createTodo, updateTodo, deleteTodo } from './graphql/mutations'; const todo = { name: 'My first todo', description: 'Hello world!' }; /* create a todo */ await API.graphql(graphqlOperation(createTodo, { input: todo })); /* update a todo */ await API.graphql( graphqlOperation(updateTodo, { input: { id: todoId, name: 'Updated todo info' } }) ); /* delete a todo */ await API.graphql(graphqlOperation(deleteTodo, { input: { id: todoId } }));
1import { API, graphqlOperation } from 'aws-amplify';
2import { createTodo, updateTodo, deleteTodo } from './graphql/mutations';
3
4const todo = { name: 'My first todo', description: 'Hello world!' };
5
6/* create a todo */
7await API.graphql(graphqlOperation(createTodo, { input: todo }));
8
9/* update a todo */
10await API.graphql(
11 graphqlOperation(updateTodo, {
12 input: { id: todoId, name: 'Updated todo info' }
13 })
14);
15
16/* delete a todo */
17await API.graphql(graphqlOperation(deleteTodo, { input: { id: todoId } }));
  • Queries - read data from the API (list, get operations)
import { API, graphqlOperation } from 'aws-amplify'; import { GraphQLQuery } from '@aws-amplify/api'; import { listTodos } from './graphql/queries'; import { ListTodosQuery } from './API'; const todos = await API.graphql<GraphQLQuery<ListTodosQuery>>( graphqlOperation(listTodos) );
1import { API, graphqlOperation } from 'aws-amplify';
2import { GraphQLQuery } from '@aws-amplify/api';
3import { listTodos } from './graphql/queries';
4import { ListTodosQuery } from './API';
5
6const todos = await API.graphql<GraphQLQuery<ListTodosQuery>>(
7 graphqlOperation(listTodos)
8);
import { API, graphqlOperation } from 'aws-amplify'; import { listTodos } from './graphql/queries'; const todos = await API.graphql(graphqlOperation(listTodos));
1import { API, graphqlOperation } from 'aws-amplify';
2import { listTodos } from './graphql/queries';
3
4const todos = await API.graphql(graphqlOperation(listTodos));
  • Subscriptions - subscribe to changes in data for real-time functionality (onCreate, onUpdate, onDelete)
import { API, graphqlOperation } from 'aws-amplify'; import { GraphQLSubscription } from '@aws-amplify/api'; import { onCreateTodo } from './graphql/subscriptions'; import { OnCreateTodoSubscription } from './API'; // Subscribe to creation of Todo const sub = API.graphql<GraphQLSubscription<OnCreateTodoSubscription>>( graphqlOperation(onCreateTodo) ).subscribe({ next: (payload) => { const createdTodo = payload.value.data?.onCreateTodo; console.log(createdTodo); } }); // Stop receiving data updates from the subscription sub.unsubscribe();
1import { API, graphqlOperation } from 'aws-amplify';
2import { GraphQLSubscription } from '@aws-amplify/api';
3import { onCreateTodo } from './graphql/subscriptions';
4import { OnCreateTodoSubscription } from './API';
5
6// Subscribe to creation of Todo
7const sub = API.graphql<GraphQLSubscription<OnCreateTodoSubscription>>(
8 graphqlOperation(onCreateTodo)
9).subscribe({
10 next: (payload) => {
11 const createdTodo = payload.value.data?.onCreateTodo;
12 console.log(createdTodo);
13 }
14});
15
16// Stop receiving data updates from the subscription
17sub.unsubscribe();
import { API, graphqlOperation } from 'aws-amplify'; import { onCreateTodo } from './graphql/subscriptions'; // Subscribe to creation of Todo const sub = API.graphql(graphqlOperation(onCreateTodo)).subscribe({ next: (payload) => { const createdTodo = payload.value.data?.onCreateTodo; console.log(createdTodo); } }); // Stop receiving data updates from the subscription sub.unsubscribe();
1import { API, graphqlOperation } from 'aws-amplify';
2import { onCreateTodo } from './graphql/subscriptions';
3
4// Subscribe to creation of Todo
5const sub = API.graphql(graphqlOperation(onCreateTodo)).subscribe({
6 next: (payload) => {
7 const createdTodo = payload.value.data?.onCreateTodo;
8 console.log(createdTodo);
9 }
10});
11
12// Stop receiving data updates from the subscription
13sub.unsubscribe();

Updating Your GraphQL Schema

When you create a GraphQL backend with the CLI, the schema definition for your backend data structure is saved in one of two places:

  1. By default, schemas are saved in amplify/backend/api/YOUR-API-NAME/schema.graphql. If the schema.graphql file exists, it will take precedence over option 2.
  2. Optionally, schemas may be saved as a set of .graphql files stored in the amplify/backend/api/YOUR-API-NAME/schema/ directory. E.g. you might have files Query.graphql, User.graphql, and Post.graphql.

Once your API is deployed, updating the schema is easy with the CLI. You can edit the schema file(s) and run amplify push command to update your GraphQL backend.

For example, a sample GraphQL schema will look like this:

type Todo @model { id: ID! name: String! description: String }
1type Todo @model {
2 id: ID!
3 name: String!
4 description: String
5}

Add a priority field to your Todo type:

type Todo @model { id: ID! name: String! description: String priority: String }
1type Todo @model {
2 id: ID!
3 name: String!
4 description: String
5 priority: String
6}

Save your schema file and update your GraphQL backend:

amplify push
1amplify push

When you run the push command, you will notice that your schema change is automatically detected, and your backend will be updated respectively.

| Category | Resource name | Operation | Provider plugin | | -------- | --------------- | --------- | ----------------- | | Api | myapi | Update | awscloudformation |
1| Category | Resource name | Operation | Provider plugin |
2| -------- | --------------- | --------- | ----------------- |
3| Api | myapi | Update | awscloudformation |

When the update is complete, you can see the changes to your backend by running the following command and select GraphQL option.

amplify api console ? Please select from one of the below mentioned services: (Use arrow keys) ❯ GraphQL REST
1amplify api console
2? Please select from one of the below mentioned services: (Use arrow keys)
3❯ GraphQL
4 REST

Using GraphQL Transformers

As you can notice in the sample schema file above, the schema has a @model directive. The @model directive leverages a set of libraries that can help simplify the process of bootstrapping highly scalable, serverless GraphQL APIs on AWS. The @model directive tells the GraphQL Transform that you would like to store Todo objects in an Amazon DynamoDB table and configure CRUD operations for it. When you create or update your backend with push command, the CLI will automatically create and configure a new DynamoDB table that works with your AppSync API. The @model directive is just one of multiple transformers that can be used by annotating your schema.graphql.

The following directives are available to be used when defining your schema:

DirectiveDescription
@model on ObjectStore objects in DynamoDB and configure CRUD resolvers.
@auth on ObjectDefine authorization strategies for your API.
@hasOne, @hasMany, @belongsTo, @manyToMany on FieldSpecify relationships between @model object types.
@searchable on ObjectStream data of an @model object type to the Amazon OpenSearch Service.
@primaryKey and @index on ObjectIndex your data with keys.
@function on FieldConnect Lambda resolvers to your API.
@predictions on FieldConnect machine learning services.
@http on FieldConfigure HTTP resolvers within your API.

You may also write your own transformers to implement reproducible patterns that you find useful.

Mocking and Local Testing

Amplify supports running a local mock server for testing your application with AWS AppSync, including debugging of resolvers, before pushing to the cloud. Please see the CLI Toolchain documentation for more details.

Generate client types from a GraphQL schema

When working with GraphQL data it is useful to import types from your schema for type safety. You can do this with the Amplify CLI's automated code generation feature. The CLI automatically downloads GraphQL Introspection Schemas from the defined GraphQL endpoint and generates TypeScript or Flow classes for you. Every time you push your GraphQL API, the CLI will provide you the option to generate types and statements.

If you want to generate your GraphQL statements and types, run:

amplify codegen
1amplify codegen

A TypeScript or Flow type definition file will be generated in your target folder.

API configuration in the amplify folder

The Amplify CLI will create an amplify/backend/api folder that will hold the existing GraphQL schema, resolvers, and additional configuration around the API. To learn more about how the CLI manages this configuration, check out the documentation here. To learn how to configure custom GraphQL resolvers, check out the documentation here.