Intro to Serverless API Workshop
Evolution of development systems
hardware
virtual machine
containers and clusters
Serverless Computing
functions as a service (FaaS)
serverless databases
state machines
Lets Get Started
node.js v4 or higher
Atom IDE unless you love vim / emacs or have another IDE
AWS Account can get for free
Get `em if you don't have `em
serverless platform account login with github account
Super quick serverless start
mkdir ~/intro-to-serverless
cd ~/intro-to-serverless
mkdir hello-world-serverless
cd hello-world-serverless
npm install -g serverless
serverless login
serverless create -t aws-nodejs
In Terminal:
In serverless.com:
1. Create an app called:
hello-world-serverless
Super quick start, cont.
1. Open project folder:
intro-to-serverless
2. Open file: intro-to-serverless/hello-world- serverless/serverless.yml
3. Change line #14 - #16 to:
In Atom:
service: hello-world-serverless
app: serverless-workshop
tenant: [put your serverless id / github id here]
serverless deploy
In Terminal:
4. After line #60 add:
events:
- http:
path: /hello
method: get
cd ~/intro-to-serverless
mkdir puppy-tracker && cd puppy-tracker
npm init -f
npm install --save express serverless-http aws-sdk body-parser
npm install --save-dev serverless-offline serverless-dynamodb-local
In Terminal:
In serverless.com:
1. Create a new app called:
puppy-tracker
Puppy Tracker API
1. In project folder folder intro-to-serverless/puppy-tracker:
create index.js file
In Atom:
Puppy Tracker cont..
const serverless = require('serverless-http');
const express = require('express')
const app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
module.exports.handler = serverless(app);
In Atom
1. In index.js:
service: puppy-tracker
tenant: [put your serverless id / github id here]
app: puppy-tracker
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1
functions:
app:
handler: index.handler
events:
- http: ANY /
- http: 'ANY {proxy+}'
Create new file serverless.yml file in same directory and
add the following code:
Deploy:
serverless deploy -v
service: puppy-tracker
tenant: [put your serverless id / github id here]
app: puppy-tracker
custom:
tableName: 'puppies-table-${self:provider.stage}'
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- { "Fn::GetAtt": ["PuppiesDynamoDBTable", "Arn" ] }
environment:
PUPPIES_TABLE: ${self:custom.tableName}
serverless.yml
functions:
app:
handler: index.handler
events:
- http: ANY /
- http: 'ANY {proxy+}'
getUser:
handler: index.handler
events:
- http: 'GET /puppy/{proxy+}'
createUser:
handler: index.handler
events:
- http: 'POST /puppies'
resources:
Resources:
PuppiesDynamoDBTable:
Type: 'AWS::DynamoDB::Table'
Properties:
AttributeDefinitions:
-
AttributeName: puppyId
AttributeType: S
KeySchema:
-
AttributeName: puppyId
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:custom.tableName}
serverless.yml
const serverless = require('serverless-http');
const bodyParser = require('body-parser');
const express = require('express')
const app = express()
const AWS = require('aws-sdk');
const PUPPIES_TABLE = process.env.PUPPIES_TABLE;
const dynamoDb = new AWS.DynamoDB.DocumentClient();
app.use(bodyParser.json({ strict: false }));
app.get('/', function (req, res) {
res.send('Hello World!')
})
index.js
// Get Puppy endpoint
app.get('/puppies/:puppyId', function (req, res) {
const params = {
TableName: PUPPIES_TABLE,
Key: {
puppyId: req.params.puppyId,
},
}
dynamoDb.get(params, (error, result) => {
if (error) {
console.log(error);
res.status(400).json({ error: 'Could not get puppy' });
}
if (result.Item) {
const {puppyId, name} = result.Item;
res.json({ puppyId, name });
} else {
res.status(404).json({ error: "Puppy not found" });
}
});
})
index.js
// Create Puppy endpoint
app.post('/puppies', function (req, res) {
const { puppyId, name } = req.body;
if (typeof puppyId !== 'string') {
res.status(400).json({ error: '"puppyId" must be a string' });
} else if (typeof name !== 'string') {
res.status(400).json({ error: '"name" must be a string' });
}
const params = {
TableName: PUPPIES_TABLE,
Item: {
puppyId: puppyId,
name: name,
},
};
dynamoDb.put(params, (error) => {
if (error) {
console.log(error);
res.status(400).json({ error: 'Could not create puppy' });
}
res.json({ puppyId, name });
});
})
module.exports.handler = serverless(app);
index.js
Test Routes
$ serverless deploy -v
Deploy:
curl -H "Content-Type: application/json" \
-X POST ${BASE_DOMAIN}/puppies \
-d '{"puppyId": "rudy1234", "name": "Rudy"}'
Run curl command to create puppy:
curl -H "Content-Type: application/json" \
-X GET ${BASE_DOMAIN}/puppies/rudy1234
Retrieve puppy:
export BASE_DOMAIN=[you can find this in your dashboard or after a deploy]
Set the BASE_DOMAIN variable to your unique domain and base path so it's easier to reuse:
Local Development
plugins:
- serverless-dynamodb-local
- serverless-offline
custom:
tableName: 'puppies-table-${self:provider.stage}'
dynamodb:
start:
migrate: true
In serverless.yml:
- add dynamodb to custom block
- add new plugins block
serverless dynamodb install
Run command to install DynamoDB local:
Local Development
const serverless = require('serverless-http');
const bodyParser = require('body-parser');
const express = require('express')
const app = express()
const AWS = require('aws-sdk');
const PUPPIES_TABLE = process.env.PUPPIES_TABLE;
const IS_OFFLINE = process.env.IS_OFFLINE;
let dynamoDb;
if (IS_OFFLINE === 'true') {
dynamoDb = new AWS.DynamoDB.DocumentClient({
region: 'localhost',
endpoint: 'http://localhost:8000'
})
console.log(dynamoDb);
} else {
dynamoDb = new AWS.DynamoDB.DocumentClient();
};
app.use(bodyParser.json({ strict: false }));
... rest of application code ...
In index.js:
- change beginning to following:
Local Development
$ serverless offline start
Start offline server:
curl -H "Content-Type: application/json" \
-X POST http://localhost:3000/puppies \
-d '{"puppyId": "rudy1234", "name": "Rudy"}'
In seperate terminal run curl command to create puppy:
curl -H "Content-Type: application/json" \
-X GET http://localhost:3000/puppies/rudy1234
Retrieve puppy:
Resources
Intro to Serverless API Workshop
By Julia Jacobs
Intro to Serverless API Workshop
- 488