Add images to the chat

overview

Chats are great but what makes them awesome is the ability to share pictures and do it in reat time. Our users would like to be able to share pictures in their messages. Let’s tackle that next!

1. Add storage and update your resources

Your files will be stored in an S3 project. You can provision one by configuring storage with the Amplify CLI and configure an Lambda function that is trigged when content is added to your bucket.

> amplify add storage
? Please select from one of the below mentioned services: **Content (Images, audio, video, etc.)**
? Please provide a friendly name for your resource that will be used to label this category in the project: **chatImages**
? Please provide bucket name: **chat-images**
? Who should have access: **Auth users only**
? What kind of access do you want for Authenticated users? **create/update, read, delete**
? Do you want to add a Lambda Trigger for your S3 Bucket? **Yes**
? Select from the following options Create a new function
Successfully added resource **S3TriggerXXXXX** locally
? Do you want to edit the local **S3TriggerXXXXX** lambda function now? **No**
Successfully added resource chatImages locally

Next update the S3 trigger function to grant it access to your AppSync API.

> amplify update function
? Select which capability you want to update: **Lambda function (serverless function)**
? Select the Lambda function you want to update **S3TriggerXXXXX**
General information
| Name: S3TriggerXXXXX
| Runtime: **nodejs**

Resource access permission
- Not configured

Scheduled recurring invocation
| Not configured

Lambda layers
- Not configured

? Which setting do you want to update? **Resource access permissions**
? Select the categories you want this function to have access to. **api**
? Select the operations you want to permit on graphqlrealtimerace **Mutation**
? Do you want to edit the local **S3TriggerXXXXX** lambda function now? **No**

Your S3 trigger function will create a webp thumbnail for every original file that is uploaded. The function will use the sharp library. You’ll add this dependency via a Lambda layer.

> amplify add function
? Select which capability you want to add: **Lambda layer** (shared code & resource used across functions)
? Provide a name for your Lambda layer: **sharp**
? Select up to 2 compatible runtimes: **NodeJS**
? The current AWS account will always have access to this layer.
Optionally, configure who else can access this layer. (Hit <Enter> to skip) 
✅ Lambda layer folders & files created:
amplify/backend/function/sharp

Change your terminal directory to amplify/backend/function/sharp/lib/nodejs and updated the sharp libraries. Please refer to the instructions here for platform specific steps: Sharp - AWS Lambda

In Cloud9:

npm install sharp

For example, here are the steps on MacOS

SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install --arch=x64 --platform=linux sharp

and the steps for Windows

npm install --arch=x64 --platform=linux sharp

Now change current terminal folder back to ‘~/environment/graphql-real-time-race’ Next update your s3 lambda function to add the layer to its configuration:

> amplify update function
? Select which capability you want to update: **Lambda function** (serverless function)
? Select the Lambda function you want to update **S3TriggerXXXXX**

? Which setting do you want to update? Lambda layers configuration
? Do you want to configure Lambda layers for this function? **Yes**
? Provide existing layers or select layers in this project to access from this function (pick up to 5): **sharp**
? Select a version for sharp: **1**
? Do you want to edit the local lambda function now? **No**

Open amplify/backend/function/S3TriggerXXXXXXXX/src/index.js and enter this code:

[ 🌟 ] amplify/backend/function/S3TriggerXXXXXXXX/src/index.js

This Lambda function is triggered when a new object is added to the bucket. The function creates a new thumbnail that is added to the same bucket. The function only creates a thumbnail when an image is added to an original folder (prefix), and takes no action otherwise. Make sure you check own implementation to avoid triggering this function repeatedly for the same objects. For more details see Using AWS Lambda with Amazon S3 .

Update your schema model to include fields for your objects stored in S3. The schema will be under amplify/backend/api/graphqlrealtimerace/schema.graphql

type Message
  @model
  @key(
    fields: ["eventId", "createdAt"]
    name: "ByEventId"
    queryField: "messagesByEventId"
  )
  @auth(
    rules: [
      { allow: owner }
      { allow: private, operations: [read] }
      { allow: private, provider: iam, operations: [update] }
    ]
  ) {
  id: ID!
  owner: ID
  content: String!
  event: Event @connection(fields: ["eventId"])
  eventId: ID
  createdAt: AWSDateTime!
  updatedAt: AWSDateTime!
  original: S3Object
  thumbnail: S3Object
}

type S3Object {
  bucket: String!
  key: String!
  region: String!
}

Note that we introduce a new rule that allows access using AWS IAM credentials. We also introduce a new S3Object. At this point your project status should look like this.

> amplify status

Current Environment: staging

| Category | Resource name       | Operation | Provider plugin   |
| -------- | ------------------- | --------- | ----------------- |
| Storage  | chatImages          | Create    | awscloudformation |
| Function | S3Trigger88a68678   | Create    | awscloudformation |
| Function | sharp               | Create    | awscloudformation |
| Api      | graphqlrealtimerace | Update    | awscloudformation |
| Auth     | graphqlrealtimerace | No Change | awscloudformation |
| Hosting  | amplifyhosting      | No Change | awscloudformation |
| Storage  | raceresults         | No Change | awscloudformation |
| Function | updateLocation      | No Change | awscloudformation |

Optional

Processing your images in a Lambda function with sharp can be an expensive task that takes a long time. You can optionally update your S3 trigger Lambda function memory configuration and max run time.

Open the file S3TriggerXXXXXXXX-cloudformation-template.json in amplify/backend/function/S3TriggerXXXXXXXX. Change the Timeout value to "60" (the function will timeout at 60 seconds). Underneath, add a field MemorySize set to "1024". This changes the memory size configuration from its default of 128 MB to 1G. You should now have:

"Timeout": "60",
"MemorySize": "1024",

Make sure to deploy your changes if needed:

amplify push --yes

2. Update your codegen configuration

Your codegen configuration is currently set with a max depth of 2. Update your configuration so that the max depth is set to 3. This will included the nested s3 object fields in the operations selection set. Edit the file .graphqlconfig.yml and set maxDepth to 3. Then run the codegen.

amplify codegen

3. Update your code

Update your Chat component to use the new Storage category.

[ 🌟 ] src/pages/Chat.tsx

4. Try out images

chat with images