• United States+1
  • United Kingdom+44
  • Afghanistan (‫افغانستان‬‎)+93
  • Albania (Shqipëri)+355
  • Algeria (‫الجزائر‬‎)+213
  • American Samoa+1684
  • Andorra+376
  • Angola+244
  • Anguilla+1264
  • Antigua and Barbuda+1268
  • Argentina+54
  • Armenia (Հայաստան)+374
  • Aruba+297
  • Australia+61
  • Austria (Österreich)+43
  • Azerbaijan (Azərbaycan)+994
  • Bahamas+1242
  • Bahrain (‫البحرين‬‎)+973
  • Bangladesh (বাংলাদেশ)+880
  • Barbados+1246
  • Belarus (Беларусь)+375
  • Belgium (België)+32
  • Belize+501
  • Benin (Bénin)+229
  • Bermuda+1441
  • Bhutan (འབྲུག)+975
  • Bolivia+591
  • Bosnia and Herzegovina (Босна и Херцеговина)+387
  • Botswana+267
  • Brazil (Brasil)+55
  • British Indian Ocean Territory+246
  • British Virgin Islands+1284
  • Brunei+673
  • Bulgaria (България)+359
  • Burkina Faso+226
  • Burundi (Uburundi)+257
  • Cambodia (កម្ពុជា)+855
  • Cameroon (Cameroun)+237
  • Canada+1
  • Cape Verde (Kabu Verdi)+238
  • Caribbean Netherlands+599
  • Cayman Islands+1345
  • Central African Republic (République centrafricaine)+236
  • Chad (Tchad)+235
  • Chile+56
  • China (中国)+86
  • Christmas Island+61
  • Cocos (Keeling) Islands+61
  • Colombia+57
  • Comoros (‫جزر القمر‬‎)+269
  • Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)+243
  • Congo (Republic) (Congo-Brazzaville)+242
  • Cook Islands+682
  • Costa Rica+506
  • Côte d’Ivoire+225
  • Croatia (Hrvatska)+385
  • Cuba+53
  • Curaçao+599
  • Cyprus (Κύπρος)+357
  • Czech Republic (Česká republika)+420
  • Denmark (Danmark)+45
  • Djibouti+253
  • Dominica+1767
  • Dominican Republic (República Dominicana)+1
  • Ecuador+593
  • Egypt (‫مصر‬‎)+20
  • El Salvador+503
  • Equatorial Guinea (Guinea Ecuatorial)+240
  • Eritrea+291
  • Estonia (Eesti)+372
  • Ethiopia+251
  • Falkland Islands (Islas Malvinas)+500
  • Faroe Islands (Føroyar)+298
  • Fiji+679
  • Finland (Suomi)+358
  • France+33
  • French Guiana (Guyane française)+594
  • French Polynesia (Polynésie française)+689
  • Gabon+241
  • Gambia+220
  • Georgia (საქართველო)+995
  • Germany (Deutschland)+49
  • Ghana (Gaana)+233
  • Gibraltar+350
  • Greece (Ελλάδα)+30
  • Greenland (Kalaallit Nunaat)+299
  • Grenada+1473
  • Guadeloupe+590
  • Guam+1671
  • Guatemala+502
  • Guernsey+44
  • Guinea (Guinée)+224
  • Guinea-Bissau (Guiné Bissau)+245
  • Guyana+592
  • Haiti+509
  • Honduras+504
  • Hong Kong (香港)+852
  • Hungary (Magyarország)+36
  • Iceland (Ísland)+354
  • India (भारत)+91
  • Indonesia+62
  • Iran (‫ایران‬‎)+98
  • Iraq (‫العراق‬‎)+964
  • Ireland+353
  • Isle of Man+44
  • Israel (‫ישראל‬‎)+972
  • Italy (Italia)+39
  • Jamaica+1876
  • Japan (日本)+81
  • Jersey+44
  • Jordan (‫الأردن‬‎)+962
  • Kazakhstan (Казахстан)+7
  • Kenya+254
  • Kiribati+686
  • Kosovo+383
  • Kuwait (‫الكويت‬‎)+965
  • Kyrgyzstan (Кыргызстан)+996
  • Laos (ລາວ)+856
  • Latvia (Latvija)+371
  • Lebanon (‫لبنان‬‎)+961
  • Lesotho+266
  • Liberia+231
  • Libya (‫ليبيا‬‎)+218
  • Liechtenstein+423
  • Lithuania (Lietuva)+370
  • Luxembourg+352
  • Macau (澳門)+853
  • Macedonia (FYROM) (Македонија)+389
  • Madagascar (Madagasikara)+261
  • Malawi+265
  • Malaysia+60
  • Maldives+960
  • Mali+223
  • Malta+356
  • Marshall Islands+692
  • Martinique+596
  • Mauritania (‫موريتانيا‬‎)+222
  • Mauritius (Moris)+230
  • Mayotte+262
  • Mexico (México)+52
  • Micronesia+691
  • Moldova (Republica Moldova)+373
  • Monaco+377
  • Mongolia (Монгол)+976
  • Montenegro (Crna Gora)+382
  • Montserrat+1664
  • Morocco (‫المغرب‬‎)+212
  • Mozambique (Moçambique)+258
  • Myanmar (Burma) (မြန်မာ)+95
  • Namibia (Namibië)+264
  • Nauru+674
  • Nepal (नेपाल)+977
  • Netherlands (Nederland)+31
  • New Caledonia (Nouvelle-Calédonie)+687
  • New Zealand+64
  • Nicaragua+505
  • Niger (Nijar)+227
  • Nigeria+234
  • Niue+683
  • Norfolk Island+672
  • North Korea (조선 민주주의 인민 공화국)+850
  • Northern Mariana Islands+1670
  • Norway (Norge)+47
  • Oman (‫عُمان‬‎)+968
  • Pakistan (‫پاکستان‬‎)+92
  • Palau+680
  • Palestine (‫فلسطين‬‎)+970
  • Panama (Panamá)+507
  • Papua New Guinea+675
  • Paraguay+595
  • Peru (Perú)+51
  • Philippines+63
  • Poland (Polska)+48
  • Portugal+351
  • Puerto Rico+1
  • Qatar (‫قطر‬‎)+974
  • Réunion (La Réunion)+262
  • Romania (România)+40
  • Russia (Россия)+7
  • Rwanda+250
  • Saint Barthélemy (Saint-Barthélemy)+590
  • Saint Helena+290
  • Saint Kitts and Nevis+1869
  • Saint Lucia+1758
  • Saint Martin (Saint-Martin (partie française))+590
  • Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)+508
  • Saint Vincent and the Grenadines+1784
  • Samoa+685
  • San Marino+378
  • São Tomé and Príncipe (São Tomé e Príncipe)+239
  • Saudi Arabia (‫المملكة العربية السعودية‬‎)+966
  • Senegal (Sénégal)+221
  • Serbia (Србија)+381
  • Seychelles+248
  • Sierra Leone+232
  • Singapore+65
  • Sint Maarten+1721
  • Slovakia (Slovensko)+421
  • Slovenia (Slovenija)+386
  • Solomon Islands+677
  • Somalia (Soomaaliya)+252
  • South Africa+27
  • South Korea (대한민국)+82
  • South Sudan (‫جنوب السودان‬‎)+211
  • Spain (España)+34
  • Sri Lanka (ශ්‍රී ලංකාව)+94
  • Sudan (‫السودان‬‎)+249
  • Suriname+597
  • Svalbard and Jan Mayen+47
  • Swaziland+268
  • Sweden (Sverige)+46
  • Switzerland (Schweiz)+41
  • Syria (‫سوريا‬‎)+963
  • Taiwan (台灣)+886
  • Tajikistan+992
  • Tanzania+255
  • Thailand (ไทย)+66
  • Timor-Leste+670
  • Togo+228
  • Tokelau+690
  • Tonga+676
  • Trinidad and Tobago+1868
  • Tunisia (‫تونس‬‎)+216
  • Turkey (Türkiye)+90
  • Turkmenistan+993
  • Turks and Caicos Islands+1649
  • Tuvalu+688
  • U.S. Virgin Islands+1340
  • Uganda+256
  • Ukraine (Україна)+380
  • United Arab Emirates (‫الإمارات العربية المتحدة‬‎)+971
  • United Kingdom+44
  • United States+1
  • Uruguay+598
  • Uzbekistan (Oʻzbekiston)+998
  • Vanuatu+678
  • Vatican City (Città del Vaticano)+39
  • Venezuela+58
  • Vietnam (Việt Nam)+84
  • Wallis and Futuna+681
  • Western Sahara (‫الصحراء الغربية‬‎)+212
  • Yemen (‫اليمن‬‎)+967
  • Zambia+260
  • Zimbabwe+263
  • Åland Islands+358
Thanks! We'll be in touch in the next 12 hours
Oops! Something went wrong while submitting the form.

Build and Deploy a Real-Time React App Using AWS Amplify and GraphQL

Omkar Joshi

Full-stack Development

GraphQL is becoming a popular way to use APIs in modern web and mobile apps.

However, learning new things is always time-consuming and without getting your hands dirty, it’s very difficult to understand the nuances of a new technology.

So, we have put together a powerful and concise tutorial that will guide you through setting up a GraphQL backend and integration into your React app in the shortest time possible. This tutorial is light on opinions, so that once you get a hang of the fundamentals, you can go on and tailor your workflow.

Key topics and takeaways:

  • Authentication
  • GraphQL API with AWS AppSync
  • Hosting
  • Working with multiple environments
  • Removing services

What will we be building?

We will build a basic real-time Restaurant CRUD app using authenticated GraphQL APIs. Click here to try the deployed version of the app to see what we’ll be building.

Will this tutorial teach React or GraphQL concepts as well?

No. The focus is to learn how to use AWS Amplify to build cloud-enabled, real-time web applications. If you are new to React or GraphQL, we recommend going through the official documentation and then coming back here.

What do I need to take this tutorial?

  • Node >= v10.9.0
  • NPM >= v6.9.0 packaged with Node.

Getting started - Creating the application

To get started, we first need to create a React project using the create-react-app boilerplate:

npx create-react-app amplify-app --typescript
cd amplify-app
view raw create_react.sh hosted with ❤ by GitHub

Let’s now install the AWS Amplify and AWS Amplify React bindings and try running the application:

npm install --save aws-amplify aws-amplify-react
npm start
view raw install_aws.sh hosted with ❤ by GitHub

If you have initialized the app with Typescript and see errors while using

aws-amplify-react, add aws-amplify-react.d.ts to src with:

declare module 'aws-amplify-react';

Installing the AWS Amplify CLI and adding it to the project

To install the CLI:

npm install -g @aws-amplify/cli
view raw cli.sh hosted with ❤ by GitHub

Now we need to configure the CLI with our credentials:

amplify configure
view raw amplify_cli.sh hosted with ❤ by GitHub

If you’d like to see a video walkthrough of this process, click here

Here we'll walk you through the amplify configure setup. After you sign in to the AWS console, follow these steps:

  • Specify the AWS region: ap-south-1 (Mumbai) <Select the region based on your location. Click here for reference>
  • Specify the username of the new IAM user: amplify-app <name of="" your="" app=""></name>

In the AWS Console, click Next: Permissions, Next: Tags, Next: Review, and Create User to create the new IAM user. Then, return to the command line and press Enter.

  • Enter the credentials of the newly created user:
    accessKeyId: <your_access_key_id> </your_access_key_id>
    secretAccessKey: <your_secret_access_key></your_secret_access_key>
  • Profile Name: default

To view the newly created IAM user, go to the dashboard. Also, make sure that your region matches your selection.

To add amplify to your project:

amplify init
view raw add_amplify.sh hosted with ❤ by GitHub

Answer the following questions:

  • Enter a name for the project: amplify-app <name of="" your="" app=""></name>
  • Enter a name for the environment: dev <name of="" your="" environment=""></name>
  • Choose your default editor: Visual Studio Code <your default editor=""></your>
  • Choose the type of app that you’re building: javaScript
  • What JavaScript framework are you using: React
  • Source Directory Path: src
  • Distribution Directory Path: build
  • Build Command: npm run build (for macOS/Linux), npm.cmd run-script build (for Windows)
  • Start Command: npm start (for macOS/Linux), npm.cmd run-script start (for Windows)
  • Do you want to use an AWS profile: Yes
  • Please choose the profile you want to use: default

Now, the AWS Amplify CLI has initialized a new project and you will see a new folder: amplify. This folder has files that hold your project configuration.

<amplify-app>
|_ amplify
|_ .config
|_ #current-cloud-backend
|_ backend
team-provider-info.json
view raw aws_amplify.sh hosted with ❤ by GitHub

Adding Authentication

To add authentication:

amplify add auth
view raw add_auth.sh hosted with ❤ by GitHub

When prompted, choose:

  • Do you want to use default authentication and security configuration: Default configuration
  • How do you want users to be able to sign in when using your Cognito User Pool: Username
  • What attributes are required for signing up: Email

Now, let’s run the push command to create the cloud resources in our AWS account:

amplify push

To quickly check your newly created Cognito User Pool, you can run

amplify status
view raw user_pool.sh hosted with ❤ by GitHub

To access the AWS Cognito Console at any time, go to the dashboard. Also, ensure that your region is set correctly.

Now, our resources are created and we can start using them.

The first thing is to connect our React application to our new AWS Amplify project. To do this, reference the auto-generated aws-exports.js file that is now in our src folder.

To configure the app, open App.tsx and add the following code below the last import:

import Amplify from 'aws-amplify';
import awsConfig from './aws-exports';
Amplify.configure(awsConfig);
view raw App.tsx hosted with ❤ by GitHub

Now, we can start using our AWS services.
To add the Authentication flow to the UI, export the app component by wrapping it with the authenticator HOC:

import { withAuthenticator } from 'aws-amplify-react';
...
// app component
...
export default withAuthenticator(App);
view raw App.tsx hosted with ❤ by GitHub

