serverless web framework for Node.js on AWS
Simone Lusenti
Co-founder & Dev @ plasticpanda
CTO @ GSO Company spa
twitter.com/Lanzone31
github.com/lusentis
Background
AWS Lambda
Amazon API Gateway
Amazon CloudFront
AWS CloudFormation
AWS Lambda
// index.js
exports.handler = function (event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));
// logic here...
callback(null, {
response: 'Awesome!'
});
};
deploying single functions to the AWS cloud, without any server to manage
$ aws lambda create-function \
--function-name XXX \
--function-code fileb://index.zip
Amazon API Gateway
creating and managing HTTP(S) Endpoints
# Call an AWS Lambda Function via HTTP (REST)
POST http://abcdef123.execute-api.eu-west-1.amazonaws.com/prod/weather
- each HTTP path can be connected to an AWS Lambda Function
- response can be text/html, application/json, text/plain, etc...
Creating the infrastructure
... using the AWS Console or the AWS CLI?
$ zip index.zip index.js node-modules/**/*
$ aws iam create-role \
--role-name RoleForLambdaFunc1 \
--policy-document ‘{JSON here...}’ \
--trust-policy ‘{JSON here...}’
$ aws lambda create-function \
--function-name LambdaFunc1 \
--function-code fileb://index.zip \
--runtime nodejs4.3 \
--memory 512 \
--timeout 30 \
--handler index.handler \
--role arn:aws:iam:XXX:XXX:role/XXX
- Easy to replicate
- failover
- redundancy in other regions
- Tracking infrastructure changes
- rolling back mistakes
Infrastructure-as-Code
Creating the infrastructure
- Defined as plain text files
AWS CloudFormation
an easy way to create and manage a collection of related AWS resources, provisioning and updating them in an orderly and predictable fashion.
AWS CloudFormation
AWS CloudFormation
"API": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Description": "REST API for dawson app",
"Name": "AppAPIDevel"
}
},
"PermissionForLambdaBarAPI": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Fn::Sub": "\x24{LambdaBarAPI.Arn}"
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:execute-api:\x24{AWS::Region}:\x24{AWS::AccountId}:\x24{API}/prod*"
}
}
},
"ExecutionRoleForLambdaBarAPI": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
],
"AWS": [{ "Fn::Sub": "arn:aws:iam::\x24{AWS::AccountId}:root" }]},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "dawson-policy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": {
"Fn::Sub": "arn:aws:logs:\x24{AWS::Region}
:\x24{AWS::AccountId}:*"
}
},
{
"Effect": "Allow",
"Action": [
"cloudformation:DescribeStacks"
],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:cloudformation:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":stack/",
{
"Ref": "AWS::StackName"
},
"/*"
]
]
}
}
]
}
}
]
}
},
serverless web framework for Node.js apps on AWS
dawson
0. Use cases
- API / Backend
- Single Page App + API
- Server-rendered Pages
dawson
- no boilerplate
- no configuration
- no runtime dependencies
// api.js
import upperFirst from 'lodash/upperFirst';
export function greet (event) {
const name = event.params.path.name
return `Hello ${upperFirst(name)}!`
}
greet.api = {
path: 'greet/{name}'
}
$ npm install -g dawson
$ dawson deploy
URL: https://d12345678.cloudfront.net
1. Easy to start with
dawson
automatic transpilation to Node.js 4.3 via babel &
built-in support for
async / await and Promise
// api.js
import fetch from 'node-fetch';
export async function greet (event) {
const response =
await fetch('http://apis.weather.com/today')
const data = await response.json()
return `Today's weather: ${data.weather}`;
}
greet.api = {
path: 'weather/today'
}
2. State-of-the-art JS
dawson
dedicated IAM Role for each function
& fully-customizable permissions
out-of-the-box https:// & automatic provisoning of SSL/TLS Certs for custom domains (for free, via AWS ACM)
3. Built-in security
native support for API Gateway's
Custom Authorizers
dawson
safe Stack Policy to prevent accidental deletions of S3 Buckets, DynamoDB Tables, ...
3. Built-in security
dawson
CloudFront to cache assets &
proxy API requests
deploy and scale to multiple AWS Regions
4. Out-of-the-box scalability
cheap support for multiple stages and
unlimited* stages per Region
dawson
100%
CloudFormation
5. Easy to extend and opt-out
100% customizable
Templates
Stateless
// api.js
import dynamoDBTable
from 'dawson-snippets/dynamodb-table';
const barTable = dynamoDBTable({
tableLogicalName: 'TableBar',
primaryKeyName: 'BarId',
enableStream: true
});
export function customTemplateFragment() {
return {
Resources: barTable
};
}
dawson
6. Pre-packaged basic infrastructure
// api.js
import pug from 'pug';
const templateFn = pug.compileFile('index.pug');
export function greet (event) {
return templateFn({ now: Date.now() });
}
greet.api = {
path: 'greet/{name}'
}
Public Assets
Public URL
dawson
Real-time log streaming
$ dawson log --follow -f userLogin
dawson v0.23.0
myapp ↣ us-east-1 ↣ preview
2017-2-28 17:47:16
Tailing logs for Lambda 'myappPreview-LambdaUserLogin-157OXJZ60ULMX'
Feb 28, 2017 5:47 PM START RequestId: a2133d5c-fdd5-11e6-9a94-915c63666d37 Version: $LATEST
Feb 28, 2017 5:47 PM
a2133d5c-fdd5-11e6-9a94-915c63666d37
event { params:
{ path: {},
querystring: {},
header:
{ Accept: 'application/json',
'Accept-Encoding': 'gzip',
'Accept-Language': 'en-GB,en;q=0.8,en-US;q=0.6,it;q=0.4',
'CloudFront-Forwarded-Proto': 'https',
'CloudFront-Is-Desktop-Viewer': 'true',
'CloudFront-Is-Mobile-Viewer': 'false',
'CloudFront-Is-SmartTV-Viewer': 'false',
'CloudFront-Is-Tablet-Viewer': 'false',
'CloudFront-Viewer-Country': 'US',
'Content-Type': 'application/json',
7. CLI integration with CloudWatch Logs
dawson
8. Awesome development experience
$ dawson dev
dawson
8. Awesome development experience
$ dawson dev
dawson
8. Awesome development experience
$ dawson dev
$ curl 'http://127.0.0.1:3000/prod/bar' -H 'content-type: application/json' -v
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET /prod/bar HTTP/1.1
> User-Agent: curl/7.50.1
> Accept: */*
> content-type: application/json
>
< HTTP/1.1 200 OK
< Date: Tue, 28 Feb 2017 17:24:28 GMT
< Content-Type: application/json
< Content-Length: 77
< Connection: keep-alive
{ "foo": "lorem ipsum" }
dawson
8. Awesome development experience
- runs functions with their own AWS permissions
-
lambci/docker-lambda
- almost-native AWS Lambda environment
- run app without deploying, via browser, curl, ...
(functions & public assets)
- can run functions locally in response to AWS Events
$ dawson dev
dawson
9. Getting started
// api.js
import upperFirst from 'lodash/upperFirst';
export function greet (event) {
const name = event.params.path.name
return `Hello ${upperFirst(name)},
you look awesome!`
}
greet.api = {
path: 'greet/{name}'
}
$ npm install -g dawson
$ export AWS_REGION=eu-west-1 AWS_PROFILE=bar
$ dawson deploy
URL: https://d12345678.cloudfront.net
dawson-org/dawson-cli
dawson
(semver starting with 1.0.0)
https://dawson.sh
twitter.com/Lanzone31
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
dawson @ serverless meetup 20170303
By Simone Lusenti
dawson @ serverless meetup 20170303
- 663