SAM 24 adds 13 AWS 24 ::Serverless::* types. The ones BookNest-sized applications use most:
| SAM type | Expands into |
|---|---|
| Function | Lambda 24 function, execution role, event sources and permissions |
| Api, HttpApi, WebSocketApi | API Gateway 24 REST, HTTP or WebSocket API, stage, deployment |
| SimpleTable | DynamoDB 24 table with one primary key, on-demand billing |
| LayerVersion | Lambda layer version |
| StateMachine | Step Functions 24 state machine and its role |
| Connector | IAM policies that let one resource call another |
| Application | A nested stack from the Serverless Application Repository |
The others are GraphQLApi (AppSync 24 ), CapacityProvider, MicrovmImage and NetworkConnector. A Globals section sets defaults for every function, and policy templates such as DynamoDBReadPolicy generate least-privilege statements for a named table:
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: BookNest's catalog API as a SAM application
Globals:
Function:
Runtime: nodejs24.x
MemorySize: 256
Timeout: 10
Resources:
BooksTable:
Type: AWS::Serverless::SimpleTable
Properties:
TableName: booknest-sam-books
PrimaryKey: {Name: id, Type: Number}
BooksFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: books.handler
Environment:
Variables:
BOOKS_TABLE: !Ref BooksTable
DYNAMODB_ENDPOINT: ""
Policies:
- DynamoDBReadPolicy: {TableName: !Ref BooksTable}
Events:
ListBooks: {Type: Api, Properties: {Path: /books, Method: get}}
GetBook: {Type: Api, Properties: {Path: "/books/{id}", Method: get}}
Outputs:
BooksApi:
Value: !Sub >-
https://${ServerlessRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/Prodimport { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand, ScanCommand } from "@aws-sdk/lib-dynamodb";
const endpoint = process.env.DYNAMODB_ENDPOINT || undefined;
const db = DynamoDBDocumentClient.from(new DynamoDBClient({ endpoint }));
const TableName = process.env.BOOKS_TABLE;
const json = (statusCode, body) => ({
statusCode, headers: { "content-type": "application/json" }, body: JSON.stringify(body),
});
export const handler = async (event) => {
const id = event.pathParameters?.id;
if (id === undefined) {
const { Items } = await db.send(new ScanCommand({ TableName }));
const books = Items.map(({ id, title, price }) => ({ id, title, price }));
return json(200, books.sort((a, b) => a.id - b.id));
}
if (!/^\d+$/.test(id)) return json(400, { error: "id must be an integer" });
const { Item } = await db.send(new GetCommand({ TableName, Key: { id: Number(id) } }));
return Item ? json(200, Item) : json(404, { error: "book not found" });
};DYNAMODB_ENDPOINT is empty in the cloud, where the SDK finds DynamoDB itself (LocalStack 63,725 injects its endpoint into the functions it runs), and is overridden only for local runs. src/package.json declares the module type; the runtime already provides the AWS SDK.