Getting Started with AWS

Build a Full-Stack React Application

Create a simple web application using AWS Amplify

Module 5: Add Storage

In this module you will add storage and the ability to associate an image with the notes in your app.

Introduction

Now that we have the notes app working, let's add the ability to associate an image with each note. In this module, you will use the Amplify CLI and libraries to create a storage service leveraging Amazon S3. You will then update the GraphQL schema you created in the previous module to associate an image with each note. Finally, you will update the React app to enable image uploading, fetching, and rendering.

What You Will Learn

  • Create a storage service
  • Update a GraphQL schema
  • Update your React app

Key Concepts

Storage service - Storing and querying for files like images and videos is a common requirement for most applications. One option to do this is to Base64 encode the file and send as a string to save in the database. This comes with disadvantages like the encoded file being larger than the original binary, the operation being computationally expensive, and the added complexity around encoding and decoding properly. Another option is to have a storage service specifically built and optimized for file storage. Storage services like Amazon S3 exist to make this as easy, performant, and inexpensive as possible.

 Time to Complete

10 minutes

 Services Used

Implementation

  • Create the storage service

    To add image storage functionality, we'll use the Amplify storage category:

    amplify add storage
    
    ? Please select from one of the below mentioned services: Content
    ? Please provide a friendly name for your resource that will be used to label this category in the project: imagestorage
    ? Please provide bucket name: <your-unique-bucket-name>
    ? Who should have access: Auth users only
    ? What kind of access do you want for Authenticated users? create, read, update, delete
    ? Do you want to add a Lambda Trigger for your S3 Bucket? N
  • Update the GraphQL schema

    Next, open amplify/backend/api/notesapp/schema.graphql and update it with the following schema:

    type Note @model {
      id: ID!
      name: String!
      description: String
      image: String
    }
    

    Make sure to save the file.

  • Deploy storage service and API updates

    Now that the storage service has been configured locally and we've updated the GraphQL schema, we can deploy the updates by running the Amplify push command:

    amplify push --y
  • Update the React app

    Now that the backend has been updated, let's update the React app to add the functionality to upload and view images for a note. Open src/App.js and make the following changes.

    a. First add the Storage class to your Amplify imports:

    import { API, Storage } from 'aws-amplify';

    b. In the main App function, create a new onChange function to handle the image upload:

    async function onChange(e) {
      if (!e.target.files[0]) return
      const file = e.target.files[0];
      setFormData({ ...formData, image: file.name });
      await Storage.put(file.name, file);
      fetchNotes();
    }
    

    c. Update the fetchNotes function to fetch an image if there is an image associated with a note:

    async function fetchNotes() {
      const apiData = await API.graphql({ query: listNotes });
      const notesFromAPI = apiData.data.listNotes.items;
      await Promise.all(notesFromAPI.map(async note => {
        if (note.image) {
          const image = await Storage.get(note.image);
          note.image = image;
        }
        return note;
      }))
      setNotes(apiData.data.listNotes.items);
    }
    

    d. Update the createNote function to add the image to the local image array if an image is associated with the note:

    async function createNote() {
      if (!formData.name || !formData.description) return;
      await API.graphql({ query: createNoteMutation, variables: { input: formData } });
      if (formData.image) {
        const image = await Storage.get(formData.image);
        formData.image = image;
      }
      setNotes([ ...notes, formData ]);
      setFormData(initialFormState);
    }
    

    e. Add an additional input to the form in the return block:

    <input
      type="file"
      onChange={onChange}
    />
    

    f. When mapping over the notes array, render an image if it exists:

    {
      notes.map(note => (
        <div key={note.id || note.name}>
          <h2>{note.name}</h2>
          <p>{note.description}</p>
          <button onClick={() => deleteNote(note)}>Delete note</button>
          {
            note.image && <img src={note.image} style={{width: 400}} />
          }
        </div>
      ))
    }
    
  • Run the app

    To test out the app, run the start command:

    npm start

    You should now be able to optionally upload an image for each note.

Conclusion

You have deployed a web application using AWS Amplify! You have added authentication to your app allowing users to sign up, sign in, and manage their account. The app also has a scalable GraphQL API configured with an Amazon DynamoDB database allowing users to create and delete notes. You have also added file storage using Amazon S3 allowing users to upload images and view them in their app.

  • Deleting the resources

    Removing individual services

    To remove individual services, you can use the Amplify remove command:

    amplify remove auth
    
    ? Choose the resource you would want to remove: <your-service-name>

    Then run the Amplify push command:

    amplify push

    Deleting the entire project

    To delete the project and the associated resources, you can run the Amplify delete command:

    amplify delete

Was this module helpful?

Thank you
Please let us know what you liked.
Sorry to disappoint you
Is something out-of-date, confusing or inaccurate? Please help us improve this tutorial by providing feedback.

Congratulations!

You successfully built a web application on AWS! As a great next step, dive deeper into specific AWS technologies and take your application to the next level.