Serverless REST APIs with DynamoDB
With Pulumi, you can combine infrastructure definitions and application code in one program. The @pulumi/cloud library is a set of Pulumi components that provide a higher-level abstraction over AWS. So, instead of provisioning an API Gateway instance, Lambda functions, and setting up IAM roles, you can use cloud.API and define application code at the same time as the infrastructure it depends on.
In this tutorial, we’ll show how to create a simple REST API that counts the number of times a route has been hit. To implement this API, we need a key-value store, an API endpoint, and a Lambda function.
Prerequisites
Create a simple REST API
Run
pulumi new:$ mkdir hello-http && cd hello-http $ pulumi new aws-javascriptReplace the contents of
index.jswith the following:const cloud = require("@pulumi/cloud-aws"); // Create a mapping from 'route' to a count let counterTable = new cloud.Table("counterTable", "route"); // Create an API endpoint let endpoint = new cloud.API("hello-world"); endpoint.get("/{route+}", (req, res) => { let route = req.params["route"]; console.log(`Getting count for '${route}'`); // get previous value and increment // reference outer `counterTable` object counterTable.get({ route }).then(value => { let count = (value && value.count) || 0; counterTable.insert({ route, count: ++count }).then(() => { res.status(200).json({ route, count }); console.log(`Got count ${count} for '${route}'`); }); }); }); exports.endpoint = endpoint.publish().url;The definition for
counterTablestores a counter for each route, using cloud.Table. On AWS, this provisions a DynamoDB instance. To create a new API Gateway instance, we create an instance of cloud.API. New routes can be added to this endpoint using methods likeget,post,putetc.The function passed to
getis the interesting part: this becomes the body of a new AWS Lambda function that is called on a GET request to the API Gateway. The body of this function can use variables defined in the main program, such ascounterTable. This is translated to a lookup on the provisioned DynamoDB instance; there is no need to store its ARN in an environment variable.Add and install the NPM dependencies:
$ npm install --save @pulumi/cloud @pulumi/cloud-awsPreview and deploy changes via
pulumi up:$ pulumi up Previewing update of stack 'hello-http' ... Updating stack 'hello-http' ... info: 14 changes performed: + 14 resources createdView the endpoint URL and curl a few routes:
$ pulumi stack output Current stack outputs (1): OUTPUT VALUE endpoint https://5e8xrktey3.execute-api.us-west-2.amazonaws.com/stage/ $ curl $(pulumi stack output endpoint)/hello {"route":"hello","count":1} $ curl $(pulumi stack output endpoint)/woohoo {"route":"woohoo","count":1}To view the runtime logs of the Lambda function, use the
pulumi logscommand. To get a log stream, usepulumi logs --follow.$ pulumi logs --follow Collecting logs since 2018-05-01T21:22:59.000-07:00. 2018-05-01T22:25:05.040-07:00[ hello-world4fcc7b60] Getting count for 'hello' 2018-05-01T22:25:05.188-07:00[ hello-world4fcc7b60] Got count 1 for 'hello' 2018-05-01T22:25:13.562-07:00[ hello-world4fcc7b60] Getting count for 'woohoo' 2018-05-01T22:25:13.704-07:00[ hello-world4fcc7b60] Got count 1 for 'woohoo'
Clean up
Before moving on, tear down the resources that are part of your stack to avoid incurring any charges.
- Run
pulumi destroyto tear down all resources. You'll be prompted to make sure you really want to delete these resources. A destroy operation may take some time, since Pulumi waits for the resources to finish shutting down before it considers the destroy operation to be complete. - To delete the stack itself, run
pulumi stack rm. Note that this command deletes all deployment history from the Pulumi Console.
Next steps
For an end-to-end application with a frontend, see the URL shortener sample.