Getting started with AWS.

How to build RESTful API

Dzmitry Tsebruk

Junoir Software Engineer

AWS

Junior Developer

What is FaaS?

AWS Overview

Lambda

Cold and Warm start

How to write Lambda Function?

exports.handler = (event, context, callback) => {
  https.get(url, (res) => {
    callback(null, res.statusCode)
  }).on('error', (e) => {
    callback(Error(e))
  })
}
exports.handler = async (event) => { 
  return new Promise((resolve, reject) => {
    if (Math.random() * 2 ^ 0) {
      resolve();
    } else {
      reject();
    }
  });
}

or

exports.handler = async (event) => {
  return https.get(url).promise();
}

or

Livecoding

IAM

Livecoding

API Gateway

Livecoding

Ways to manage AWS

AWS CLI usage example

# aws lambda invoke \
  --function-name <value> \
  <outfile>

Livecoding

Terminal

AWS SDK usage example

var lambda = new AWS.Lambda();
lambda.addLayerVersionPermission(params, function (err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});
var lambda = new AWS.Lambda();
lambda.addLayerVersionPermission(params).promise();

or

Database Services

Livecoding

AWS Free Tier

Free Tier Details

Billing Dashboard

Billing Dashboard

Pros & Cons

Pros

  1. Cheap cost
  2. Auto scalable
  3. You can make simple things easily

Cons

  1. You should track what happens
  2. Сomplex architecture
  3. It's hard to make tests 
  4. Steep learning curve 

Serverless Framework

Install framework and setup credentials

# npm install -g serverless

serverless.yml

service: aws-rest-ful-api

custom:
  tableName: 'table-notes-${self:provider.stage}'
  dynamodb:
    start:
      migrate: true

provider:
  name: aws
  runtime: nodejs8.10
  stage: dev
  region: us-east-1
  environment:
    NOTES_TABLE: ${self:custom.tableName}

serverless.yml

functions:
  create:
    handler: src/handler.create
    events:
      - http:
          path: notes
          method: post
          cors: true
  getAll:
    handler: src/handler.getAll
    events:
      - http:
          path: notes
          method: get
          cors: true
  delete:
    handler: src/handler.delete
    events:
      - http:
          path: notes/{id}
          method: delete
          cors: true
  ...

serverless.yml


resources:
  Resources:
    NotesDynamoDBTable:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        AttributeDefinitions:
          -
            AttributeName: id
            AttributeType: S
        KeySchema:
          -
            AttributeName: id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:custom.tableName}

serverless.yml

    NotesDynamoDBIamPolicy:
      Type: AWS::IAM::Policy
      DependsOn: NotesDynamoDBTable
      Properties:
        PolicyName: lambda-dynamodb
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - dynamodb:Query
                - dynamodb:Scan
                - dynamodb:GetItem
                - dynamodb:PutItem
                - dynamodb:UpdateItem
                - dynamodb:DeleteItem
              Resource: arn:aws:dynamodb:*:*:table/${self:custom.tableName}
        Roles:
          - Ref: IamRoleLambdaExecution

How to build RESTful API

src/handler.js

const AWS = require('aws-sdk');
const uuidv1 = require('uuid/v1');
const message = require('./message');

const dynamoDb = new AWS.DynamoDB.DocumentClient();
const { NOTES_TABLE } = process.env;

module.exports.create = async (event) => {
    ...
};

module.exports.getOne = async (event) => {
    ...
};

module.exports.getAll = async () => {
    ...
};

module.exports.update = async (event) => {
    ...
};

module.exports.delete = async (event) => {
    ...
};

src/handler.js

module.exports.getOne = async (event) => {
  const { id } = event.pathParameters;

  const params = {
    TableName: NOTES_TABLE,
    Key: {
      id,
    },
  };

  return new Promise((resolve) => {
    dynamoDb.get(params, (error, result) => {
      if (error) {
        global.console.log(error);

        message(400, 'Could not get the note!', resolve);
      }

      if (result.Item) {
        message(200, JSON.stringify(result.Item), resolve);
      } else {
        message(404, 'Note is not found', resolve);
      }
    });
  });
};

src/message.js

module.exports = (statusCode, body, callback) => {
  const message = {
    statusCode,
    body,
  };

  message.headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Credentials': true,
  };

  if (statusCode !== 200) {
    message.headers['Content-Type'] = 'text/plain';
  }

  callback(message);
};

Deploying

# serverless deploy

Deploying

Now we can use endpoints ...

Thank You!

Links

Q&A

AWS

By Dzmitry Tsebruk

AWS

  • 256