Skip to content

Commit

Permalink
add aws-node-upload-to-s3-and-postprocess
Browse files Browse the repository at this point in the history
Example to demonstrate how to upload a file to S3 using a HTML form, and
have an S3 event trigger a lambda function.

fixes #16
  • Loading branch information
christophgysin committed Mar 3, 2017
1 parent 044adb8 commit ec58bd9
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Have an example? Submit a PR or [open an issue](https://github.com/serverless/ex
| [Serverless Single Page App Plugin](https://github.com/serverless/examples/tree/master/aws-node-single-page-app-via-cloudfront/serverless-single-page-app-plugin) <br/> A plugin to simplify deploying Single Page Application using S3 and CloudFront | nodeJS |
| [Aws Text Analysis Via Sns Post Processing](https://github.com/serverless/examples/tree/master/aws-node-text-analysis-via-sns-post-processing) <br/> Example demonstrates how to setup a simple data processing pipeline | nodeJS |
| [Aws Node Twilio Send Text Message](https://github.com/serverless/examples/tree/master/aws-node-twilio-send-text-message) <br/> Send a text message via twilio from aws lambda. [See live demo](http://twilio-serverless-example.surge.sh) | nodeJS |
| [Upload To S3 And Postprocess](https://github.com/serverless/examples/tree/master/aws-node-upload-to-s3-and-postprocess) <br/> Upload files to S3 using a HTML form, then trigger a lambda function to postprocess. | nodeJS |
| [Aws Alexa Skill](https://github.com/serverless/examples/tree/master/aws-python-alexa-skill) <br/> This example demonstrates how to use an AWS Lambdas for your custom Alexa skill. | python |
| [Aws Rest With Dynamodb](https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-dynamodb) <br/> Serverless CRUD service exposing a REST HTTP interface | python |
| [Aws Scheduled Cron](https://github.com/serverless/examples/tree/master/aws-python-scheduled-cron) <br/> Example of creating a function that runs as a cron job using the serverless `schedule` event | python |
Expand Down
3 changes: 3 additions & 0 deletions aws-node-upload-to-s3-and-postprocess/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.serverless
index.html
89 changes: 89 additions & 0 deletions aws-node-upload-to-s3-and-postprocess/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Upload a file to S3 to trigger a lambda function

This example shows how to upload a file to S3 using a HTML form, and have S3
trigger a lambda function.

## Use-cases

- Postprocess files uploaded to an S3 bucket.

## Setup

- Edit `serverless.yml` and choose a unique S3 bucket name.
- Edit `generate-form.js` and fill in your `aws_access_key_id`,
`aws_secret_access_key` and `bucket_name`.
- Generate the HTML form:


```bash
node generate-form.js
```

## Deploy

In order to deploy the example, simply run:

```bash
serverless deploy
```

The output should look similar to:

```bash
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3 (3.85 MB)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
........................
Serverless: Stack update finished...
Service Information
service: upload-to-s3-and-postprocess
stage: dev
region: us-east-1
api keys:
None
endpoints:
None
functions:
upload-to-s3-and-postprocess-dev-postprocess

```

## Usage

Open the generated `frontend/index.html` in your browser, or run:

```bash
xdg-open frontend/index.html
```

Select a PNG image smaller than 1Mb, and click "Upload File to S3".

You should get an XML response similar to:

```xml
<PostResponse>
<Location>https://serverless-fetch-file-and-store-in-s3.s3.amazonaws.com/uploads%2Fimage.png</Location><
Bucket>serverless-fetch-file-and-store-in-s3</Bucket>
<Key>uploads/image.png</Key>
<ETag>"08c03c6a24e5058b9f3556981a23b1d7"</ETag>
</PostResponse>
```

After a while, the postprocess function gets triggerd by an S3 event:

```bash
serverless logs --function postprocess
```

```
START RequestId: e2decc94-f2a0-11e6-b641-e3fbcfad7d8c Version: $LATEST
2017-02-14 12:32:30.350 (+02:00) e2decc94-f2a0-11e6-b641-e3fbcfad7d8c New .png object has been created: uploads/image.png (23975 bytes)
END RequestId: e2decc94-f2a0-11e6-b641-e3fbcfad7d8c
REPORT RequestId: e2decc94-f2a0-11e6-b641-e3fbcfad7d8c Duration: 2.84 ms Billed Duration: 100 msMemory Size: 1024 MB Max Memory Used: 29 MB
```
24 changes: 24 additions & 0 deletions aws-node-upload-to-s3-and-postprocess/frontend/index.template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<html>
<head>
<title>S3 POST Form</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>

<body>
<form action="%BUCKET_URL%" method="post" enctype="multipart/form-data">
<input type="hidden" name="Content-Type" value="image/png">
<input type="hidden" name="AWSAccessKeyId" value="%AWS_ACCESS_KEY%">
<input type="hidden" name="acl" value="public-read">
<input type="hidden" name="success_action_status" value="201">
<input type="hidden" name="policy" value="%POLICY_BASE64%">
<input type="hidden" name="signature" value="%SIGNATURE%">

Destination filename: <input type="text" name="key" value="uploads/image.png">
<br>
File to upload to S3:
<input name="file" type="file">
<br>
<input type="submit" value="Upload File to S3">
</form>
</body>
</html>
48 changes: 48 additions & 0 deletions aws-node-upload-to-s3-and-postprocess/generate-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env node

const crypto = require('crypto');
const fs = require('fs');

const awsAccessKeyId = '<your access key id>';
const awsSecretAccessKey = '<your secret access key>';
const bucketName = '<your bucket name>';

const msPerDay = 24 * 60 * 60 * 1000;
const expiration = new Date(Date.now() + msPerDay).toISOString();
const bucketUrl = `https://${bucketName}.s3.amazonaws.com`;

const policy = {
expiration,
conditions: [
['starts-with', '$key', 'uploads/'],
{ bucket: bucketName },
{ acl: 'public-read' },
['starts-with', '$Content-Type', 'image/png'],
{ success_action_status: '201' },
],
};

const policyB64 = Buffer(JSON.stringify(policy), 'utf-8').toString('base64');

const hmac = crypto.createHmac('sha1', awsSecretAccessKey);
hmac.update(new Buffer(policyB64, 'utf-8'));

const signature = hmac.digest('base64');

fs.readFile('frontend/index.template.html', 'utf8', (err, input) => {
if (err) {
console.log(err);
}

const data = input
.replace(/%BUCKET_URL%/g, bucketUrl)
.replace(/%AWS_ACCESS_KEY%/g, awsAccessKeyId)
.replace(/%POLICY_BASE64%/g, policyB64)
.replace(/%SIGNATURE%/g, signature);

fs.writeFile('frontend/index.html', data, 'utf8', (e) => {
if (e) {
console.log(e);
}
});
});
9 changes: 9 additions & 0 deletions aws-node-upload-to-s3-and-postprocess/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

module.exports.postprocess = (event) => {
event.Records.forEach((record) => {
const filename = record.s3.object.key;
const filesize = record.s3.object.size;
console.log(`New .png object has been created: ${filename} (${filesize} bytes)`);
});
};
9 changes: 9 additions & 0 deletions aws-node-upload-to-s3-and-postprocess/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "upload-to-s3-and-postprocess",
"description": "Upload a files to S3 to trigger a lambda function.",
"version": "1.0.0",
"author": "Christoph Gysin <[email protected]>",
"license": "MIT",
"dependencies": {
}
}
25 changes: 25 additions & 0 deletions aws-node-upload-to-s3-and-postprocess/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
service: upload-to-s3-and-postprocess

frameworkVersion: ">=1.1.0"

custom:
bucket: <your-bucket-name>

provider:
name: aws
runtime: nodejs4.3
iamRoleStatements:
- Effect: Allow
Action:
- s3:*
Resource: "*"

functions:
postprocess:
handler: handler.postprocess
events:
- s3:
bucket: ${self:custom.bucket}
event: s3:ObjectCreated:*
rules:
- suffix: .png

0 comments on commit ec58bd9

Please sign in to comment.