The Simple Web Service in AWS CDK

The Simple Web Service is one of the best simple patterns that you will often see in a serverless architecture. Coined by Jeremy Daly – https://www.jeremydaly.com/serverless-microservice-patterns-for-aws/#simplewebservice this stack is a great one to build for a fundamental web application.

The simple web service is made up of three main elements.

  • DynamoDB – our database, for holding dynamic data
  • Lambda – the compute
  • Api Gateway – the network gateway

To create the DynamoDB we do not need many elements. The table is set to pay per request and destroy mode as an example. The partition key will be ‘ID’ and the table name is simpleWebServiceTable.

    // Dynamo Table for returning data
    const dynamoTable = new dynamodb.Table(this, 'simpleWebserviceTable', {
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      partitionKey: { name: 'ID', type: dynamodb.AttributeType.STRING },
      removalPolicy: RemovalPolicy.DESTROY,
      tableName: 'simpleWebServiceTable',
    });

Next, we have the Lambda function, for this we can use the node js function. We will pass an environment variable into the function for the table name, using dynamoTable.tableName. We will also grant the lambda function read access on the dynamo db table.

    // Node Lambda Function
    const lambdaFn = new lambdaNode.NodejsFunction(this, 'LambdaFunctionHandler', {
      runtime: lambda.Runtime.NODEJS_14_X,
      entry: 'lambda/simpleWebservice.ts',
      handler: 'main',
      timeout: Duration.seconds(3),
      bundling: {
        externalModules: [
        ],
        nodeModules: [
        ],
        minify: true
      },
      environment: {
        region: process.env.CDK_DEFAULT_REGION!,
        tableName: dynamoTable.tableName
      }
    });
    // Grant read access to the lambda function on the dynamo table
    dynamoTable.grantReadData(lambdaFn);

The final part of the infrastructure is the AWS API Gateway, for this we are going to use a Rest API. First, we add a versioning resource to the api, this gives us our /v1, next we will add the api itself, the example is get-dynamo-item, this give us the api endpoint /v1/get-dynamo-item. Next add some CORS options to allow all origins, this will open the API up to anyone. Finally, we add the lambda integration. This hooks up the lambda and the api gateways, setting the lambda integration as a GET method.

    const gateway = new apigw.RestApi(this, 'ApiGAteway');
    const version = gateway.root.addResource('v1');
    const api = version.addResource('get-dynamo-item');
    // enable cors
    api.addCorsPreflight({
      allowOrigins: apigw.Cors.ALL_ORIGINS
    });
    // Integration of lambda
    const lambdaIntegration = new apigw.LambdaIntegration(lambdaFn);
    // Add the Lambda as a GET method
    api.addMethod('GET', lambdaIntegration)

Before we deploy the stack, the lambda directory and code must be created. The directory will be ‘lambda’ under the project directory and the code typescript file will be ‘simpleWebservice.ts’. The code for this example is quite simple and has a hard coded lookup on the dynamo table.

The Lambda code will just go and grab an item from dynamo with the ID TEST_ITEM and return it to the user with a 200 response.

import { Context, Callback } from 'aws-lambda';
import {DynamoDB} from 'aws-sdk';

export async function main(event: any, _context: Context, callback: Callback) {

    try {
        // Write a random number to the dynamo table
        const documentClient = new DynamoDB.DocumentClient();
        const params: DynamoDB.DocumentClient.GetItemInput = {
            TableName : process.env.tableName!,
            Key: {
                ID: "TEST_ITEM"
            }
        }
        const data = await documentClient.get(params).promise();
        console.log('data ', data);
        return {
            statusCode: 200,
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(data)
        };
    } catch (error) {
        console.log('error', error)
        return {
            statusCode: 400,
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(error)
        };
    }
}

The stack can now be built and deployed.

Once the stack is deployed, we need to add the example data to the dynamo table for testing. The ID for this needs to be the same as the hard coded get in the lambda function, in this case TEST_ITEM.

To add an item, navigate to the dynamo service, select the table created (called simpleWebserviceTable) and click add item.

You can now hit the API. The base URL can be found as a result of the build process. Added to the end of this url we need to add the resource and the method (/v1/get-dynamo-item).

Using a tool such a postman we can now hit the full url as a GET request and we can see that the item is returned.

Checkout the code on GitHub



Categories: AWS

Tags: , , , , , , , , ,

1 reply

Trackbacks

  1. AWS CDK – API Gateway Custom Domain – greenchapel.dev

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: