Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save tonkatsu7/e4c026e93d07ff7350fee53e99eab2a6 to your computer and use it in GitHub Desktop.
Save tonkatsu7/e4c026e93d07ff7350fee53e99eab2a6 to your computer and use it in GitHub Desktop.
Safari Books Online - Hands-on Serverless Architecture with AWS Lambda by Alan Rodrigues

Si's learning notes

Video tutorial

Safari Books Online - Hands-on Serverless Architecture with AWS Lambda by Alan Rodrigues

Code repo https://github.com/PacktPublishing/Hands-on-Serverless-Architecture-with-AWS-Lambda

NOTE" original video was done using Node.js 6.10 runtime for Lambda - I'll be using the latest at the time of writing which s 8.10

Some useful 8.10 lnks

Pre-requisites

  1. AWS account

Creating a Lambda function

  1. Create a new Lambda function
    1. Named customerapp
    exports.handler = async (event) => {
        // TODO implement
        const response = {
            statusCode: 200,
            body: JSON.stringify('Hello from Lambda!')
        };
    
        console.log("Hello Phamalicious")
        console.log('value1 =', event.key1);
        console.log('value2 =', event.key2);
        console.log('value3 =', event.key3);
        return response;
    };
  2. Create a new role using role templates
    1. Named customerrole
      • AWSLambdaBasicExecutionRole

Creating DynamoDB table & reading from Lambda using AWS-SDK

  1. Create a new table
    1. Name Customer
    2. Partition key
      • Named 'ID' of type 'Number'
    3. Accept all defaults
  2. View the table
  3. View items
  4. Insert some sample data with schema as we go
    {
      {
        "ID": "1",
        "Name": "John"
       },
       {
        "ID": "2",
        "Name": "Mark"
       },
       {
        "ID": "3",
        "Name": "James"
       },
      }
    }
    
  5. Edit Lambda function to read from Customer table using the SDK
    1. Import the sdk and use promises in Node.js 8.10
    let AWS = require('aws-sdk');
    
    exports.handler = async (event) => {
      let docClient = new AWS.DynamoDB();
      let table = "Customer";
      let id = "1";
    
      let params = {
          TableName: table,
          Key: {
              "ID": {
                  N: id
              }
          }
      };
      console.log("0");
    
      // return docClient.getItem(params, function(err, data) {
      //     console.log("1");
      //     if (err) {
      //         console.log("2");
      //         console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
      //     } else {
      //         console.log("3");
      //         console.log("GetItem succeeded:", JSON.stringify(data, null, 2))
      //     }
      // }).promise();
    
      // return await docClient.getItem(params).promise();
      let data;
    
      try {
        data = await docClient.getItem(params).promise();
      } 
      catch (err) {
        console.log(err);
        return err;
      }
    
      return data.Item;
    };
    1. Add the presmission to the Lambda's role to read from Dynamo
      1. In IAM, for role customerrole
        • AmazonDynamoDBReadOnlyAccess
    2. Testing will produce output with return value from method call
    Response:
    {
      "Item": {
        "ID": {
          "N": "1"
        },
        "Name": {
          "S": "John"
        }
      }
    }
    
    Request ID:
    "eaa9fdea-da5e-11e8-b001-ad153824f7d3"
    
    Function Logs:
    START RequestId: eaa9fdea-da5e-11e8-b001-ad153824f7d3 Version: $LATEST
    2018-10-28T03:09:43.714Z	eaa9fdea-da5e-11e8-b001-ad153824f7d3	0
    END RequestId: eaa9fdea-da5e-11e8-b001-ad153824f7d3
    REPORT RequestId: eaa9fdea-da5e-11e8-b001-ad153824f7d3	Duration: 802.15 ms	Billed Duration: 900 ms 	Memory Size: 128 MB	Max Memory Used: 30 MB	
    

Exposing the Lambda function using API Gateway

  1. Create a new API
    1. API Named customer
    2. Leave Endpoint Type as Regional
  2. Create a method
    1. Actions > Create Method > POST
    2. Once created, leave Integration Type as Lambda Function
      1. Lambda Function is customerapp (should auto complete)
      2. Leave other defults and click Save (arn:aws:lambda:ap-southeast-2:040656198761:function:customerapp)
    3. Test API gateway method
      1. Request body
      {"ID":"3"}
      1. Edit Lambda function to get ID from incoming request body
      let AWS = require('aws-sdk');
      
      exports.handler = async (event) => {
          let docClient = new AWS.DynamoDB();
          let table = "Customer";
          let id = event["ID"];
      
          console.log("checking id=", id);
      
          let params = {
              TableName: table,
              Key: {
                  "ID": {
                      N: id
                  }
              }
          };
      
          let data;
      
          try {
              data = await docClient.getItem(params).promise();
          } 
          catch (err) {
              console.log(err);
              return err;
          }
      
          return data.Item;
      };
  3. Deploy API
    1. Actions > Deploy API
    2. Create a new stage by selecting New Stage and call it Production
    3. Note the invocation URL https://XXXXXXXXXX.execute-api.ap-southeast-2.amazonaws.com/Production
  4. Enable CORS
    1. Actions > Enable CORS
    2. Click Enable CORS
    3. Deploy API again Actions > Deploy API and select previously created Production stage
  5. Test public POST API using sample static webpage
    <!DOCTYPE html>
    <html>
        <head>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
            <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
            <script>
                $(document).ready(function(){
                    console.log("In ready!");
                    $("button").click(function(){
                        console.log("Button click!");
                        var jsonData = {};
                        jsonData['ID'] = document.getElementById("cid").value;
                        console.log(jsonData['ID']);
                        $.ajax({
                            type: "POST",
                            url: "https://XXXXXXXX.execute-api.ap-southeast-2.amazonaws.com/Production",
                            crossDomain: true,
                            data: JSON.stringify({"ID": jsonData['ID']}),
                            contentType: "application/json",
                            dataType: "json",
                            success: function(data, status) {
                                console.log(data);
                                document.getElementById("Cname").value = data.PersonName.S;
                            }
                        });
                    });
                });
            </script>
        </head>
        <body>
            <div class="jumbotron">
                <div class="container text-center">
                    <h1>Customer Data</h1>
                    <p>Data</p>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="col-xs-2">
                        <label for="usr">ID:</label>
                        <input type="text" class="form-control" id="cid">
                    </div>
                </div>
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="col-xs-2">
                        <label for="usr">Name:</label>
                        <input type="text" class="form-control" id="Cname">
                    </div>
                </div>
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="col-xs-2">
                        <button type="submit" value="Submit">Get Name</button>
                    </div>
                </div>
            </div>
        </body>
    </html>

