Request
Body
assertBodySize(event, limit)
Asserts that request body size is within the specified limit.
If body size exceeds the limit, throws a 413 Request Entity Too Large response error.
Example:
app.get("/", async (event) => {
await assertBodySize(event, 10 * 1024 * 1024); // 10MB
const data = await event.req.formData();
});
readBody(event, options?)
Reads request body and tries to parse using JSON.parse or URLSearchParams.
By default the body is parsed as JSON (falling back to URL-encoded parsing when the Content-Type is application/x-www-form-urlencoded). Other body types, such as multipart/form-data, must be opted into explicitly via options.type and are never auto-detected from the request headers.
Example:
app.post("/", async (event) => {
const body = await readBody(event);
});
Example:
app.post("/upload", async (event) => {
const body = await readBody(event, { type: "formData" });
});
readValidatedBody(event, validate)
Tries to read the request body via readBody, then uses the provided validation schema or function and either throws a validation error or returns the result.
You can use a simple function to validate the body or use a Standard-Schema compatible library like zod to define a schema.
Example:
function validateBody(body: any) {
return typeof body === "object" && body !== null;
}
app.post("/", async (event) => {
const body = await readValidatedBody(event, validateBody);
});
Example:
import { z } from "zod";
const objectSchema = z.object({
name: z.string().min(3).max(20),
age: z.number({ coerce: true }).positive().int(),
});
app.post("/", async (event) => {
const body = await readValidatedBody(event, objectSchema);
});
Example:
import * as v from "valibot";
app.post("/", async (event) => {
const body = await readValidatedBody(
event,
v.object({
name: v.pipe(v.string(), v.minLength(3), v.maxLength(20)),
age: v.pipe(v.number(), v.integer(), v.minValue(1)),
}),
{
onError: ({ issues }) => ({
statusText: "Custom validation error",
message: v.summarize(issues),
}),
},
);
});
Query (HTTP QUERY method)
Utilities for the HTTP QUERY method (RFC 10008): advertise the query formats a resource accepts and validate the request Content-Type.
appendAcceptQuery(event, mediaTypes)
Advertise the query formats a resource accepts by setting the Accept-Query response header (RFC 10008, HTTP QUERY method).
The media types are serialized as a Structured Fields List: the base media type becomes a token and any ;name=value parameters are emitted with their values as quoted strings.
Example:
app.query("/search", (event) => {
appendAcceptQuery(event, ["application/sql;charset=UTF-8", "application/jsonpath"]);
// Accept-Query: application/sql;charset="UTF-8", application/jsonpath
return handleSearch(event);
});
defineQueryHandler()
Define an HTTP QUERY method handler (RFC 10008) with the accepted query formats enforced and advertised.
The formats array lists the accepted query media types (wildcards like application/* are supported). On every response — including error responses — they are advertised via the Accept-Query header. The handler receives the matched request media type as format (lower-cased, without parameters) and reads the query from the request body as usual.
Requests are rejected with 405 (non-QUERY method), 400 (missing Content-Type), 422 (malformed Content-Type), or 415 (unsupported query format).
Example:
app.query("/books", defineQueryHandler({
formats: ["application/sql", "application/jsonpath"],
handler: async (event, { format }) => {
const query = await readBody(event, { type: "text" });
return runQuery(format, query);
},
}));
With the `get` option, the same handler also serves an equivalent,
HTTP-cacheable GET (RFC 10008 §2.3): the query is read from the given URL
search param (and the format from `?format=`), the handler receives the
resolved `query` in its context on both paths, and successful QUERY
responses advertise the equivalent GET via `Content-Location` — preserving
existing search params, and skipped when the URL would exceed 2048 chars.
Register the handler for both methods; `HEAD` is served automatically via
the GET route. GET-path rejections are `400`.
Example:
const searchBooks = defineQueryHandler({
formats: ["application/sql", "application/jsonpath"],
get: "q",
handler: (event, { format, query }) => runQuery(format, query),
});
app.get("/books", searchBooks).query("/books", searchBooks);
// QUERY /books -> 200 + Content-Location: /books?q=<query>&format=<format>
// GET /books?q=... -> same result, ordinary HTTP caching applies
requireContentType(event, acceptedTypes)
Assert that the request Content-Type is present and one of the accepted media types, following the requirements of RFC 10008 for the HTTP QUERY method.
Throws:
400 Bad Requestif theContent-Typeheader is missing.422 Unprocessable Contentif theContent-Typeheader is malformed.415 Unsupported Media Typeif the media type is not accepted.
Accepted types may use wildcards: * / */* match anything and type/* matches any subtype of type.
Example:
app.query("/search", async (event) => {
requireContentType(event, ["application/sql", "application/jsonpath"]);
const body = await readBody(event, { type: "text" });
// ...
});
Cache
handleCacheHeaders(event, opts)
Check request caching headers (If-Modified-Since) and add caching headers (Last-Modified, Cache-Control) Note: public cache control will be added by default
More Request Utils
assertMethod(event, expected, allowHead?)
Asserts that the incoming request method is of the expected type using isMethod.
If the method is not allowed, it will throw a 405 error and include an Allow response header listing the permitted methods, as required by RFC 9110.
If allowHead is true, it will allow HEAD requests to pass if the expected method is GET.
Example:
app.get("/", (event) => {
assertMethod(event, "GET");
// Handle GET request, otherwise throw 405 error
});
getQuery(event)
Get parsed query string object from the request URL.
Example:
app.get("/", (event) => {
const query = getQuery(event); // { key: "value", key2: ["value1", "value2"] }
});
getRequestHost(event, opts: { xForwardedHost? })
Get the request hostname.
If xForwardedHost is true, it will use the x-forwarded-host header if it exists.
If no host header is found, it will return an empty string.
Example:
app.get("/", (event) => {
const host = getRequestHost(event); // "example.com"
});
getRequestIP(event)
Try to get the client IP address from the incoming request.
If xForwardedFor is true, it will use the x-forwarded-for header if it exists.
If IP cannot be determined, it will default to undefined.
Example:
app.get("/", (event) => {
const ip = getRequestIP(event); // "192.0.2.0"
});
getRequestProtocol(event, opts: { xForwardedProto? })
Get the request protocol.
If x-forwarded-proto header is set to "https", it will return "https". If the header contains a comma-separated list of protocols, the first entry is used. You can disable this behavior by setting xForwardedProto to false.
If protocol cannot be determined, it will default to "http".
Example:
app.get("/", (event) => {
const protocol = getRequestProtocol(event); // "https"
});
getRequestURL(event, opts: { xForwardedHost?, xForwardedProto? })
Generated the full incoming request URL.
If xForwardedHost is true, it will use the x-forwarded-host header if it exists.
If xForwardedProto is false, it will not use the x-forwarded-proto header.
Example:
app.get("/", (event) => {
const url = getRequestURL(event); // "https://example.com/path"
});
getRouterParam(event, name, opts: { decode? })
Get a matched route param by name.
If decode option is true, it will decode the matched route param (like decodeURIComponent), except encoded path separators (%2f, %5c) are kept encoded so decoding can never reintroduce a / or \ the router never matched.
Example:
app.get("/", (event) => {
const param = getRouterParam(event, "key");
});
getRouterParams(event, opts: { decode? })
Get matched route params.
If decode option is true, it will decode the matched route params (like decodeURIComponent), except encoded path separators (%2f, %5c) are kept encoded so decoding can never reintroduce a / or \ the router never matched.
Example:
app.get("/", (event) => {
const params = getRouterParams(event); // { key: "value" }
});
getValidatedQuery(event, validate)
Get the query param from the request URL validated with validate function.
You can use a simple function to validate the query object or use a Standard-Schema compatible library like zod to define a schema.
Example:
app.get("/", async (event) => {
const query = await getValidatedQuery(event, (data) => {
return "key" in data && typeof data.key === "string";
});
});
Example:
import { z } from "zod";
app.get("/", async (event) => {
const query = await getValidatedQuery(
event,
z.object({
key: z.string(),
}),
);
});
Example:
import * as v from "valibot";
app.get("/", async (event) => {
const params = await getValidatedQuery(
event,
v.object({
key: v.string(),
}),
{
onError: ({ issues }) => ({
statusText: "Custom validation error",
message: v.summarize(issues),
}),
},
);
});
getValidatedRouterParams(event, validate)
Get matched route params and validate with validate function.
If decode option is true, it will decode the matched route params (like decodeURIComponent), except encoded path separators (%2f, %5c) are kept encoded so decoding can never reintroduce a / or \ the router never matched.
You can use a simple function to validate the params object or use a Standard-Schema compatible library like zod to define a schema.
Example:
app.get("/:key", async (event) => {
const params = await getValidatedRouterParams(event, (data) => {
return "key" in data && typeof data.key === "string";
});
});
Example:
import { z } from "zod";
app.get("/:key", async (event) => {
const params = await getValidatedRouterParams(
event,
z.object({
key: z.string(),
}),
);
});
Example:
import * as v from "valibot";
app.get("/:key", async (event) => {
const params = await getValidatedRouterParams(
event,
v.object({
key: v.pipe(v.string(), v.picklist(["route-1", "route-2", "route-3"])),
}),
{
decode: true,
onError: ({ issues }) => ({
statusText: "Custom validation error",
message: v.summarize(issues),
}),
},
);
});
isMethod(event, expected, allowHead?)
Checks if the incoming request method is of the expected type.
If allowHead is true, it will allow HEAD requests to pass if the expected method is GET.
Example:
app.get("/", (event) => {
if (isMethod(event, "GET")) {
// Handle GET request
} else if (isMethod(event, ["POST", "PUT"])) {
// Handle POST or PUT request
}
});
requestWithBaseURL(req, base)
Create a lightweight request proxy with the base path stripped from the URL pathname.
requestWithURL(req, url)
Create a lightweight request proxy that overrides only the URL.
Avoids cloning the original request (no new Request() allocation).
toRequest(input, options?)
Convert input into a web Request.
If input is a relative URL, it will be normalized into a full path based on headers.
If input is already a Request and no options are provided, it will be returned as-is.
getRequestFingerprint(event, opts)
Get a unique fingerprint for the incoming request.