Start a safe NestJS API
End-to-end tutorial: boot with `createNestApp`, validate DTOs, return prefixed ids, and exercise the documented error shape with `curl`.
At a glance
- Who: Backend developers shipping a first HTTP API with validation, logging, rate limits, and stable error JSON.
- What: End-to-end tutorial: boot with
createNestApp, validate DTOs, return prefixed ids, and exercise the documented error shape withcurl. - Use when: When you want one walkthrough that wires nest, core ids, and the global error filter together.
- Avoid when: When you only need a single piece — use the focused needs (
Bootstrap a Nest app,Return uniform error bodies) instead. - See also: Bootstrap a Nest app, Return uniform error bodies, Generate prefixed unique IDs
Install
pnpm add @zedtech/zedkit-nestLatest: 0.1.2 (via changesets).
Example
import { createNestApp } from "@zedtech/zedkit-nest";
import { newPrefixedId } from "@zedtech/zedkit-core";
const app = await createNestApp({ module: AppModule, envSchema: AppEnv });
await app.listen(3000);
// Walkthrough sources: packages/nest/examples/safe-api (compiled in @zedtech/zedkit-nest tests).Wraps: @nestjs/platform-fastify, nestjs-pino, @nestjs/throttler, class-validator
Prerequisites
- Node.js 22+ and pnpm 9+ (same as the repo root
engines). @zedtech/zedkit-nestand@zedtech/zedkit-corein your app (see Install above).- A
TUTORIAL_TOKENenv var (any non-empty string for local dev).
Walkthrough
The runnable tutorial lives in the monorepo at
packages/nest/examples/safe-api/. CI type-checks those files and boots the
app in tutorial-safe-api.test.ts.
- Env —
TutorialEnvvalidatesTUTORIAL_TOKENand optionalPORT(tutorial.env.ts). - DTO —
CreateItemDtousesclass-validatorso empty names fail before your handler runs (create-item.dto.ts). - Ids —
ItemsServiceassignsnewPrefixedId("item")from@zedtech/zedkit-core(items.service.ts). - Bootstrap — call
createNestApp({ module: TutorialModule, envSchema: TutorialEnv, … })(seetutorial-safe-api.test.ts) with validation, structured logging (auth headers redacted by default), throttling, OpenAPI, and the globalErrorBodyfilter from Return uniform error bodies.
Final result
With the app listening on port 3000:
curl -sS -X POST http://127.0.0.1:3000/items \
-H 'content-type: application/json' \
-d '{"name":"bolt","quantity":2}'You should get 201 JSON with an id like item_01J….
Malformed body (empty name):
curl -sS -X POST http://127.0.0.1:3000/items \
-H 'content-type: application/json' \
-d '{"name":"","quantity":1}'Expect 400 with { "code": "invalid_input", "message": "…", "requestId": "…" }.
That shape is documented once on the error-bodies need page; this tutorial only
exercises it.
Troubleshooting
Boot fails on TUTORIAL_TOKEN — Export a non-empty value:
export TUTORIAL_TOKEN=local-dev.
400 but you expected 201 — Check DTO rules: name must be 1–80 chars,
quantity must be an integer ≥ 0.
429 after many requests — the tutorial test enables throttling (30
requests per minute). Slow down or raise limits in your own bootstrap options.
Ids fail isPrefixedId — Use the same prefix (item) when validating ids
from clients; see
Generate prefixed unique IDs.
Next steps
- Ship request logs without leaking credentials
- Rate limit calls per key when you outgrow global throttling
- Bootstrap a Nest app for every factory option in one place