National Park of Minnesota

    aws-api-lambda-scaffold

    2.0.5 • Public • Published

    AWS API Gateway and Lambda function integration scaffolding for Node.js

    Project setup

    You need to install AWS-CLI. (pip install --upgrade --user awscli)

    You need to setup AWS-CLI with your credentials. (aws configure)

    You need to install mocha for running tests (npm install --global mocha)

    Features

    • Routing
    • Response transformation
    • Layered middleware

    What's new

    v.2.0.0 - Added middleware, refactored code and project minification

    API Gateway setup

    Creating a new endpoint

    When creating a new method for a resource endpoint check the "Use Lambda Proxy integration" checkbox to pass request data into the event object in the lambda function.

    Lambda setup

    Configuration

    Select the Node.js 6+ Runtime

    Lambda Node.js support: http://www.whatdoeslambdasupport.com/

    Installation

    Using npm

    npm i aws-api-lambda-scaffold

    Working with the framework

    Main function

    The main handler function should be defined in the index.js file and is the entry and exit point for the application.

    Import the scaffold package:

    const scaffold = require("aws-api-lambda-scaffold")

    Or import the Router and Response classes directly

    const Router = require("aws-api-lambda-scaffold").Router,
          Response = require("aws-api-lambda-scaffold").Response;

    Program flow

    Upon invoking the handler a Router instance should be created and passed event and context parameters. All of the routes that need to be handled need to be registered with the Router instance by invoking Router.route(path, method, handler). The Router will handle the request and invoked the provided callback when you invoke the Router.process(callback) method. If a route is not found the Router will throw an error.

    To instantiate the Router:

    const router = new scaffold.Router(event, context);

    And when instantiating a Response or CustomResponse

    return new scaffold.Response(body, statusCode, isBase64Encoded, headers)
    const response = new scaffold.CustomResponse(headers, isBase64Encoded);
     
    // Send the response
    return response.send(body);

    Both Response classes have a default header value of:

    {"Content-type": "application/json"}

    The benefits of using a custom response and passing it to the router is that you can share response data without having to write it multiple times.

    To see an example Lambda function, view the demo.js file in the package directory.

    Routes

    To add a route to the router after instantiation use the following

    router.route("/route/{param}", "GET", handler, [middleware, middleware]);

    The route will match if the lambda is invoked trough API Gateway with the specified path, and the handler function will be invoked.

    Route handler

    The route handler is a function that will be invoked when a resource match is found. It will receive the request data object, which contains useful information which can be extracted from the event object and the execution callback that can be invoked for async functions. It will also be injected with the CustomResponse instance that is passed to Router.process(ctx, responseInstance) or a newly instantiated CustomResponse class if none is passed to Router.process(ctx, customResponseInstance).

    function ({requestBody, queryStringParameters, pathParameters, headers, stageVariables, requestContext}, response, callback) {
        /** function body */
    }

    If the handler returns a value it must return a Response object with the following format

    {
        "isBase64Encoded": Boolean,
        "statusCode": Number,
        "headers": {"key": "val"},
        "body": String
    }

    Or it should invoke the callback (ie. if the function is doing async work and has no return value). The handler should return a Response instance a CustomResponse.send(body) object.

    Example API Gateway route test: http://i.imgur.com/dPkux1k.png

    Basic directory structure we recommend is having a separate directory for all the route handlers. (You can see an example in the package directory)

    Middleware

    Middleware is one of those very flexible things allowing you to seperate your lambda properly by removing logging/authorization/etc... from your handler's business logic.

    If your handlers run sync code, you need to return the next(request) or assign it to a variable and then return the code. In case of async handlers the middleware must NOT return anything if you want to proceed further, otherwise the framework will use the returned value as the lambda execution result.

    Sync handler middleware

    function ({requestBody, queryStringParameters, pathParameters, headers, stageVariables, requestContext}, responseInstance, next) {
        // If error you can return it and the execution will stop there
        if (error) {
            return response.send({success: false});
        }
     
        // If you want the middleware to resolve and progress invoke next(request);
        return next(request);
    }

    Async handler middleware

    function ({requestBody, queryStringParameters, pathParameters, headers, stageVariables, requestContext}, responseInstance, next) {
        // If error you can return it and the execution will stop there
        if (error) {
            // End the lambda execution early due to an error by invoking the original callback to end lambda execution
            return request.callback(null, response.send({success: false}));
        }
     
        // If you want the middleware to resolve and progress invoke next(request);
        next(request);
    }

    Example usage can be found in the demo.js file.

    Publishing your changes to the Lambda

    Create a .lambda_contents file in your root directory (example .lambda_contents is located in the package directory), and add your lambda project files and folders separated by newlines.

    When you want to apply changes to the lambda you can run the publish.sh script from the package directory.

    ./node_modules/aws-api-lambda-scaffold/publish.sh yourLambdaName

    (Replace yourLambdaName with your Lambda function name)

    It will automatically zip all of the files from the .lambda_contents file and push the changes to the lambda using aws-cli.

    Running tests

    To run tests you can execute npm run test which will run all mocha tests located in the test directory

    Mocha docs: https://mochajs.org/

    Misc

    Webstorm js language help

    Install assert-plus, node, mocha libraries to get code completion and help in WebStorm and enable nodejs coding assistance

    Useful links

    http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html

    Example Lambda data availability

    The Lambda handler is receiving three parameters: event, context and callback The event contains request data, context contains the lambda context and callback – You can use the optional callback to return information to the caller, otherwise return value is null. It should be invoked because it terminates the lambda function properly.

    {
        "event": {
            "resource": "/hash",
            "path": "/hash",
            "httpMethod": "POST",
            "headers": null,
            "queryStringParameters": null,
            "pathParameters": null,
            "stageVariables": null,
            "requestContext": {
                "path": "/hash",
                "accountId": "123",
                "resourceId": "7kyb5s",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": null,
                    "accountId": "123",
                    "cognitoIdentityId": null,
                    "caller": "CALLER",
                    "apiKey": "test-invoke-api-key",
                    "sourceIp": "test-invoke-source-ip",
                    "accessKey": "YOURACCESSKEY",
                    "cognitoAuthenticationType": null,
                    "cognitoAuthenticationProvider": null,
                    "userArn": "arn:aws:iam::123:user/nenad-lukic",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_112)",
                    "user": "123"
                },
                "resourcePath": "/hash",
                "httpMethod": "POST",
                "apiId": "123ijjk13"
            },
            "body": "{\n    \"email\"\"djole@gmail.com\"\n}",
            "isBase64Encoded": false
        },
        "context": {
            "callbackWaitsForEmptyEventLoop": true,
            "logGroupName": "/aws/lambda/createAnIntercomHash",
            "logStreamName": "2017/06/05/[$LATEST]124241",
            "functionName": "createAnIntercomHash",
            "memoryLimitInMB": "128",
            "functionVersion": "$LATEST",
            "invokeid": "8ad3b3c0-49fe-11e7-86d5-a38a3b86ba05",
            "awsRequestId": "8ad3b3c0-49fe-11e7-86d5-a38a3b86ba05",
            "invokedFunctionArn": "arn:aws:lambda:ap-southeast-2:127579097966:function:createAnIntercomHash"
        }
    }

    Install

    npm i aws-api-lambda-scaffold

    DownloadsWeekly Downloads

    0

    Version

    2.0.5

    License

    MIT

    Unpacked Size

    27.4 kB

    Total Files

    14

    Last publish

    Collaborators

    • lnenad