-
Notifications
You must be signed in to change notification settings - Fork 0
Body parsing
The adapter handles request bodies in two modes, picked automatically per request.
Is ctx.request.body defined?
├─ Yes → use it as-is (body-parser middleware already handled parsing)
└─ No → stream ctx.req, enforce maxBodyBytes, JSON.parse the result
Most Koa apps already have koa-bodyparser or @koa/bodyparser in the middleware chain for other routes. When ctx.request.body !== undefined, the adapter uses that value directly.
import bodyParser from 'koa-bodyparser';
app.use(bodyParser({jsonLimit: '2mb'}));
app.use(mount('/planets', createKoaAdapter(planets)));In this mode the body parser's own size cap applies; the adapter's maxBodyBytes is not consulted. This keeps the body-size policy in one place (the middleware chain), which is usually what you want.
Advantages:
- One place to configure JSON parsing (including non-JSON content types if you need them).
- Other middleware downstream / upstream can inspect / transform the body.
- Consistent
ctx.request.bodyshape across all routes.
If no body parser is installed, the adapter consumes ctx.req (the raw Node IncomingMessage) directly, enforces a byte cap, and JSON.parses the result. Rejected on cap overflow or malformed JSON.
app.use(createKoaAdapter(planets, {maxBodyBytes: 256 * 1024}));Useful when:
- Your app is small enough that a body parser isn't worth pulling in.
- You want per-adapter body-size policy (e.g. a bulk-load endpoint accepts 16 MiB while everything else caps at 64 KiB).
- You want to stay zero-deps beyond what's strictly required.
Default cap: 1048576 (1 MiB).
| Condition | Status | code |
|---|---|---|
Body exceeds maxBodyBytes
|
413 |
PayloadTooLarge |
| Body is not valid JSON | 400 |
BadJsonBody |
| Body is missing required shape | 400 |
BadLoadBody |
BadLoadBody specifically fires on PUT /-load when the body isn't an array.
You can run multiple adapters with different body-cap policies:
app.use(bodyParser({jsonLimit: '256kb'})); // default for most routes
app.use(mount('/planets', createKoaAdapter(planets))); // uses pre-parsed body (256 KiB cap)
app.use(mount('/bulk', createKoaAdapter(bulk, { // but pre-parsed means the bodyparser cap applies —
maxBodyBytes: 16 * 1024 * 1024 // `maxBodyBytes` here is ignored as long as
}))); // bodyParser ran first.If you need per-route body-size policy, mount the bulk adapter before the global body parser, or scope the body parser to specific routes using koa-mount / a router.
// Bulk route streams its own body (no bodyparser upstream → maxBodyBytes kicks in).
app.use(mount('/bulk', createKoaAdapter(bulk, {maxBodyBytes: 16 * 1024 * 1024})));
// Everything else uses the shared bodyparser.
app.use(bodyParser({jsonLimit: '256kb'}));
app.use(mount('/planets', createKoaAdapter(planets)));Some stream-parsers destroy the underlying socket when they see an over-cap body, to prevent the client from uploading more. This adapter does not — Koa still needs the socket alive to write the 413 response. Backpressure plus the aborted flag stop the reader from buffering; the response completes normally; the connection closes via the framework's standard response-end path.
The worst case is a few kernel-buffer bytes per over-sized request — negligible compared to letting the framework respond.
The stream reader is a small utility exposed under dynamodb-toolkit-koa/read-body.js:
import {readJsonBody} from 'dynamodb-toolkit-koa/read-body.js';
// Elsewhere in your Koa app:
const body = await readJsonBody(ctx.req, 1024 * 1024);Normally you won't need this — the adapter handles it internally. It's exported so consumers can reuse the same cap-enforced JSON reader in unrelated routes or when writing their own middleware for edge cases.