Now, let’s run the app to check if an Authentication flow has been added before our App component is rendered.

Authentication flow

This flow gives users the ability to sign up and sign in. To view any users that were created, go back to the Cognito dashboard. Alternatively, you can also use:

amplify console auth
view raw console-auth.sh hosted with ❤ by GitHub

Cognito dashboard

The withAuthenticator HOC is a really easy way to get up and running with authentication, but in a real-world application, we probably want more control over how our form looks and functions. We can use the aws-amplify/Auth class to do this. This class has more than 30 methods including signUp, signIn, confirmSignUp, confirmSignIn, and forgotPassword. These functions return a promise, so they need to be handled asynchronously.

Adding and Integrating the GraphQL API

To add GraphQL API, use the following command:

amplify add api
view raw add_api.sh hosted with ❤ by GitHub

Answer the following questions:

  • Please select from one of the below mentioned services: GraphQL
  • Provide API name: RestaurantAPI
  • Choose an authorization type for the API: API key
  • Do you have an annotated GraphQL schema: No
  • Do you want a guided schema creation: Yes
  • What best describes your project: Single object with fields (e.g., “Todo” with ID, name, description)
  • Do you want to edit the schema now: Yes

When prompted, update the schema to the following:

type Restaurant @model {
id: ID!
name: String!
description: String!
city: String!
}
view raw schema.graphql hosted with ❤ by GitHub

Next, let’s run the push command to create the cloud resources in our AWS account:

amplify push
view raw push-command.sh hosted with ❤ by GitHub

  • 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: 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

Notice your GraphQL endpoint and API KEY. This step has created a new AWS AppSync API and generated the GraphQL queries, mutations, and subscriptions on your local. To check, see src/graphql or visit the AppSync dashboard. Alternatively, you can use:

amplify console api
view raw console_api.sh hosted with ❤ by GitHub

Please select from one of the below mentioned services: GraphQL

Now, in the AppSync console, on the left side click on Queries. Execute the following mutation to create a restaurant in the API:

mutation createRestaurant {
createRestaurant(input: {
name: "Nobu"
description: "Great Sushi"
city: "New York"
}) {
id name description city
}
}

Now, let’s query for the restaurant:

query listRestaurants {
listRestaurants {
items {
id
name
description
city
}
}
}
view raw queries.graphql hosted with ❤ by GitHub

We can even search / filter data when querying:

query searchRestaurants {
listRestaurants(filter: {
city: {
contains: "New York"
}
}) {
items {
id
name
description
city
}
}
}
view raw queries.graphql hosted with ❤ by GitHub

Queries

Now that the GraphQL API is created, we can begin interacting with it from our client application. Here is how we’ll add queries, mutations, and subscriptions:

import Amplify, { API, graphqlOperation } from 'aws-amplify';
import { withAuthenticator } from 'aws-amplify-react';
import React, { useEffect, useReducer } from 'react';
import { Button, Col, Container, Form, Row, Table } from 'react-bootstrap';
import './App.css';
import awsConfig from './aws-exports';
import { createRestaurant } from './graphql/mutations';
import { listRestaurants } from './graphql/queries';
import { onCreateRestaurant } from './graphql/subscriptions';
Amplify.configure(awsConfig);
type Restaurant = {
name: string;
description: string;
city: string;
};
type AppState = {
restaurants: Restaurant[];
formData: Restaurant;
};
type Action =
| {
type: 'QUERY';
payload: Restaurant[];
}
| {
type: 'SUBSCRIPTION';
payload: Restaurant;
}
| {
type: 'SET_FORM_DATA';
payload: { [field: string]: string };
};
type SubscriptionEvent<D> = {
value: {
data: D;
};
};
const initialState: AppState = {
restaurants: [],
formData: {
name: '',
city: '',
description: '',
},
};
const reducer = (state: AppState, action: Action) => {
switch (action.type) {
case 'QUERY':
return { ...state, restaurants: action.payload };
case 'SUBSCRIPTION':
return { ...state, restaurants: [...state.restaurants, action.payload] };
case 'SET_FORM_DATA':
return { ...state, formData: { ...state.formData, ...action.payload } };
default:
return state;
}
};
const App: React.FC = () => {
const createNewRestaurant = async (e: React.SyntheticEvent) => {
e.stopPropagation();
const { name, description, city } = state.formData;
const restaurant = {
name,
description,
city,
};
await API.graphql(graphqlOperation(createRestaurant, { input: restaurant }));
};
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
getRestaurantList();
const subscription = API.graphql(graphqlOperation(onCreateRestaurant)).subscribe({
next: (eventData: SubscriptionEvent<{ onCreateRestaurant: Restaurant }>) => {
const payload = eventData.value.data.onCreateRestaurant;
dispatch({ type: 'SUBSCRIPTION', payload });
},
});
return () => subscription.unsubscribe();
}, []);
const getRestaurantList = async () => {
const restaurants = await API.graphql(graphqlOperation(listRestaurants));
dispatch({
type: 'QUERY',
payload: restaurants.data.listRestaurants.items,
});
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
dispatch({
type: 'SET_FORM_DATA',
payload: { [e.target.name]: e.target.value },
});
return (
<div className="App">
<Container>
<Row className="mt-3">
<Col md={4}>
<Form>
<Form.Group controlId="formDataName">
<Form.Control onChange={handleChange} type="text" name="name" placeholder="Name" />
</Form.Group>
<Form.Group controlId="formDataDescription">
<Form.Control onChange={handleChange} type="text" name="description" placeholder="Description" />
</Form.Group>
<Form.Group controlId="formDataCity">
<Form.Control onChange={handleChange} type="text" name="city" placeholder="City" />
</Form.Group>
<Button onClick={createNewRestaurant} className="float-left">
Add New Restaurant
</Button>
</Form>
</Col>
</Row>
{state.restaurants.length ? (
<Row className="my-3">
<Col>
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>City</th>
</tr>
</thead>
<tbody>
{state.restaurants.map((restaurant, index) => (
<tr key={`restaurant-${index}`}>
<td>{index + 1}</td>
<td>{restaurant.name}</td>
<td>{restaurant.description}</td>
<td>{restaurant.city}</td>
</tr>
))}
</tbody>
</Table>
</Col>
</Row>
) : null}
</Container>
</div>
);
};
export default withAuthenticator(App);
view raw App.tsx hosted with ❤ by GitHub

