Notes and annotations for https://egghead.io/courses/develop-a-serverless-backend-using-node-js-on-aws-lambda
- Create an IAM user with programmatic access, and AdministratorAccess policy (for ease of testing / evaluation - not recommended for production)
- Install
awscli
:$ brew install awscli
- Store the user's key on your system by:
- Running
$ aws configure
- Entering Access Key ID for new user
- Entering Secret access key for new user
- Used defaults for remaining options
- Running
- Install
serverless
framework:$ npm i -g serverless
sls
is an alias for theserverless
command$ sls
will show all commands available through the serverless framework- You can use
sls create -h
to see how to bootstrap projects
-
create
serverless.yml
-
add
service
property with name of your application -
add
provider
block with name of provider and runtime for your service -
add
functions
block to define your functions -
in
functions
block add a name for a function, and in that block add ahandler
property withhandler.[my-export-name]
for the function that Lambda will execture for that function block -
create a js file with a named export of the same name as the handler defined in the above step.
-
lambdas take 3 parameters
- event - request data
- context - aws-specific data
- callback - a function that should be invoked with either an error response for the first argument, or a success response for the second argument
-
deploy the service using
sls deploy
-
test the service works by running
sls invoke --function [functionName]
-
console.log
statements can be evaluated by running theinvoke
command with the--log
flag:$ sls invoke --function myFunc --log
-
one can view past logs for a function, too:
$ sls logs --function myFunc
-
instead of calling the callback in the function, we can instead return a promise
-
to redeploy a change to a specific function faster, run:
$ sls deploy --function myFunc
-
with Node 8 we can leverage
async / await
, so we can define a function asasync
instead of explicitly returning a promise
-
we can configure HTTP endpoints for lambdas by defining an HTTP path and method in
serverless.yml
on theevents
property. -
to create a
GET
request at the path/
we can do the following:functions: myFunction: handler: [file-name].[function-name] events: - http path: / method: GET
-
lambdas can only be invoked by an AWS SDK
-
AWS's API Gateway is such an SDK, and the serverless framework configures one under the hood
-
when using events for lambdas, responses must be structured with a
statusCode
andbody
-
one has to rerun deployment when
serverless.yml
is updated so that the stack is updated accordingly, and because we've added an http event, the API Gateway service needs to be configured -
once the deployment succeeds, we will receive an endpoint where a request can be made using curl etc.
To store data, we need a database
-
to add resources to your application, such as DynamoDB, add a
resources
block in the rootServerless.yml
-
nest a
Resources
block inside that block. Cloud formation also supports keywords in addition toResources
, so the nesting is required -
the minimum configuration for a table includes:
- table name
- attributes for primary and secondary instances
- key schema with mandatory properties for the primary key of the table
- throughput capacity for read and write access
-
run
$ sls deploy
to have the serverless framework configure the application -
you can see the instance in your AWS console
By default, lambdas are not allowed to interact with databases. In order to allow access, we need to create an IAM role.
The serverless
framework allows for configuration of IAM roles instead of
manually creating them.
To create an IAM role for lambdas:
-
add an
iamRoleStatements
property to the providerproperty
with the following details:provider: ... iamRoleStatements: - Effect: Allow # we need to allow our functions to put items onto the dynamo db table Action: - dynamodb:PutItem # arn:partition:service:region:account-id:resourcetype/resource Resource: "arn:aws:dynamodb:es-east-1:12398712398:table/todos"
-
the
Resource
field has the following format:"arn:aws:dynamodb:us-east-1:12398712398:table/todos" [1] [2] [3] [4] [5] [6] [7] 1 - amazon resource name 2 - partition name 3 - service 4 - region 5 - account id 6 - resource type 7 - resource
Further details can be found here: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-arns
-
It's common to see configs with * for the resource - security is improved by providing explicit access to resources, rather than wildcarding them
-
we can leverage modules from the
aws-sdk
package directly from our lambda files without having to install anything -
to create a DynamoDB client:
const AWS = require('aws-sdk') const dynamoDbClient = AWS.DynamoDB.DocumentClient();
-
to write to a DynamoDB table:
await dynamoDbClient.put({ TableName: [tablename], Item: {...itemProps} }).promise()