Skip to content

ServerlessReact.dev

Student Login
  • Welcome to the workshop
Before the workshop
The workshop
Before you head out

Save File to S3

As you saw in the last exercise, taking screenshots is a slow process. You wouldn't want to do that every time a user wants to see your picture.

And API Gateway isn't the happiest about serving images. You'll get high bandwidth bills.

A better solution is to store your screenshot to S3 - a service made specifically for static file storage.

Exercise

Copy your solution from exercise-4 to exercise-5, or start from mine in the repository.

Create a new YAML file to specify a new S3 bucket. This is where infrastructure as code shines.

# s3.yml
Resources:
ScreenshotsBucket:
Type: AWS::S3::Bucket

Then include this file as a resource in your serverless config. And install the serverless-resources-env plugin.

# serverless.yml
resources:
- ${file(s3.yml)}
plugins:
- serverless-resources-env

You can now access your new S3 bucket's name as process.env.CF_ScreenshotsBucket

You'll need to grant access to this bucket from your Lambda .

# serverless.yml
provider:
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:*"
Resource: "arn:aws:s3:::*/*"

This grants full permissions on all S3 buckets in your account. You can limit to a specific bucket and specific permissions with tricky incantations. The biggest pain point of AWS if you ask me.

To upload your screenshot to S3, use code like this:

// dont forget to import util and fs
const readFile = util.promisify(fs.readFile)
const buffer = await readFile(path)
// aws comes from importing aws-sdk
const s3 = new aws.S3({
apiVersion: "2006-03-01",
})
const { Location } = await s3
.upload({
Bucket: process.env.CF_ScreenshotsBucket,
Key: "<filename>.png",
Body: buffer,
ACL: "public-read", // grant public read access
})
.promise()

Return the Location from your function.

Try your function

Leave payload empty for GET requests, valid JSON for POST.

Solution

https://github.com/Swizec/serverless-workshop-exercises/tree/exercise-5-solution

Did you enjoy this chapter?

Previous:
Chrome puppeteer
Next:
Read/write a database
Created bySwizecwith ❤️