Creating an API Gateway

Now create an API Gateway powered by Lambda for its sole REST API handler for GET requests at the / route.

The first step is to create the code for the Lambda itself — this is the code that will run in response to an API call at runtime. Place this code into a new handler/index.js file.

Create a new handler directory and create a new file index.js Paste the below code in the the javascript file:

const AWS = require("aws-sdk");

exports.handler = async function(event, context, callback) {
    console.log("Received event: ", event);
    const dc = new AWS.DynamoDB.DocumentClient();
    const result = await dc.update({
        TableName: process.env["HITS_TABLE"],
        Key: { "Site": "ACMECorp" },
        UpdateExpression: "SET Hits = if_not_exists(Hits, :zero) + :incr",
        ExpressionAttributeValues: { ":zero": 0, ":incr": 1 },
        ReturnValues: "UPDATED_NEW",
    }).promise();
    return {
        statusCode: 200,
        headers: { "Content-Type": "text/html" },
        body: "<h1>Welcome to ACMECorp!</h1>\n"+
            `<p>${result.Attributes.Hits} hits.</p>\n`,
    };
};

Next, create the API Gateway and Lambda-based handler to index.ts:

const site = new awsx.apigateway.API("site", {
    routes: [{
        path: "/",
        method: "GET",
        eventHandler: new aws.lambda.Function("get-handler", {
            runtime: aws.lambda.NodeJS10dXRuntime,
            code: new pulumi.asset.AssetArchive({
                ".": new pulumi.asset.FileArchive("handler"),
            }),
            handler: "index.handler",
            role: handlerRole.arn,
            environment: {
                variables: {
                    "HITS_TABLE": hits.name,
                },
            },
        }, { dependsOn: handlerPolicy }),
    }],
});
export const url = site.url;

The index.ts file should now have the following contents:

import * as AWS from "aws-sdk";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
import * as pulumi from "@pulumi/pulumi";

const hits = new aws.dynamodb.Table("hits", {
    attributes: [{ name: "Site", type: "S" }],
    hashKey: "Site",
    billingMode: "PAY_PER_REQUEST",
});

const handlerRole = new aws.iam.Role("handler-role", {
    assumeRolePolicy: {
        Version: "2012-10-17",
        Statement: [{
            Action: "sts:AssumeRole",
            Principal: {
                Service: "lambda.amazonaws.com"
            },
            Effect: "Allow",
            Sid: "",
        }],
    },
});

const handlerPolicy = new aws.iam.RolePolicy("handler-policy", {
    role: handlerRole,
    policy: hits.arn.apply(arn => JSON.stringify({
        Version: "2012-10-17",
        Statement: [
            {
                Action: [
                    "dynamodb:UpdateItem",
                    "dynamodb:PutItem",
                    "dynamodb:GetItem",
                    "dynamodb:DescribeTable",
                ],
                Resource: arn,
                Effect: "Allow",
            },
            {
                Action: ["logs:*", "cloudwatch:*"],
                Resource: "*",
                Effect: "Allow",
            },
        ],
    })),
});

const site = new awsx.apigateway.API("site", {
    routes: [{
        path: "/",
        method: "GET",
        eventHandler: new aws.lambda.Function("get-handler", {
            runtime: aws.lambda.NodeJS10dXRuntime,
            code: new pulumi.asset.AssetArchive({
                ".": new pulumi.asset.FileArchive("handler"),
            }),
            handler: "index.handler",
            role: handlerRole.arn,
            environment: {
                variables: {
                    "HITS_TABLE": hits.name,
                },
            },
        }, { dependsOn: handlerPolicy }),
    }],
});
export const url = site.url;

Notice this definition references the code stored in handler/index.js file through the use of an “asset” — a mechanism for packaging up files and directories for use by your infrastructure. At the end, your API’s base URL will be printed out.