Using S3 to host static webpage

  1. Create a enw bucket
    1. Edit public access settings for this bucket
      1. Leave default options
    2. Properties > Static website hosting
    3. Enable by selecting radio button 'Use this bucket to host a website'
      1. Index Document = same test page in previous API Gateway testing
      2. Note the public URL
      3. Click Save
    4. Upload html file
      1. Overview tab
      2. Click Upload and upload the file
      3. After uploading, you're taken back to the Overview tab
      4. Click into the uplaoded file in the bucket listing and click Mark public

Using Cognito for identity and authenticaiton

WebApp --> UserPool --> Tokens --> IdentityPool --> AWS Credentials --> AWS Services

  1. Define a user pool

    1. Create a user pool
      1. Named customerapp
      2. Stepping through the settings for this exercise
        1. Leave default Username
        2. Leave default standard attributes
          1. Email
        3. Leave default password policy
        4. Leave default allowing users to sign themselves up
        5. Leave remaining defaults (including App clients as default too as we'll do that later)
        6. Click Create pool
      3. In the confirmation screen, note t Pool iid
  2. Define an App Client

    1. Go to user pool for customerapp > App clients
    2. Click on Add an app client
      1. Name as demoapp
      2. Uncheck 'Generate client secret' as this is not needed by Javascript client app
      3. Check 'Enable username-password (non-SRP) flow for app-based authentication (USER_PASSWORD_AUTH)'
    3. In the App Client confirmation screen, note the App client id
  3. Using a demo page to sign up or register by consuming the Cognito API from Javascript

    <!DOCTYPE html>
    <html>
        <head>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
            <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
            <script src="node_modules/amazon-cognito-identity-js/dist/amazon-cognito-identity.min.js"></script>
            <script>
                $(document).ready(function(){
                    console.log("In ready!");
                    $("button").click(function(){
                        console.log("Button click!");
                        var name = document.getElementById("username").value;
                        var password = document.getElementById("password").value;
                        var email = document.getElementById("email").value;
    
                        var CognitoUserPool = AmazonCognitoIdentity.CognitoUserPool;
    
                        var poolData = {
                            UserPoolId: 'ap-southeast-2_od8tqWHJT',
                            ClientId: '57ni95hiu2mvulnss24nk6kt10'
                        };
    
                        var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
    
                        var attributeList = [];
    
                        var dataEmail = {
                            Name: 'email',
                            Value: email
                        };
    
                        var dataGivenName = {
                            Name: 'given_name',
                            Value: name
                        };
    
                        var attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail);
                        var attributeGivenName = new AmazonCognitoIdentity.CognitoUserAttribute(dataGivenName);
    
                        attributeList.push(attributeEmail);
                        attributeList.push(attributeGivenName);
    
                        userPool.signUp(name, password, attributeList, null, function(err, result) {
                            if (err) {
                                alert(err.message || JSON.stringify(err));
                                return;
                            }
                            cognitoUser = result.user;
                            console.log('Username is ' + cognitoUser.getUsername());
                        });
                    });
                });
            </script>
        </head>
        <body>
            <div class="jumbotron">
                <div class="container text-center">
                    <h1>Sample Application</h1>
                    <p>Sign up</p>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="col-xs-2">
                        <label for="usr">Username:</label>
                    </div>
                    <div class="col-xs-2">
                        <label for="usr">Password:</label>
                    </div>
                    <div class="col-xs-2">
                        <label for="usr">Email:</label>
                    </div>
                </div>
                <div class="col-sm-offset-2 col-sm-10">
                        <div class="col-xs-2">
                            <input type="text" class="form-control" id="username">
                        </div>
                        <div class="col-xs-2">
                            <input type="password" class="form-control" id="password">
                        </div>
                        <div class="col-xs-2">
                            <input type="email" class="form-control" id="email">
                        </div>
                        <div class="col-xs-2">
                            <button type="submit" value="Submit">Register</button>
                        </div>
                    </div>
            </div>
        </body>
    </html>
    1. Noting that to import the amazon-cognito-identity library, using npm in the root of the html files
    // install only the auth module of aws-amplify
    npm install @aws-amplify/auth --save
    
    1. Then search for amazon-cognito-identity.min.js should return a relative path similar to node_modules/amazon-cognito-identity-js/dist/amazon-cognito-identity.min.js

    2. Upload only the follwoing files to the root of the same S3 bucket to host statically (remembering to make public)

      1. Demo.html
      2. node_modules/amazon-cognito-identity-js/dist/amazon-cognito-identity.min.js (directories too)
  4. Create an authorizer for the customerapp API with the customerapp User Pool

SQS

SNS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment