Episode 2 — React Frontend Architecture NextJS / 2.20 — Building APIs with NextJS
2.20 — Exercise Questions: Building APIs with Next.js
Build these in a small App Router project (or sketch requests with
curl/ REST Client first).
A. File conventions (2.20.a)
-
Create
GET /api/pingreturning{ "data": { "pong": true } }. -
Add
app/api/items/[id]/route.tssupportingGETby id. Return 404 with your standard error JSON when missing. -
Explain what happens if a client calls
POST /api/pingwhen you only exportedGET.
B. HTTP verbs (2.20.b)
-
Implement
POST /api/items— validates{ "name": string }with Zod, returns 201 +Locationheader. -
Implement
PUT /api/items/[id]full replace vsPATCHpartial update — document the behavioral difference in comments. -
Implement
DELETE /api/items/[id]returning 204 on success.
C. Database (2.20.c)
-
Wire
GET /api/itemsto your database through alistItemsservice function (no raw queries inroute.ts). -
Add a unique index on
emailand map duplicate insert to 409 with codeEMAIL_IN_USE.
D. Errors & consistency (2.20.d)
-
Introduce a shared
jsonError(code, message, status, details?)helper and use it in three different handlers. -
Add
X-Request-Idin middleware (or inside handlers) and include it in every JSONmetablock.
E. Cross-cutting
-
Write
curlexamples for GET list (with query), POST create, and DELETE. -
Compare your Route Handler for “create comment” with a Server Action version (2.21) — one paragraph on when you would keep only the Route Handler.
F. Stretch
-
Implement OPTIONS + CORS headers for a trusted origin calling your API from the browser.
-
Load-test locally (e.g.
autocannon) and observe DB connection behavior — write three bullet takeaways.
Answers & guidance (self-check)
1. GET /api/ping
app/api/ping/route.tsexportingGETreturningNextResponse.json({ data: { pong: true } }).
2. GET by id + 404 JSON
- Service
getItem(id)returnsnull→NextResponse.json({ error: { code: 'NOT_FOUND', message: 'Item not found' } }, { status: 404 }).
3. POST with only GET
- Next returns 405 Method Not Allowed (default) because no
POSTexport exists for that segment.
4. POST create
- Validate body with Zod; on success
return NextResponse.json(entity, { status: 201, headers: { Location:/api/items/${entity.id}} }).
5. PUT vs PATCH
- Document:
PUTreplaces entire record (missing fields cleared or rejected);PATCHmerges provided fields only.
6. DELETE 204
return new NextResponse(null, { status: 204 })— no JSON body on 204.
7. Service layer
route.tsshould be thin: parse request → calllistItems→ map to DTO → return response. Keeps tests fast and DB logic reusable from Server Actions too.
8. Unique email → 409
- Catch DB unique violation (Prisma
P2002etc.) and map to{ error: { code: 'EMAIL_IN_USE' } }with 409.
9. jsonError helper
- Centralizes shape
{ error: { code, message, details? } }; ensures you never leak stack traces to clients.
10. Request id
- Generate UUID per request; set response header; include in
meta.requestIdfor correlating client reports with server logs.
11. curl examples (sketch)
curl -sS 'http://localhost:3000/api/items?page=2'curl -sS -X POST http://localhost:3000/api/items -H 'Content-Type: application/json' -d '{"name":"Tea"}' -icurl -sS -X DELETE http://localhost:3000/api/items/123 -i
12. Route Handler only
- Keep when you need public HTTP for mobile/partners, webhooks, OpenAPI docs, unusual streaming/status semantics, or cross-origin clients not using Next’s action protocol.
13. CORS + OPTIONS
export function OPTIONS()returnsNextResponsewithAccess-Control-Allow-Origin: https://trusted.example(not*if cookies), allow methods/headers you need; mirror on actual responses or use middleware helper.
14. Load test takeaways (examples)
- Connection pool exhaustion under concurrency; need for PgBouncer/Accelerate; p95 latency spikes when sequential DB in hot handlers.