Finally, we have our app ready. You can now sign-up,sign-in, add new restaurants, see real-time updates of newly added restaurants.

Real-time Update

Hosting

The hosting category enables you to deploy and host your app on AWS.

amplify add hosting
view raw hosting.sh hosted with ❤ by GitHub

  • Select the environment setup: DEV (S3 only with HTTP)
  • hosting bucket name: <YOUR_BUCKET_NAME>
  • index doc for the website: index.html
  • error doc for the website: index.html

Now, everything is set up & we can publish it:

amplify publish
view raw publish.sh hosted with ❤ by GitHub

Working with multiple environments

You can create multiple environments for your application to create & test out new features without affecting the main environment which you are working on.

When you use an existing environment to create a new environment, you get a copy of the entire backend application stack (CloudFormation) for the current environment. When you make changes in the new environment, you are then able to test these new changes in the new environment & merge only the changes that have been made since the new environment was created.

Let's take a look at how to create a new environment. In this new environment, we'll add another field for the restaurant owner to the GraphQL Schema.

First, we'll initialize a new environment using amplify init:

amplify init
view raw init.sh hosted with ❤ by GitHub

  • Do you want to use an existing environment: N
  • Enter a name for the environment: apiupdate
  • Do you want to use an AWS profile: Y

Once the new environment is initialized, we should be able to see some information about our environment setup by running:

amplify env list
| Environments |
| ------------ |
| dev |
| *apiupdate |
view raw environment.sh hosted with ❤ by GitHub

Now, add the owner field to the GraphQL Schema in

amplify/backend/api/RestaurantAPI/schema.graphql:
view raw owner.sh hosted with ❤ by GitHub

type Restaurant @model {
...
owner: String
}
view raw schema.graphql hosted with ❤ by GitHub

Run the push command to create a new stack:

amplify push.
view raw push_command.sh hosted with ❤ by GitHub

After testing it out, it can be merged into our original dev environment:

amplify env checkout dev
amplify status
amplify push
view raw testing.sh hosted with ❤ by GitHub

  • Do you want to update code for your updated GraphQL API: Y
  • Do you want to generate GraphQL statements: Y

Removing Services

If at any time, you would like to delete a service from your project & your account, you can do this by running the amplify remove command:

amplify remove auth
amplify push

If you are unsure of what services you have enabled at any time, amplify status will give you the list of resources that are currently enabled in your app.

Sample code

The sample code for this blog post with an end to end working app is available here.

Summary

Once you've worked through all the sections above, your app should now have all the capabilities of a modern app, and building GraphQL + React apps should now be easier and faster with Amplify.

Get the latest engineering blogs delivered straight to your inbox.
No spam. Only expert insights.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Did you like the blog? If yes, we're sure you'll also like to work with the people who write them - our best-in-class engineering team.

We're looking for talented developers who are passionate about new emerging technologies. If that's you, get in touch with us.

Explore current openings

Build and Deploy a Real-Time React App Using AWS Amplify and GraphQL

GraphQL is becoming a popular way to use APIs in modern web and mobile apps.

However, learning new things is always time-consuming and without getting your hands dirty, it’s very difficult to understand the nuances of a new technology.

So, we have put together a powerful and concise tutorial that will guide you through setting up a GraphQL backend and integration into your React app in the shortest time possible. This tutorial is light on opinions, so that once you get a hang of the fundamentals, you can go on and tailor your workflow.

Key topics and takeaways:

  • Authentication
  • GraphQL API with AWS AppSync
  • Hosting
  • Working with multiple environments
  • Removing services

What will we be building?

We will build a basic real-time Restaurant CRUD app using authenticated GraphQL APIs. Click here to try the deployed version of the app to see what we’ll be building.

Will this tutorial teach React or GraphQL concepts as well?

No. The focus is to learn how to use AWS Amplify to build cloud-enabled, real-time web applications. If you are new to React or GraphQL, we recommend going through the official documentation and then coming back here.

What do I need to take this tutorial?

  • Node >= v10.9.0
  • NPM >= v6.9.0 packaged with Node.

Getting started - Creating the application

To get started, we first need to create a React project using the create-react-app boilerplate:

npx create-react-app amplify-app --typescript
cd amplify-app
view raw create_react.sh hosted with ❤ by GitHub

Let’s now install the AWS Amplify and AWS Amplify React bindings and try running the application:

npm install --save aws-amplify aws-amplify-react
npm start
view raw install_aws.sh hosted with ❤ by GitHub

If you have initialized the app with Typescript and see errors while using

aws-amplify-react, add aws-amplify-react.d.ts to src with:

declare module 'aws-amplify-react';

Installing the AWS Amplify CLI and adding it to the project

To install the CLI:

npm install -g @aws-amplify/cli
view raw cli.sh hosted with ❤ by GitHub

Now we need to configure the CLI with our credentials:

amplify configure
view raw amplify_cli.sh hosted with ❤ by GitHub

If you’d like to see a video walkthrough of this process, click here

Here we'll walk you through the amplify configure setup. After you sign in to the AWS console, follow these steps:

  • Specify the AWS region: ap-south-1 (Mumbai) <Select the region based on your location. Click here for reference>
  • Specify the username of the new IAM user: amplify-app <name of="" your="" app=""></name>

In the AWS Console, click Next: Permissions, Next: Tags, Next: Review, and Create User to create the new IAM user. Then, return to the command line and press Enter.

  • Enter the credentials of the newly created user:
    accessKeyId: <your_access_key_id> </your_access_key_id>
    secretAccessKey: <your_secret_access_key></your_secret_access_key>
  • Profile Name: default

To view the newly created IAM user, go to the dashboard. Also, make sure that your region matches your selection.

To add amplify to your project:

amplify init
view raw add_amplify.sh hosted with ❤ by GitHub

Answer the following questions:

  • Enter a name for the project: amplify-app <name of="" your="" app=""></name>
  • Enter a name for the environment: dev <name of="" your="" environment=""></name>
  • Choose your default editor: Visual Studio Code <your default editor=""></your>
  • Choose the type of app that you’re building: javaScript
  • What JavaScript framework are you using: React
  • Source Directory Path: src
  • Distribution Directory Path: build
  • Build Command: npm run build (for macOS/Linux), npm.cmd run-script build (for Windows)
  • Start Command: npm start (for macOS/Linux), npm.cmd run-script start (for Windows)
  • Do you want to use an AWS profile: Yes
  • Please choose the profile you want to use: default

Now, the AWS Amplify CLI has initialized a new project and you will see a new folder: amplify. This folder has files that hold your project configuration.

<amplify-app>
|_ amplify
|_ .config
|_ #current-cloud-backend
|_ backend
team-provider-info.json
view raw aws_amplify.sh hosted with ❤ by GitHub

Adding Authentication

To add authentication:

amplify add auth
view raw add_auth.sh hosted with ❤ by GitHub

When prompted, choose:

  • Do you want to use default authentication and security configuration: Default configuration
  • How do you want users to be able to sign in when using your Cognito User Pool: Username
  • What attributes are required for signing up: Email

Now, let’s run the push command to create the cloud resources in our AWS account:

amplify push

To quickly check your newly created Cognito User Pool, you can run

amplify status
view raw user_pool.sh hosted with ❤ by GitHub

To access the AWS Cognito Console at any time, go to the dashboard. Also, ensure that your region is set correctly.

Now, our resources are created and we can start using them.

The first thing is to connect our React application to our new AWS Amplify project. To do this, reference the auto-generated aws-exports.js file that is now in our src folder.

To configure the app, open App.tsx and add the following code below the last import:

import Amplify from 'aws-amplify';
import awsConfig from './aws-exports';
Amplify.configure(awsConfig);
view raw App.tsx hosted with ❤ by GitHub

