DEV Community

Joe Sak
Joe Sak

Posted on

Barebones AWS Amplify + React + GraphQL App

This is a simple guide on how to get a very basic React app going with GraphQL and AWS Amplify. Unfortunately, the AWS docs aren't the best and I find myself forgetting what to do and unable to follow their examples every time.

I think the biggest culprit is the part of the docs which cover adding Auth to your app. If you don't need Auth, you'll be tempted to skip that section, but unfortunately one of the most crucial steps is documented there and only there, instead of as a basic preliminary step for all apps that want to use Amplify.

Not only that, but all the tutorials and examples that I can find out there are super complex, including libraries and code design strategies that further confuse me and throw me off track. I am putting out the super barebones example that I wish I could find.

Finally, create-react-app sets you up with a functional component by default, whereas the docs use examples for a classical component, which is also confusing. So here goes:

Requirements:
(As of this post in mid November 2019)

  • node 13.1.0
  • amplify 3.16.0
  • create-react-app 3.2.0

This post assumes you already ran aws configure - this portion of the docs has never been an issue for me personally

Steps:

$ create-react-app my-project-name
$ cd my-project-name
$ yarn add aws-amplify aws-amplify-react

$ amplify init
  # follow the default instructions
  # wait for the cloud processes to finish

$ amplify add api 
  # follow prompts for GraphQL + 
  # API Key for authorization +
  # default prompts that will guide you 
  # in creating a schema +
  # Single-Object +
  # No to editing the schema

# You now have a basic API for a simple ToDo model

$ amplify push
  # say Yes to generate the code for your GraphQL API
  # (all the default answers will work fine for this post)
  # ... and wait a while (-:
Enter fullscreen mode Exit fullscreen mode

Now here is the crucial code that they sort of hide in the "Adding Auth" section of the docs, for those of us who do not need to add Auth:

Add this code to index.js

// other imports...
import Amplify from "aws-amplify"
import awsconfig from "./aws-exports"

Amplify.configure(awsconfig)

// ReactDOM.render...
Enter fullscreen mode Exit fullscreen mode

Next, start with a bare-bones App.js

import React from 'react';
import './App.css';

function App() {
  return (
    <div className="App">
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

And so that our CSS isn't wonky later, consider replacing the .App definition in App.css:

.App {
  padding: 1rem;

  /* instead of text-align: center; */
}
Enter fullscreen mode Exit fullscreen mode

Now let's add a basic input to create a ToDo and store it at the AWS AppSync GraphQL backend

First, we will need to add a controlled input, and in a functional component, we must import useState

// change FROM this:
import React from 'react';
// TO this:
import React, { useState } from 'react';
Enter fullscreen mode Exit fullscreen mode

In the top of the App function, add this:

function App() {
  const [todoName, setTodoName] = useState('')

  // ...the rest...
}
Enter fullscreen mode Exit fullscreen mode

And return the JSX for the input + button:

// ...

  return (
    <div className="App">
      <input type="text" value={todoName} onChange={handleChange} />
      <button onClick={addTodo}>Add ToDo</button>
    </div>
  );

//...
Enter fullscreen mode Exit fullscreen mode

And the function to handle the controlled input change:

// ...
  const handleChange = (evt) => {
    setTodoName(evt.target.value)
  }

// return ( ...
Enter fullscreen mode Exit fullscreen mode

Now to enable the addTodo function we will import the API and graphQL tools:

import { API, graphqlOperation } from "aws-amplify"
import { createTodo } from "./graphql/mutations
Enter fullscreen mode Exit fullscreen mode

And finally the addTodo function

// ...
  const addTodo = async () => {
    await API.graphql(
      graphqlOperation(createTodo, { input: { name: todoName } })
    )
    setTodoName('') // make the input blank again
  }
  // Another fun fact of the AWS docs is
  // they don't give the updated 
  // example that the 2nd argument 
  // is an object with the "input" property (-:

// ...
Enter fullscreen mode Exit fullscreen mode

With your local server started via yarn start you ought to now be able to successfully create a ToDo in your AWS GraphQL backend!

Let's list our ToDos just to be sure.

Note: the following is probably a very naïve implementation and others will suggest a "better" way but I just want to be sure that my application is working during this prototyping phase.

We'll import our GraphQL query:

import { listTodos } from "./graphql/queries"
Enter fullscreen mode Exit fullscreen mode

And add another useState to get an array of our ToDo items:

const [todoItems, setTodoItems] = useState([])

Enter fullscreen mode Exit fullscreen mode

Create a function to populate our ToDos from AWS:

  const updateTodos = async () => {
    const allTodos = await API.graphql(graphqlOperation(listTodos))
    setTodoItems(allTodos.data.listTodos.items)
  }
Enter fullscreen mode Exit fullscreen mode

Add some quick JSX to list our ToDos:

// ...

return (
  // ...

  <ul>
    {todoItems.map((item) => {
      return <li key={item.id}>{ item.name }</li>
    })}
  </ul>
)
Enter fullscreen mode Exit fullscreen mode

Modify our addTodo function:

(yes there is a better way with graphQL subscriptions, but this is okay for today!)

const addTodo = async () => {
  await API.graphql(
    graphqlOperation(createTodo, { input: { name: todoName } })
  )
  setTodoName('')

  updateTodos() // here it is
}
Enter fullscreen mode Exit fullscreen mode

And the very, very naïve call to updateTodos before returning our JSX:

  // ...

  updateTodos()

  return ( //...
    //...
  )
}
Enter fullscreen mode Exit fullscreen mode

Welp, that should be it!

Here is the full index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import Amplify from "aws-amplify"
import awsconfig from "./aws-exports"
Amplify.configure(awsconfig)

ReactDOM.render(<App />, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
Enter fullscreen mode Exit fullscreen mode

And full App.js

import React, { useState } from 'react';
import './App.css';

import { API, graphqlOperation } from "aws-amplify"
import { createTodo } from "./graphql/mutations"
import { listTodos } from "./graphql/queries"

function App() {
  const [todoName, setTodoName] = useState('')
  const [todoItems, setTodoItems] = useState([])

  const addTodo = async () => {
    await API.graphql(
      graphqlOperation(createTodo, { input: { name: todoName } })
    )
    setTodoName('')
    updateTodos()
  }

  const handleChange = (evt) => {
    setTodoName(evt.target.value)
  }

  const updateTodos = async () => {
    const allTodos = await API.graphql(graphqlOperation(listTodos))
    setTodoItems(allTodos.data.listTodos.items)
  }

  updateTodos()

  return (
    <div className="App">
      <input type="text" value={todoName} onChange={handleChange} />

      <button onClick={addTodo}>Add ToDo</button>

      <ul>
        {todoItems.map((item) => {
          return <li key={item.id}>{ item.name }</li>
        })}
      </ul>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Top comments (0)