CRUD API for books backed by MongoDB, with Jest tests, ESLint, and GitHub Actions. Companion code for Building Serverless Node.js Apps on AWS (Cloud Bytes Collection). Canonical copy: this folder inside the serverless-nodejs-dev monorepo — there is no separate Book API tree elsewhere.
Chapter 2 starter: sample-aws-book-api-starter.
- Node.js 22+ (see
.nvmrc) - MongoDB for local runs (Docker recommended)
nvm use
npm ciCopy environment defaults (required for LocalStack vars; DB_URL also has a localhost default in serverless.yml):
cp .env.example .env
# after npm run localstack:setup, merge the printed BOOK_EVENTS_TOPIC_ARN lines into .envStart MongoDB (and optional LocalStack for SNS emulation):
docker compose up -d mongo
# optional, for Chapter 5 local SNS publish:
docker compose up -d localstack
npm run localstack:setup # prints BOOK_EVENTS_TOPIC_ARN for your .envCopy .env.example to .env and fill in values from localstack:setup when using LocalStack.
npm startBase URL: http://localhost:3000/dev
| Method | Path |
|---|---|
| POST | /api/books/createBook |
| GET | /api/books/getBook?id=... or ?isbn=... |
| PUT | /api/books/updateBook |
| DELETE | /api/books/deleteBook?id=... |
A Postman collection is in misc/Books API.postman_collection.json.
With MongoDB running and DB_URL set:
npm run stats:localThis invokes dailyStats locally (cron(0 6 * * ? *) in AWS). Confirm a new document in the stats collection.
LocalStack emulates SNS on port 4566. It does not automatically run notifyNewBook when you publish — that wiring exists only in AWS after deploy. The sample notifies subscribers by logging structured lines (easy to verify in the terminal or CloudWatch). Use this flow locally:
-
Start stack and configure
.envdocker compose up -d mongo localstack npm run localstack:setup # copy the printed lines into .env (AWS_ENDPOINT_URL, BOOK_EVENTS_TOPIC_ARN, etc.) cp .env.example .env # if you have not already
-
SNS publish on create — with
.envloaded,npm startandPOST /api/books/createBookpublishes to LocalStack SNS (confirm with AWS CLI againsthttp://localhost:4566if you like). -
Run the notification handler — add a subscriber in MongoDB (
subscriberscollection), e.g.{ "email": "reader@example.com", "active": true }, then:npm run notify:local
This invokes
notifyNewBookwithmisc/sample-sns-book-created.json. Look for[notifyNewBook]JSON lines in the output.
SNS publish is skipped when BOOK_EVENTS_TOPIC_ARN is unset; CRUD still works.
Or run the full check: npm run verify:local (with npm start in another terminal).
Deploy, add a subscriber, create a book — SNS triggers notifyNewBook automatically. Use sls logs -f notifyNewBook to see the same log lines in CloudWatch.
To send real email later, extend services/notify-subscribers.js (SES, Discord webhooks, etc.) without changing the SNS handler.
Before sls deploy to AWS: comment out or remove AWS_ENDPOINT_URL (and LocalStack keys) from .env so deployed Lambdas do not point at localhost:4566.
Two Bedrock patterns ship in the same project:
| Pattern | Function | Trigger | Purpose |
|---|---|---|---|
| Async enrichment | enrichBook |
SNS book_created |
Generate blurb, save on book (does not slow createBook) |
| Sync assist | suggestBlurb |
POST /api/books/suggestBlurb |
Return a preview blurb before save |
Local default: SKIP_BEDROCK=true in .env returns placeholder text so Jest and verify:local work without model access. For real calls, set SKIP_BEDROCK=false and use inference profile model IDs (e.g. us.anthropic.claude-haiku-4-5-20251001-v1:0 in us-east-1 — bare anthropic.* IDs fail with an on-demand throughput error). Enable the model in the Bedrock console. Keep AWS_ENDPOINT_URL on createBook only so Bedrock does not route to LocalStack.
# with npm start running:
npm run verify:local # includes suggestBlurb + enrichBook (uses last createBook id)
npm run enrich:local # or BOOK_ID=<mongo-id> npm run enrich:localReal Bedrock on your machine (uses ~/.aws or env credentials — not LocalStack test keys):
npm run verify:local # leaves /tmp/create-book-response.json
npm run bedrock:local # real Bedrock via invoke local (no npm start restart needed)bedrock:local uses invoke local --real-aws (not offline HTTP), so SKIP_BEDROCK=true in a running npm start does not matter. For POST /suggestBlurb through offline, set SKIP_BEDROCK=false in .env and restart npm start.
SNS still does not auto-trigger Lambdas under offline. Deploy for full fan-out.
npm testTests use mockingoose and do not require a running database.
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_ACCESS_KEY"
export DB_URL="your-mongodb-connection-string"
npx serverless deploy -v --stage devThe Dockerfile targets a custom base image for full-container workflows. For local development, docker compose up mongo plus npm start on the host is usually enough.
- Lambda runtime:
nodejs22.xinserverless.yml - Serverless Framework 3.40 (no vendor login required)
- npm overrides patch
tar,uuid, andfile-typein Serverless’s dependency tree (see starter README). Avoidnpm audit fix --force(upgrades to v4). npm auditmay list 3 lowaws-sdkv2 advisories with no v2 patch; usenpm audit --audit-level=moderatein CI if needed.npm cimay show deprecation notices from Serverless’s dependency tree; they do not block local development