Writeup
Serverless Dice Roll API
A dice rolling API on Lambda and API Gateway, deployed from a SAM template.
- AWS Lambda
- API Gateway
- AWS SAM CLI
- CloudFormation
- Node.js
- IaC
- curl
What I built
A small API that rolls dice and returns the result as JSON. There is no server behind it. A Lambda function does the work, API Gateway gives it a public URL, and a SAM template defines the infrastructure as code to deploy and delete both automatically.
A GET to /roll returns a six-sided roll by default, and an optional sides parameter rolls anything from 2 to 100. The function and the template are both in the repo.
The Lambda function
The handler takes the event API Gateway passes it, reads the sides value out of the query string, generates the roll, and returns a status code, headers, and a JSON body. That return shape is what API Gateway converts into the HTTP response.
export const handler = async (event) => {
// API Gateway passes query string params (?sides=20) through the event object.
const params = event.queryStringParameters || {};
// Default to a standard 6-sided die if we don't get a value for sides.
const sides = parseInt(params.sides) || 6;
// A 1-sided die isn't a die, and anything more than 100 sides is just chaos.
// We'll return a client error.
if (sides < 2 || sides > 100) {
return {
statusCode: 400,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
error: "Sides must be between 2 and 100.",
}),
};
}
// Calculate a random integer between 1 and sides.
const result = Math.floor(Math.random() * sides) + 1;
// Lambda functions behind API Gateway return this shape:
// statusCode, headers, and a stringified body
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sides: sides,
roll: result,
}),
};
};API Gateway
A Lambda function has no public address on its own. API Gateway provides one. It terminates TLS, maps the route to the function, passes the request in as an event, and turns the return value back into an HTTP response.
Defining it as code
All of this way deployed using infrastructure as code (IaC). The Lambda function, API Gateway, its IAM permissions, and the API output are all declared in a template file.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Dice Roll API - A serverless API that rolls dice
Resources:
DiceRollFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs24.x
CodeUri: lambda/
Timeout: 5
MemorySize: 128
Events:
RollDice:
Type: Api
Properties:
Path: /roll
Method: get
Outputs:
DiceRollApi:
Description: API Gateway endpoint URL
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/roll"Testing with curl
curl against the endpoint the stack prints as an output confirms the whole path works. A GET returns the JSON roll, and running it a few times returns different numbers, which shows the function is executing per request rather than serving something cached.
$ curl "https://abcxyz.execute-api.us-east-1.amazonaws.com/Prod/roll"
{"sides":6,"roll":4}Rolling other dice
The endpoint takes an optional sides parameter, so /roll?sides=12 returns a number between 1 and 12. It is the one piece of input the API accepts.
Anything outside 2 to 100 comes back as a 400 with a message rather than a roll.
$ curl "https://abcxyz.execute-api.us-east-1.amazonaws.com/Prod/roll?sides=12"
{"sides":12,"roll":9}
$ curl "https://abcxyz.execute-api.us-east-1.amazonaws.com/Prod/roll?sides=1"
{"error":"Sides must be between 2 and 100."}