Metal Toad has been building applications and cloud environments for some of the most well-known global brands for over a decade. Learn more > >

rubix cube

Floggr Amplify App Pt II - Storage

This is a three part post about my experience using AWS Amplify to develop a food logging app for the Metal Toad hackathon. In part one I covered the initial project overview/setup and our experience implementing Amplify Auth. Here in part two I will cover Amplify Storage. Finally, part three will cover my favorite part, Amplify AppSync and PubSub.

In part one team Floggr developed a basic React app wrapped with Amplify's Auth library with some customizable overrides. The default Auth behavior is to hide the main content until signed in. The overrides allowed implementation of a custom banner and control over when the feed is hidden. The banner and food feed have placeholder images that are ready to accept an avatar image. Now on to storing and retrieving an avatar in an s3 bucket using Amplify Storage, and displaying it using Amplify React S3Image!

custom banner

Storage

AWS provides an easy to follow example code for setting, storing, and retrieving an image file using Amplify. Adding the Storage library to your Amplify project is very simple. From the CLI project root add amplify storage to your project:

$ amplify add storage

From the next two options choose content type for storing images.

? Please select from one of the below mentioned services (Use arrow keys)
❯ Content (Images, audio, video, etc.)
  NoSQL Database

One of the key steps in the setup process is permissions for the files. Most use cases will probably want to restrict guests to a maximum permission of read only. Authenticated users need create/update and delete permission to create and update their avatars.

? Who should have access: Auth and guest users
? What kind of access do you want for Authenticated users? create/update, read, delete
? What kind of access do you want for Guest users? read

After that just run the push command to deploy the code to AWS!

$ amplify push

Now that the backend is published, import the Storage library and set the permission level before you use it for the first time. Default configuration for Storage is public. Setting it private follows the principle of least privilege. The permission may be elevated locally as needed.

Storage.configure({ level: 'private' });

In your file upload handler, create the avatar on s3 by passing the file and file path to the Storage put method.

const handleAvatarUpload = evt => {
    const file = evt.target.files[0];
    const fileName = file.name;
  
    Storage.put(fileName, file).then(() => saveUserAvatar(user, fileName));
};

Lastly, add the avatar to the banner and food feed using the S3Image component. Pass the file name to the S3Image component via the image key property.

<S3Image level="private" imgKey={fileName} />

Wahoo! An avatar is born!

image of the banner that now includes a user avatar

The problem with this approach is that the avatars are not available to other users viewing the feed! Let's go ahead and fix that.

The private permission allows the file owner to create, read, update, and delete their file, no other user may read the file. Protected allows other users read access only. Pass an object with the level property set to protected as the third parameter of the Storage put method and Amplify will store it in s3 with protected access.

Storage.put(fileName, file, { level: 'protected' });

To display the avatar, the identity id for the owner of the image needs to be passed to the S3Image component. If the current user is the owner, then it is not necessary to provide the identity id as it will be provided automatically. Hence, the S3Image in our banner will not require the identity id prop, but it will be needed in the feed.

<S3Image level="protected" identityId={identityId} imgKey={fileName}/>

Where did I get that identity id from? The identity id corresponds to a unique Amazon Cognito Identity ID for that user. It can be retrieved after the user is authenticated and stored with the user data in the database.

const credentials = await Auth.currentCredentials();
const { identityId } = credentials;
saveUserCredentials(user, credentials);

The final product with our avatars!

food feed now with user avatars

Storage File Structure on s3

Storage has three different levels, public, protected, and private. Public allows any authorized user to create, read, write, and delete files. Protected only allows the file creator to write and delete, but other users may read the file. Private is like protected, but only allows the creator to read the file.

Each level gets its own folder in s3. The s3 bucket in the AWS console will show a folder for each level that contains files.

image showing s3 file structure

The private and public folder each have subfolders that map to the identity id of the user who owns the files. The public folder has no such subfolder as all of the files are available for all users. This is important to keep in mind as there few use cases for users creating and modifying public files. A user uploading a file called my_file.png could have it overwritten by the next user who uploads a different file with the same name.

With protected and private storage a developer could hard code the name of the avatar to something like my_avatar.png. This would ensure the user only ever has one uploaded and allows for simpler file management. Another user with the same filename will only have access to their own file. However, some social networks allow users to upload multiple avatars. This could be achieved by storing the filename, identity id, and current avatar filename in the user data in the database and then mapping it to the user in the feed.

In part three, the final part of this series, I will cover how to store user data in a GraphQL database, as well as publishing and subscribing to a food feed using a GraphQL database powered by AWS AppSync. Stay tuned for more!

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

About the Author

Joe Matthies, Javascript Engineer

Software engineer with a front end focus. Experienced in JavaScript, ReactJs, Redux, Android, and full stack development. I thrive in an innovative, tight knit, creative culture that values curiosity and growth. 

Ready to get started?