Front-End Web & Mobile

Use an existing S3 bucket or DynamoDB table for your Amplify project

AWS Amplify is the fastest and easiest way to build cloud-powered mobile and web apps on AWS. Amplify comprises a set of tools and services that enables front-end web and mobile developers to leverage the power of AWS services to build innovative and feature-rich applications.

With today’s Amplify CLI release, we’re extending the newly announced import capability to S3 buckets and DynamoDB tables. This will enable your REST API, Functions, and, Predictions category to access these storage resources. The S3 bucket information will also be autofilled into your Amplify library configuration file (aws-exports.js & amplifyconfiguration.json).

For this guide, we’ll focus on re-using an existing S3 bucket. Review our documentation for more information on how to import DynamoDB tables.

Benefits:

  • independently manage S3 buckets while working with Amplify
  • re-use S3 buckets created and managed by existing Amplify projects
  • incrementally adopt Amplify for your application stack

What we’ll build:

  • “Dog or Not“ React application where you can upload a photo of a dog to an existing S3 bucket
  • Identify if the photo contains a dog by enabling the Amplify’s Predictions with the imported S3 bucket

Dog or not app preview

Prerequisites:

  • Install the latest Amplify CLI version
    • Open terminal and run npm install -g @aws-amplify/cli to update to the latest Amplify CLI.
  • Amplify CLI is already configured
  • Have an existing S3 bucket. For this demo, I’ll use an existing S3 bucket called: dogphoto-bucket

Setup React & Amplify project

Run the following command to create a new React project called “photo-share” or if you already have an existing Amplify project skip to the next section.

npx create-react-app dog-or-not
cd dog-or-not

Install the Amplify dependencies by running

npm install aws-amplify

Initialize an Amplify project by running:

amplify init

For the purposes of this blog post, you can just accept all the default values in the amplify init workflow.

Import an existing S3 bucket into your Amplify project

To import an existing S3 bucket into your Amplify project, run:

amplify import storage

Select S3 bucket - content (Images, audio, videos, etc.) and then you can use the auto-completion prompt to search for an S3 bucket within your Amplify project’s region.

In case you’re prompted for an auth resource, select “Add auth” to leverage Amplify’s Auth category configurations. For the purposes of this demo, you can just accept all default.

? Please select from one of the below mentioned services: S3 bucket - Content (Images, audio, video, etc.)
✔ Do you want to add or import auth now? · add
? Do you want to use the default authentication and security configuration? Default configuration
? How do you want users to be able to sign in? Username
? Do you want to configure advanced settings? No, I am done.
Successfully added auth resource dogornot9f488dba locally

✔ Select the S3 Bucket you want to import: · pupperdex-demofbf1d627d0374b7e95414a9d8f9e4216160913-staging

✅ S3 Bucket 'pupperdex-demofbf1d627d0374b7e95414a9d8f9e4216160913-staging' was successfully imported.

Next steps:
- This resource can now be accessed from REST APIs (‘amplify add api’) and Functions (‘amplify add function’)
- Use Amplify Libraries to add, upload, and download objects to your frontend app
  - iOS: https://docs.amplify.aws/lib/storage/getting-started/q/platform/ios
  - Android: https://docs.amplify.aws/lib/storage/getting-started/q/platform/android
  - JavaScript: https://docs.amplify.aws/lib/storage/getting-started/q/platform/js

Now run “amplify push” to fully complete the import procedure.

amplify push

After the amplify push, your src/aws-exports.js file be updated with your S3 bucket & Cognito information.

Update Identity Pool’s role policies to access S3 buckets

Amplify assumes certain access patterns for your S3 bucket. This makes it simple to interact with the S3 bucket. While this is not strictly required, it is highly recommended for the best developer experience with Amplify.

Let’s create a Managed Policy and attach that to our Unauthenticated Role to upload and delete public objects:

  • Run amplify console auth and select Identity Pool to identify your unauthenticated access role
  • Edit the identity pool and make sure that access to unauthenticated identities is enabled

Enable unauthenticated identities for identity pool

  • Open the IAM Console and find the unauthenticated role attached to your identity pool
  • Click on “Attach policies”
  • Create a new managed policy
  • Paste in the following statements
{
    "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
    ],
    "Resource": [
        "arn:aws:s3:::{YOUR_S3_BUCKET_NAME}/public/*"
    ],
    "Effect": "Allow"
}
  • Go back to your IAM Console and attach the policy

Create a managed policy to access S3 bucket

This demo only illustrates the required policies for an unauthenticated publicly accessible bucket. Amplify provides additional access levels:

  • protected – readable by all users but writable only by the creating user
  • private – only accessible for the individual user.

Review our access patterns guide to apply these additional constraints onto your bucket.

Update S3 bucket’s CORS settings

In order for your application you will need to make sure your CORS settings allow access from localhost. In our demo, we’ll enable any origin to create requests with this S3 bucket. Limit this to your application’s domain when releasing to production.

Go to your S3 bucket’s “Permissions” tab and “Edit” the CORS settings with the following snippet:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "HEAD",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "x-amz-server-side-encryption",
            "x-amz-request-id",
            "x-amz-id-2",
            "ETag"
        ],
        "MaxAgeSeconds": 3000
    }
]

