@nextrush/body-parser
Parse JSON, URL-encoded, text, and raw request bodies with size limits and security protections.
Parse incoming request bodies before your handlers process them.
HTTP request bodies arrive as raw byte streams. This middleware reads, validates, and parses them into usable JavaScript values — handling JSON, URL-encoded forms, plain text, and raw binary data. Built-in protections guard against oversized payloads, prototype pollution, and malformed input.
Default Behavior
With default options, bodyParser() parses JSON and URL-encoded request bodies. Text and raw binary parsing stay off until you enable them.
Bodyless HTTP methods (GET, HEAD, DELETE, OPTIONS) are skipped automatically. If the body has already been parsed by another middleware, parsing is skipped.
Installation
$ pnpm add @nextrush/body-parser
Minimal Usage
import { createApp } from '@nextrush/core';
import { bodyParser } from '@nextrush/body-parser';
const app = createApp();
// Parses JSON and URL-encoded bodies by default
app.use(bodyParser());
app.use(async (ctx) => {
ctx.json({ received: ctx.body });
});Individual Parsers
Use individual parsers when you need to handle specific content types only.
import { json } from '@nextrush/body-parser';
app.use(json());
// Parses: application/jsonimport { urlencoded } from '@nextrush/body-parser';
app.use(urlencoded());
// Parses: application/x-www-form-urlencodedimport { text } from '@nextrush/body-parser';
app.use(text());
// Parses: text/plainimport { raw } from '@nextrush/body-parser';
app.use(raw());
// Parses: application/octet-streamConfiguration Options
bodyParser(options?)
Combined parser that routes to the appropriate parser based on Content-Type.
function bodyParser(options?: BodyParserOptions): BodyParserMiddleware;Options
| Property | Type | Description |
|---|---|---|
json | JsonOptions | false= {} | JSON parser options, or false to disable |
urlencoded | UrlEncodedOptions | false= {} | URL-encoded parser options, or false to disable |
text | TextOptions | false= undefined | Text parser options — disabled by default |
raw | RawOptions | false= undefined | Raw parser options — disabled by default |
JSON and URL-encoded parsing are enabled by default. To enable text or raw parsing, provide an options object (even {} activates them). To disable a parser, set it to false.
app.use(
bodyParser({
json: { limit: '10mb', strict: true },
urlencoded: { extended: true, depth: 5 },
text: {}, // Enable text parsing with defaults
raw: false, // Explicitly disable raw parsing
})
);Multipart requests (multipart/form-data) throw an UNSUPPORTED_CONTENT_TYPE error with a hint to use a dedicated multipart parser.
json(options?)
function json(options?: JsonOptions): BodyParserMiddleware;JSON Options
| Property | Type | Description |
|---|---|---|
limit | number | string= '1mb' (1,048,576 bytes) | Maximum body size in bytes or as a string with unit |
strict | boolean= true | Accept only objects and arrays — rejects primitives |
type | string | string[]= ['application/json'] | Content-Type(s) to match |
rawBody | boolean= false | Store raw Buffer on ctx.rawBody |
reviver? | JsonReviver | Custom reviver passed to JSON.parse() |
maxDepth? | number | Maximum JSON nesting depth — rejects deeper payloads after parsing |
verify? | VerifyCallback | Callback invoked with raw buffer before parsing — throw to reject |
urlencoded(options?)
function urlencoded(options?: UrlEncodedOptions): BodyParserMiddleware;URL-Encoded Options
| Property | Type | Description |
|---|---|---|
limit | number | string= '100kb' (102,400 bytes) | Maximum body size in bytes or as a string with unit |
extended | boolean= true | Enable nested object parsing (e.g. user[name]=John) |
parameterLimit | number= 1000 | Maximum number of parameters accepted |
depth | number= 20 | Maximum nesting depth for extended parsing |
type | string | string[]= ['application/x-www-form-urlencoded'] | Content-Type(s) to match |
rawBody | boolean= false | Store raw Buffer on ctx.rawBody |
verify? | VerifyCallback | Callback invoked with raw buffer before parsing — throw to reject |
text(options?)
function text(options?: TextOptions): BodyParserMiddleware;Text Options
| Property | Type | Description |
|---|---|---|
limit | number | string= '100kb' (102,400 bytes) | Maximum body size in bytes or as a string with unit |
defaultCharset | SupportedCharset= 'utf-8' | Fallback charset when not specified in Content-Type |
type | string | string[]= ['text/plain'] | Content-Type(s) to match |
rawBody | boolean= false | Store raw Buffer on ctx.rawBody |
verify? | VerifyCallback | Callback invoked with raw buffer before parsing — throw to reject |
raw(options?)
function raw(options?: RawOptions): BodyParserMiddleware;Raw Options
| Property | Type | Description |
|---|---|---|
limit | number | string= '100kb' (102,400 bytes) | Maximum body size in bytes or as a string with unit |
type | string | string[]= ['application/octet-stream'] | Content-Type(s) to match |
verify? | VerifyCallback | Callback invoked with raw buffer before parsing — throw to reject |
Integration Example
An API server with error handling, JSON parsing, and webhook signature verification:
import { createApp } from '@nextrush/core';
import { json, BodyParserError } from '@nextrush/body-parser';
import { createHmac } from 'node:crypto';
const app = createApp();
// Error handler (register before body parser)
app.use(async (ctx, next) => {
try {
await next();
} catch (error) {
if (error instanceof BodyParserError) {
ctx.status = error.status;
ctx.json({ error: error.message, code: error.code });
return;
}
throw error;
}
});
// Parse JSON with raw body access for webhook verification
app.use(json({ limit: '1mb', rawBody: true }));
app.post('/webhook', async (ctx) => {
const signature = ctx.headers['x-signature'] as string;
const rawBody = ctx.rawBody as Buffer;
const expected = createHmac('sha256', process.env.WEBHOOK_SECRET!).update(rawBody).digest('hex');
if (signature !== expected) {
ctx.status = 401;
ctx.json({ error: 'Invalid signature' });
return;
}
ctx.json({ ok: true });
});Error Handling
All parsers throw BodyParserError on failure. Each error includes status (HTTP status code), code (machine-readable string), and expose (whether the message is safe for clients).
import { BodyParserError } from '@nextrush/body-parser';
app.use(async (ctx, next) => {
try {
await next();
} catch (error) {
if (error instanceof BodyParserError) {
ctx.status = error.status;
ctx.json({ error: error.message, code: error.code });
return;
}
throw error;
}
});Error Codes
| Code | Status | Cause |
|---|---|---|
ENTITY_TOO_LARGE | 413 | Body exceeds configured size limit |
INVALID_JSON | 400 | JSON syntax error |
STRICT_MODE_VIOLATION | 400 | JSON value is a primitive in strict mode |
JSON_DEPTH_EXCEEDED | 400 | JSON nesting depth exceeds maxDepth |
INVALID_URLENCODED | 400 | Malformed URL-encoded data |
TOO_MANY_PARAMETERS | 413 | URL-encoded parameter count exceeds parameterLimit |
DEPTH_EXCEEDED | 400 | URL-encoded nesting exceeds depth limit |
INVALID_PARAMETER | 400 | Prototype pollution attempt (__proto__, constructor, prototype) |
UNSUPPORTED_CHARSET | 415 | Charset in Content-Type is not supported |
UNSUPPORTED_CONTENT_TYPE | 415 | Content type not handled (e.g. multipart/form-data) |
BODY_READ_ERROR | 400 | Error reading request stream |
REQUEST_CLOSED | 400 | Connection closed before body was received |
REQUEST_ABORTED | 400 | Client aborted the request |
Common Mistakes
bodyParser() does not parse text or raw bodies by default. Pass text: {} or raw: {} in
the options to enable them.
- Using
bodyParser()and expecting text/raw parsing — these are disabled by default. Enable them explicitly:bodyParser({ text: {}, raw: {} }). - Setting the wrong size limit units — limits accept
'b','kb','mb','gb'. A bare number is treated as bytes. - Expecting multipart form uploads to work — this parser does not handle
multipart/form-data. Use a dedicated multipart parser. - Forgetting error handling — without an error-catching middleware upstream,
BodyParserErrorwill crash your app.
Troubleshooting
ctx.body is undefined after parsing:
- Verify the request has a matching
Content-Typeheader. - Check the HTTP method —
GET,HEAD,DELETE, andOPTIONSrequests are skipped. - Confirm no earlier middleware has already set
ctx.body.
413 errors on valid payloads:
- Increase the
limitoption. The JSON default is1mb; URL-encoded, text, and raw default to100kb.
UNSUPPORTED_CONTENT_TYPE error:
- The combined parser throws this for
multipart/form-datarequests. Use a separate multipart parser.
Related
- Middleware Overview — All middleware packages
- @nextrush/cors — CORS handling
- @nextrush/rate-limit — Rate limiting