Typesafe, Fullstack React & GraphQL with AWS Amplify
Tags: react, graphql, aws
Published: 2020-09-15 21:23:42

---
title: Typesafe, Fullstack React & GraphQL with AWS Amplify
published: true
description: This is the blog version of a talk I am giving at React Summit 2020
tags: React, GraphQL, AWS
slug: aws_typesafe_fullstack_react
canonical_url: https://www.swyx.io/writing/aws_typesafe_fullstack_react
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/1hfx0h8s4cb9lmot9c4m.png
---

*This is the blog form of a talk I gave at React Summit and Reactathon 2020*

{% youtube ja6meOLHjIg %}

## Resources

I am going to skim over [the slides, which are available here.](https://docs.google.com/presentation/d/1wU2VCAgdNk67EtxokcKUPMWyHJ5e0wVqcrOjqGLUyqg/edit?usp=sharing)

GitHub Repo for this demo: https://github.com/sw-yx/talk-typesafe-fullstack-react-demo-cms

I will also assume you already have the [AWS Amplify CLI setup and configured](https://docs.amplify.aws/cli).

## Livecode Demo Script

First we clone our premade React + TypeScript app and initialize it as an AWS Amplify project:

```bash
git clone https://github.com/sw-yx/talk-typesafe-fullstack-react-demo-cms
cd talk-typesafe-fullstack-react-demo-cms
yarn
amplify init # select defaults for everything
```

At this point we have our simple app with some mock data:

![https://user-images.githubusercontent.com/6764957/93261590-7c13f980-f7d5-11ea-9fda-b482ac1abdac.png](https://user-images.githubusercontent.com/6764957/93261590-7c13f980-f7d5-11ea-9fda-b482ac1abdac.png)

This gives us a strongly typed frontend with React and TypeScript! If you wish to learn how to wield React and TypeScript well, check out the [React and TypeScript cheatsheet](https://react-typescript-cheatsheet.netlify.app/) I have been maintaining for [over two years](https://twitter.com/swyx/status/1002776892154445826)!

### Adding a GraphQL Database

We will now add a strongly typed backend to complement the frontend, using Amplify and AWS AppSync:

```bash
amplify add api

# choose the graphql option and defaults for the rest

? Please select from one of the below mentioned services: GraphQL
? Provide API name: myapiname
? Choose the default authorization type for the API API key
? Enter a description for the API key: 
? After how many days from now the API key should expire (1-365): 7
? Do you want to configure advanced settings for the GraphQL API No, I am do
ne.
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID,
 name, description)

The following types do not have '@auth' enabled. Consider using @auth with @model
         - Todo
Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/directives#auth


GraphQL schema compiled successfully.

? Do you want to edit the schema now? Yes
```

We'll use GraphQL SDL to define our database schema:

```graphql
# amplify/backend/api/myapiname/schema.graphql
type Blog @model {
  id: ID!
  title: String!
  image: String!
  body: String!
}
```

That `@model` there is a special GraphQL directive, which AppSync uses to provision infrastructure for you alongside your GraphQL model via a library called [GraphQL Transform](https://docs.amplify.aws/cli/graphql-transformer/directives). It has loads more goodies you can explore on your own, like `@auth`, `@searchable`, `@function` and `@predictions`, that you can add to your backend.

Provisioning this infrastructure in AWS takes a long time, so we'll kick it off in the background while we work on the rest of the app:

```bash
amplify push -y # skips the yes check
```

### Wiring up Backend to Frontend

We're in the home stretch. We'll need the `aws-amplify` library for interacting from the frontend:

```bash
yarn add -D aws-amplify
```

Notice that during `amplify init` an `aws-exports.js` file was generated in your `src` folder, with some non-secret information for your backend. We'll use this to wire up our app with AWS Amplify:

```tsx
// // src/index.tsx

// the other imports
import Amplify from 'aws-amplify';
import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

// rest of the app
```

You also notice that during `amplify push` there was an autogenerated folder in `src/graphql` with a bunch of GraphQL queries. We will use this in our app!

Optional step first - we can configure the codegen to generate typescript, so that types and auto imports work:

```bash
amplify codegen configure

? Choose the code generation language target typescript
? Enter the file name pattern of graphql queries, mutations and subscriptions src/
graphql/**/*.ts
? Enter the file name for the generated code src/API.ts
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
```

Then we will use the `listBlogs` query in our app!

```tsx
// src/App.tsx
import { API } from 'aws-amplify'; // new
import { listBlogs } from "./graphql/queries"; // new
// other imports here

function App() {
  
  // new
  React.useEffect(fetchBlogs);
  function fetchBlogs() {
    const query = API.graphql({ query: listBlogs }) as Promise<any>
    query.then(
      ({
        data: {
          listBlogs: { items },
        },
      }) => setBlogs(items)
    );
  }
  // etc
}
```

This sets up the blog items to refresh from backend whenever the app rerenders.

Then we'll also do the same for adding and updating blogs:

```tsx
// make sure to import createBlog and updateBlog

  async function addBlog(values: Blog) {
    const timestamp = new Date();
    const newBlog: Blog = {
      ...values,
      id: uuidv4(),
      createdAt: timestamp,
      updatedAt: timestamp,
    };
    setBlogs([...blogs, newBlog]);
    await API.graphql({query: createBlog, variables: {input: values}}) // NEW!
  }
  function _updateBlog(oldValues: Blog) {
    return async function (newValues: Blog) {
      const timestamp = new Date();
      const newBlog: Blog = {
        ...newValues,
        createdAt: oldValues.createdAt,
        updatedAt: timestamp,
      };
      setBlogs([...blogs.filter((x) => x.id !== oldValues.id), newBlog]);

      const { createdAt, updatedAt, ...input } = newBlog; // NEW!
      await API.graphql({ query: updateBlog, variables: { input } }); // NEW!
    };
  }
```

And there you have it! The basics of an end to end typed app!

You got stuck you can see the completed version of the app here https://github.com/sw-yx/talk-react-summit-demo-cms/blob/withAWS/src/App.tsx and the slides are [here](https://docs.google.com/presentation/d/1wU2VCAgdNk67EtxokcKUPMWyHJ5e0wVqcrOjqGLUyqg/edit?usp=sharing).

[![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1hfx0h8s4cb9lmot9c4m.png)](https://docs.google.com/presentation/d/1wU2VCAgdNk67EtxokcKUPMWyHJ5e0wVqcrOjqGLUyqg/edit?usp=sharing)

I'm sure you have questions - let's hear them!