Now, we can start using our AWS services.
To add the Authentication flow to the UI, export the app component by wrapping it with the authenticator HOC:

import { withAuthenticator } from 'aws-amplify-react';
...
// app component
...
export default withAuthenticator(App);
view raw App.tsx hosted with ❤ by GitHub

Now, let’s run the app to check if an Authentication flow has been added before our App component is rendered.

Authentication flow

This flow gives users the ability to sign up and sign in. To view any users that were created, go back to the Cognito dashboard. Alternatively, you can also use:

amplify console auth
view raw console-auth.sh hosted with ❤ by GitHub

Cognito dashboard

The withAuthenticator HOC is a really easy way to get up and running with authentication, but in a real-world application, we probably want more control over how our form looks and functions. We can use the aws-amplify/Auth class to do this. This class has more than 30 methods including signUp, signIn, confirmSignUp, confirmSignIn, and forgotPassword. These functions return a promise, so they need to be handled asynchronously.

Adding and Integrating the GraphQL API

To add GraphQL API, use the following command:

amplify add api
view raw add_api.sh hosted with ❤ by GitHub

Answer the following questions:

  • Please select from one of the below mentioned services: GraphQL
  • Provide API name: RestaurantAPI
  • Choose an authorization type for the API: API key
  • Do you have an annotated GraphQL schema: No
  • Do you want a guided schema creation: Yes
  • What best describes your project: Single object with fields (e.g., “Todo” with ID, name, description)
  • Do you want to edit the schema now: Yes

When prompted, update the schema to the following:

type Restaurant @model {
id: ID!
name: String!
description: String!
city: String!
}
view raw schema.graphql hosted with ❤ by GitHub

Next, let’s run the push command to create the cloud resources in our AWS account:

amplify push
view raw push-command.sh hosted with ❤ by GitHub

  • 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: 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

Notice your GraphQL endpoint and API KEY. This step has created a new AWS AppSync API and generated the GraphQL queries, mutations, and subscriptions on your local. To check, see src/graphql or visit the AppSync dashboard. Alternatively, you can use:

amplify console api
view raw console_api.sh hosted with ❤ by GitHub

Please select from one of the below mentioned services: GraphQL

Now, in the AppSync console, on the left side click on Queries. Execute the following mutation to create a restaurant in the API:

mutation createRestaurant {
createRestaurant(input: {
name: "Nobu"
description: "Great Sushi"
city: "New York"
}) {
id name description city
}
}

Now, let’s query for the restaurant:

query listRestaurants {
listRestaurants {
items {
id
name
description
city
}
}
}
view raw queries.graphql hosted with ❤ by GitHub

We can even search / filter data when querying:

query searchRestaurants {
listRestaurants(filter: {
city: {
contains: "New York"
}
}) {
items {
id
name
description
city
}
}
}
view raw queries.graphql hosted with ❤ by GitHub

Queries

Now that the GraphQL API is created, we can begin interacting with it from our client application. Here is how we’ll add queries, mutations, and subscriptions:

import Amplify, { API, graphqlOperation } from 'aws-amplify';
import { withAuthenticator } from 'aws-amplify-react';
import React, { useEffect, useReducer } from 'react';
import { Button, Col, Container, Form, Row, Table } from 'react-bootstrap';
import './App.css';
import awsConfig from './aws-exports';
import { createRestaurant } from './graphql/mutations';
import { listRestaurants } from './graphql/queries';
import { onCreateRestaurant } from './graphql/subscriptions';
Amplify.configure(awsConfig);
type Restaurant = {
name: string;
description: string;
city: string;
};
type AppState = {
restaurants: Restaurant[];
formData: Restaurant;
};
type Action =
| {
type: 'QUERY';
payload: Restaurant[];
}
| {
type: 'SUBSCRIPTION';
payload: Restaurant;
}
| {
type: 'SET_FORM_DATA';
payload: { [field: string]: string };
};
type SubscriptionEvent<D> = {
value: {
data: D;
};
};
const initialState: AppState = {
restaurants: [],
formData: {
name: '',
city: '',
description: '',
},
};
const reducer = (state: AppState, action: Action) => {
switch (action.type) {
case 'QUERY':
return { ...state, restaurants: action.payload };
case 'SUBSCRIPTION':
return { ...state, restaurants: [...state.restaurants, action.payload] };
case 'SET_FORM_DATA':
return { ...state, formData: { ...state.formData, ...action.payload } };
default:
return state;
}
};
const App: React.FC = () => {
const createNewRestaurant = async (e: React.SyntheticEvent) => {
e.stopPropagation();
const { name, description, city } = state.formData;
const restaurant = {
name,
description,
city,
};
await API.graphql(graphqlOperation(createRestaurant, { input: restaurant }));
};
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
getRestaurantList();
const subscription = API.graphql(graphqlOperation(onCreateRestaurant)).subscribe({
next: (eventData: SubscriptionEvent<{ onCreateRestaurant: Restaurant }>) => {
const payload = eventData.value.data.onCreateRestaurant;
dispatch({ type: 'SUBSCRIPTION', payload });
},
});
return () => subscription.unsubscribe();
}, []);
const getRestaurantList = async () => {
const restaurants = await API.graphql(graphqlOperation(listRestaurants));
dispatch({
type: 'QUERY',
payload: restaurants.data.listRestaurants.items,
});
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
dispatch({
type: 'SET_FORM_DATA',
payload: { [e.target.name]: e.target.value },
});
return (
<div className="App">
<Container>
<Row className="mt-3">
<Col md={4}>
<Form>
<Form.Group controlId="formDataName">
<Form.Control onChange={handleChange} type="text" name="name" placeholder="Name" />
</Form.Group>
<Form.Group controlId="formDataDescription">
<Form.Control onChange={handleChange} type="text" name="description" placeholder="Description" />
</Form.Group>
<Form.Group controlId="formDataCity">
<Form.Control onChange={handleChange} type="text" name="city" placeholder="City" />
</Form.Group>
<Button onClick={createNewRestaurant} className="float-left">
Add New Restaurant
</Button>
</Form>
</Col>
</Row>
{state.restaurants.length ? (
<Row className="my-3">
<Col>
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>City</th>
</tr>
</thead>
<tbody>
{state.restaurants.map((restaurant, index) => (
<tr key={`restaurant-${index}`}>
<td>{index + 1}</td>
<td>{restaurant.name}</td>
<td>{restaurant.description}</td>
<td>{restaurant.city}</td>
</tr>
))}
</tbody>
</Table>
</Col>
</Row>
) : null}
</Container>
</div>
);
};
export default withAuthenticator(App);
view raw App.tsx hosted with ❤ by GitHub

Finally, we have our app ready. You can now sign-up,sign-in, add new restaurants, see real-time updates of newly added restaurants.

Real-time Update

Hosting

The hosting category enables you to deploy and host your app on AWS.

amplify add hosting
view raw hosting.sh hosted with ❤ by GitHub

  • Select the environment setup: DEV (S3 only with HTTP)
  • hosting bucket name: <YOUR_BUCKET_NAME>
  • index doc for the website: index.html
  • error doc for the website: index.html

Now, everything is set up & we can publish it:

amplify publish
view raw publish.sh hosted with ❤ by GitHub

Working with multiple environments

You can create multiple environments for your application to create & test out new features without affecting the main environment which you are working on.

When you use an existing environment to create a new environment, you get a copy of the entire backend application stack (CloudFormation) for the current environment. When you make changes in the new environment, you are then able to test these new changes in the new environment & merge only the changes that have been made since the new environment was created.

Let's take a look at how to create a new environment. In this new environment, we'll add another field for the restaurant owner to the GraphQL Schema.

First, we'll initialize a new environment using amplify init:

amplify init
view raw init.sh hosted with ❤ by GitHub

  • Do you want to use an existing environment: N
  • Enter a name for the environment: apiupdate
  • Do you want to use an AWS profile: Y

Once the new environment is initialized, we should be able to see some information about our environment setup by running:

amplify env list
| Environments |
| ------------ |
| dev |
| *apiupdate |
view raw environment.sh hosted with ❤ by GitHub

Now, add the owner field to the GraphQL Schema in

amplify/backend/api/RestaurantAPI/schema.graphql:
view raw owner.sh hosted with ❤ by GitHub

type Restaurant @model {
...
owner: String
}
view raw schema.graphql hosted with ❤ by GitHub

Run the push command to create a new stack:

amplify push.
view raw push_command.sh hosted with ❤ by GitHub

After testing it out, it can be merged into our original dev environment:

amplify env checkout dev
amplify status
amplify push
view raw testing.sh hosted with ❤ by GitHub

  • Do you want to update code for your updated GraphQL API: Y
  • Do you want to generate GraphQL statements: Y

Removing Services

If at any time, you would like to delete a service from your project & your account, you can do this by running the amplify remove command:

amplify remove auth
amplify push

If you are unsure of what services you have enabled at any time, amplify status will give you the list of resources that are currently enabled in your app.

Sample code

The sample code for this blog post with an end to end working app is available here.

Summary

Once you've worked through all the sections above, your app should now have all the capabilities of a modern app, and building GraphQL + React apps should now be easier and faster with Amplify.

Did you like the blog? If yes, we're sure you'll also like to work with the people who write them - our best-in-class engineering team.

We're looking for talented developers who are passionate about new emerging technologies. If that's you, get in touch with us.

Explore current openings