Setting S3 bucket's CORS settings

Building UI to upload a photo to S3

Amplify libraries enables you to easily upload and retrieve files from S3 with just few lines of code.
First, initialize Amplify by adding the following lines of code to your index.js file

import Amplify from 'aws-amplify'
import awsconfig from './aws-exports'

Amplify.configure(awsconfig)

Replace your App.js file with the following content:

import { useState } from 'react'
import { Storage } from 'aws-amplify';

function App() {
  const [file, setFile] = useState();
  const [uploaded, setUploaded] = useState(false);

  return (
    <div className="App">
      <input type="file" onChange={(e) => setFile(e.target.files[0])} />
      <button onClick={async () => {
        const storageResult = await Storage.put('puppy.png', file, {
          level: 'public',
          type: 'image/png'
        })
        // Insert predictions code here later
        setUploaded(true)
        console.log(storageResult);
      }}>Upload and check if there's a dog!</button>

      <div>
        {uploaded
          ? <div>Your image is uploaded!</div>
          : <div>Upload a photo to get started</div>}
      </div>
    </div>
    );
}

export default App;

Test your application and check if you see a successful upload. Start your React app by running:

yarn start

You’ll notice a successful upload if the console logs a result of Storage.putand the label change to “Your image is uploaded!”

Uploading a dog photo to S3

Add Predictions to automatically identify and label uploaded images

Now that we can upload photos from a client to S3, let’s add the ability to figure out if these images contains dogs! To get started run:

amplify add predictions

While Amplify supports a wide variety of AI/ML use cases, today we’re going to just leverage the ability to identify labels within an image.

Select the following options:

? Please select from one of the categories below Identify
? What would you like to identify? Identify Labels
? Provide a friendly name for your resource: (accept default)
? Would you like use the default configuration? Default Configuration
? Who should have access? Auth and Guest users

This category usually would’ve required an Amplify-managed S3 bucket but with today’s release any S3 bucket requirement within any Amplify category can be fulfilled with an existing S3 bucket.

And let’s deploy your backend with the latest prediction category additions.

amplify push

We’ll need to modify the Amplify configuration in index.js slightly to take advantage of Amplify’s Predictions category. Make the following edits within index.js:

import Amplify from 'aws-amplify'
import { AmazonAIPredictionsProvider } from '@aws-amplify/predictions'
import awsconfig from './aws-exports'

Amplify.configure(awsconfig)
Amplify.addPluggable(new AmazonAIPredictionsProvider())

In your App.js, import the Predictions category from aws-amplify

import { Storage, Predictions } from 'aws-amplify'

You also need to create a new state to track if there is a dog in the image or not:

const [isDog, setIsDog] = useState(false)

Now let’s add this code snippet right after the await Storage.put(...) line to identify objects in the image:

const predictionsResult = await Predictions.identify({
  labels: {
    source: {
      key: storageResult.key
    }
  }
})

if (predictionsResult.labels.find(x => x.name === 'Dog')) {
  setIsDog(true)
} else {
  setIsDog(false)
}

This code snippet tells the Predictions category which S3 key to use as the source for their labeling algorithm. If any of the labels contain “Dog”, we’ll call it a success for now! This can also be refined further by evaluating the confidence value of the predicted label.

Now that we’ve got the network requests hooked up, let’s add JSX to display the result:

        {isDog
          ? <div> This image contains a dog ?</div>
          : <div> This image doesn't have a dog ? </div>}

Your final App.js code should look like this:

import { useState } from 'react'
import { Storage, Predictions } from 'aws-amplify';

function App() {
  const [file, setFile] = useState();
  const [uploaded, setUploaded] = useState(false);
  const [isDog, setIsDog] = useState(false)

  return (
    <div className="App">
      <input type="file" onChange={(e) => setFile(e.target.files[0])} />
      <button onClick={async () => {
        const storageResult = await Storage.put('puppy.png', file, {
          level: 'public',
          type: 'image/png'
        })

        const predictionsResult = await Predictions.identify({
          labels: {
            source: {
              key: storageResult.key
            }
          }
        })
        
        if (predictionsResult.labels.find(x => x.name === 'Dog')) {
          setIsDog(true)
        } else {
          setIsDog(false)
        }
        
        setUploaded(true)
        console.log(storageResult);
      }}>Upload and check if there's a dog!</button>

      <div>
        {uploaded
          ? <div>Your image is uploaded!</div>
          : <div>Upload a photo to get started</div>}
        {isDog
          ? <div> This image contains a dog ?</div>
          : <div> This image doesn't have a dog ? </div>}
      </div>
    </div>
    );
}

export default App;

? Success!

Dog or not app preview

Congratulations! You’ve got a fully functioning Amplify project up and running with your existing S3 bucket. With a few commands, you were able to import your existing S3 bucket and run AI/ML algorithms on-top of its contents.

Next steps: If you’re looking for more information like multi-environment support and how to unlink an imported resource, please review our documentation. If you have any feedback or enhancement requests, please create an issue in the Github repository.