Build an API EndPoint For Serverless S3 Uploads With Lambda In AWS

Build an API EndPoint For Serverless S3 Uploads With Lambda In AWS

Utilizing Lambda for uploads offloads all the bandwidth and compute resources from your application and it relies on S3. This can free up your servers to handle other requests. It works with Web Apps and even ones that do not utilize the serverless architecture like WordPress or any LAMP STACK Application. For example, if you’re building an application that allows end-users to upload media files. S3 provides Presigned URLs to give temporary access to unauthorized users to GET or POST files to and from S3.

Side note... Think of a service like dropbox offers how it works and how you’re able to share files with your friends and colleagues.😃😎

Why use Presigned URLs?

Suppose you have an application that is deployed on AWS Lambda and is made accessible by AWS API Gateway. One of the APIs in the application allows users to upload multiple images for a resource. One limitation🤦‍♂️ you might encounter is API Gateway’s payload size limitation which is 10MB and cannot be increased. Presigned URLs can provide an alternative by allowing AWS Lambda to expose an S3 signed URL in response to an API Gateway request allowing users to securely upload data directly to S3, triggered by the API Gateway.

Now how can you go about this?

I’m assuming you already have created a bucket. If not you can make one.

$ aws s3 mb s3://<bucket-name>

Next, I will set up a CORS configuration.

CORS Configuration

The Lambda Function

I used Nodejs 12x but you can use any other supported language. Here, is some sample code.

const AWS = require('aws-sdk')
AWS.config.update({ region: process.env.AWS_REGION })
const s3 = new AWS.S3();

// The Lambda handler
exports.handler = async(event) => {
const result = await getUploadURL()
console.log('Result: ', result)
return result
}

const getUploadURL = async function() {
const randomId = parseInt(Math.random() * 10000000000)

const s3Params = {
Bucket: process.env.UploadBucket,
Key: `${randomId}.jpg`,
ContentType: 'image/jpeg',
ACL: 'public-read'
// ACL: 'public-read', //Optional if you want the
object 2 be publicly readable
};

console.log('getUploadURL: ', s3Params)

return new Promise((resolve, reject) => {
// Get signed URL
resolve({
"statusCode": 200,
"isBase64Encoded": false,
"headers": {
"Access-Control-Allow-Origin": "*"
},
"body": JSON.stringify({
"uploadURL": s3.getSignedUrl('putObject', s3Params),
"photoFilename": `${randomId}.jpg`
})
})
})
}

Presigned URL generated by Lambda

You will need to adjust the execution role to give access to S3

The configuration should be as follows Specify the S3 object then:

Read => GetObject
Write => PutObject
Permisssion Management => PutObjectACL

Resources specify the ARN for the bucket:

Bucket name*
Object name* < * > //specify a star (*) so that it can access
all objects in the bucket

ARN Configuration for the bucket

Next, Add a Trigger.

API endpoint

Now let's go ahead and test our endpoint, I will use Postman, copy and paste the URL endpoint to Postman

Upload URL in the response after calling the function.

That’s about it you can go ahead and build a front-end application if you want to build a UI for end-users to upload files

In your code, you specify the API ENDPOINT as follows….

const API_ENDPOINT = '>'

If you have any questions feel free to hit me up on Twitter.!!