Relevant source files
The following files were used as context for generating this wiki page:
- src/middleware/ip-restriction/index.ts
- src/validator/validator.ts
- src/utils/jwt/jwt.ts
- src/request.ts
- src/adapter/aws-lambda/handler.ts
- src/validator/index.ts
- src/types.ts
- src/validator/utils.ts
- src/utils/body.ts
- src/middleware/jwt/jwt.ts
- src/utils/url.ts
- src/utils/cookie.ts
- src/middleware/language/language.ts
- src/client/fetch-result-please.ts
- src/context.ts
- src/jsx/utils.ts
- src/jsx/dom/render.ts
- src/middleware/method-override/index.ts
- src/helper/adapter/index.ts
- src/middleware/body-limit/index.ts
- src/client/utils.ts
- src/utils/accept.ts
- src/helper/accepts/accepts.ts
- src/utils/types.ts
- src/utils/basic-auth.ts
- package.json
- src/middleware/pretty-json/index.ts
- src/helper/cookie/index.ts
Overview
Hono provides a flexible validation middleware via the validator helper src/validator/index.ts:6, enabling developers to inspect, parse, and validate incoming request data across multiple targets including JSON payloads, form data, query parameters, path parameters, headers, and cookies src/validator/validator.ts:9-12, 93-159. By integrating tightly with TypeScript type inference, the validation layer ensures that downstream handlers receive correctly typed input parameters while cleanly separating payload normalization and schema execution src/validator/validator.ts:64-82, 162-170. When validation fails, the system generates structured error responses or dispatches exceptions such as HTTPException to handle malformed inputs src/validator/validator.ts:101-102, 123-125.
Sources: src/validator/index.ts:6, src/validator/validator.ts:9-12, src/validator/validator.ts:64-82, src/validator/validator.ts:93-159, src/validator/validator.ts:162-170, src/validator/validator.ts:101-102, src/validator/validator.ts:123-125
Validator middleware signature and targets
Public Middleware API
The core validation mechanism is exposed through the validator helper function, which accepts a validation target and a validation callback function src/validator/validator.ts:46-88. The function signature leverages generic type parameters to enforce strict type safety between the requested validation target, the input data passed to the callback, and the inferred output type available to subsequent handlers src/validator/validator.ts:46-82.
export const validator = <
InputType,
P extends string,
M extends string,
U extends ValidationTargetByMethod<M>,
P2 extends string = P,
// Capture the actual validation function as a type
VF extends (
value: unknown extends InputType ? ValidationTargets[U] : InputType,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
c: Context<any, P2>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => any = (
value: unknown extends InputType ? ValidationTargets[U] : InputType,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
c: Context<any, P2>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => any,
V extends {
in: {
[K in U]: K extends 'json'
? unknown extends InputType
? ExtractValidatorOutput<VF>
: InputType
: InferInput<ExtractValidatorOutput<VF>, K, FormValue>
}
out: { [K in U]: ExtractValidatorOutput<VF> }
} = {
in: {
[K in U]: K extends 'json'
? unknown extends InputType
? ExtractValidatorOutput<VF>
: InputType
: InferInput<ExtractValidatorOutput<VF>, K, FormValue>
}
out: { [K in U]: ExtractValidatorOutput<VF> }
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
E extends Env = any,
>(
target: U,
validationFunc: VF
): MiddlewareHandler<E, P, V, ExtractValidationResponse<VF>> => {Sources: src/validator/validator.ts:46-88
The validation function receives the extracted target value and the execution context src/validator/validator.ts:14-22. It may execute synchronously or asynchronously, returning either the transformed output value, a TypedResponse, or a direct Response instance src/validator/validator.ts:14-22.
export type ValidationFunction<
InputType,
OutputType,
E extends Env = {},
P extends string = string,
> = (
value: InputType,
c: Context<E, P>
) => OutputType | TypedResponse | Promise<OutputType> | Promise<TypedResponse>
Sources: src/validator/validator.ts:14-23
Supported Validation Targets
Hono supports validation across six distinct request input targets src/validator/validator.ts:93-159. The allowed target keys are constrained based on the HTTP method of the route; specifically, get and head methods prohibit body-containing targets (json and form) src/validator/validator.ts:9-12.
type ValidationTargetKeysWithBody = 'form' | 'json'
type ValidationTargetByMethod<M> = M extends 'get' | 'head' // GET and HEAD request must not have a body content.
? Exclude<keyof ValidationTargets, ValidationTargetKeysWithBody>
: keyof ValidationTargets
Sources: src/validator/validator.ts:9-13
| Target Key | Description | Allowed HTTP Methods |
|---|---|---|
json | Request body parsed as JSON | All methods except GET, HEAD |
form | Request body parsed as FormData or URL-encoded fields | All methods except GET, HEAD |
query | URL query string parameters | All methods |
param | Route path parameters | All methods |
header | Request headers | All methods |
cookie | Parsed request cookies | All methods |
Sources: src/validator/validator.ts:9-12, src/validator/validator.ts:93-159
Note
get and head routes restrict ValidationTargetByMethod to exclude body validation targets (form and json), preventing misuse on HTTP verbs that must not carry payload bodies.
Sources: src/validator/validator.ts:10-12
Target extraction and decoding mechanisms
Extraction and Parsing Call Sequences
When the validator middleware processes a cookie target, it dispatches execution through a structured utility chain to extract, parse, trim, and decode cookie values [[src/validator/validator.ts:157-159|src/validator/validator.ts:157-159], [src/helper/cookie/index.ts:27-48|src/helper/cookie/index.ts:27-48], [src/utils/cookie.ts:102-138|src/utils/cookie.ts:102-138], [src/utils/url.ts:81-93|src/utils/url.ts:81-93]].
The first call sequence executes: validator → getCookie → parse → trimCookieWhitespace [[src/validator/validator.ts:157-159|src/validator/validator.ts:157-159], [src/helper/cookie/index.ts:27-48|src/helper/cookie/index.ts:27-48], [src/utils/cookie.ts:102-138|src/utils/cookie.ts:102-138], [src/utils/cookie.ts:79-100|src/utils/cookie.ts:79-100]].
validatorhandles the target switch case forcookie, invokinggetCookie(c)src/validator/validator.ts:157-159. Sources: src/validator/validator.ts:157-159getCookiereads theCookieheader fromc.req.raw.headers, and callsparse(cookie)if no specific key is requested src/helper/cookie/index.ts:27-48. Sources: src/helper/cookie/index.ts:27-48parsesplits the cookie string by;, iterates through each pair, and isolates cookie names and values src/utils/cookie.ts:107-124. Sources: src/utils/cookie.ts:107-124trimCookieWhitespacestrips leading and trailing spaces and tab characters (charCode0x20and0x09) from the parsed cookie name and value substrings [[src/utils/cookie.ts:79-100|src/utils/cookie.ts:79-100], [src/utils/cookie.ts:115|src/utils/cookie.ts:115], [src/utils/cookie.ts:124|src/utils/cookie.ts:124]]. Sources: src/utils/cookie.ts:79-100, src/utils/cookie.ts:115, src/utils/cookie.ts:124
The second call sequence executes: validator → getCookie → parse → tryDecode [[src/validator/validator.ts:157-159|src/validator/validator.ts:157-159], [src/helper/cookie/index.ts:27-48|src/helper/cookie/index.ts:27-48], [src/utils/cookie.ts:102-138|src/utils/cookie.ts:102-138], [src/utils/url.ts:81-93|src/utils/url.ts:81-93]].
validatordispatches togetCookie(c)src/validator/validator.ts:157-159. Sources: src/validator/validator.ts:157-159getCookieretrieves the raw header and invokesparse(cookie)src/helper/cookie/index.ts:27-48. Sources: src/helper/cookie/index.ts:27-48parsevalidates cookie values againstvalidCookieValueRegExand checks for percent encoding src/utils/cookie.ts:128-130. Sources: src/utils/cookie.ts:128-130tryDecodeattempts to decode percent-encoded cookie values usingdecodeURIComponent_, gracefully falling back to partial replacements if malformed sequences are encountered [[src/utils/cookie.ts:130|src/utils/cookie.ts:130], [src/utils/url.ts:81-93|src/utils/url.ts:81-93]]. Sources: src/utils/cookie.ts:130, src/utils/url.ts:81-93
Sources: src/validator/validator.ts:157-159, src/helper/cookie/index.ts:27-48, src/utils/cookie.ts:79-138, src/utils/url.ts:81-93
Target Extraction Implementations
Non-cookie targets extract request data directly from the context request wrapper inside the validator switch statement src/validator/validator.ts:93-160. Query parameters map multi-value fields when query arrays exceed a length of one src/validator/validator.ts:144-150.
case 'query':
value = Object.fromEntries(
Object.entries(c.req.queries()).map(([k, v]) => {
return v.length === 1 ? [k, v[0]] : [k, v]
})
)
break
case 'param':
value = c.req.param() as Record<string, string>
break
case 'header':
value = c.req.header()
break
case 'cookie':
value = getCookie(c)
break
}Sources: src/validator/validator.ts:144-160
Warning
When parsing cookies or query parameters, tryDecode catches decoding exceptions on malformed percent-encoding and decodes valid segments independently rather than failing the entire request src/utils/url.ts:81-93.
Sources: src/utils/url.ts:81-93
Note
getQueryStrings scans the request URL starting at index 8 to locate query parameters, returning an empty string if no query indicator ? is present src/utils/url.ts:136-139.
Sources: src/utils/url.ts:136-139
Payload parsing and form normalization
Processing JSON and Form Payloads
When the validator processes a request with target json or form, it first inspects the Content-Type header against explicit regular expression patterns defined in src/validator/validator.ts. JSON payloads require a content type matching jsonRegex, which supports standard application/json types along with structured syntax suffixes. Form payloads accept content types matching either multipartRegex or urlencodedRegex.
const jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/
const multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/
const urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/Sources: src/validator/validator.ts:24-26
If a request specifies a json target but supplies a malformed body or an unmatching content type, c.req.json() throws an error caught by the validator, which then throws an HTTPException with status code 400 and message 'Malformed JSON in request body'.
try {
value = await c.req.json()
} catch {
const message = 'Malformed JSON in request body'
throw new HTTPException(400, { message })
}Sources: src/validator/validator.ts:98-103
Warning
Form body parsing checks c.req.bodyCache.formData before consuming the stream. If absent, it reads the request as an ArrayBuffer and transforms it via bufferToFormData, caching the resulting FormData instance on the request object.
Sources: src/validator/validator.ts:113-127
FormData Normalization and Key Handling
The form target normalizes raw FormData entries into a structured record using a null-prototype object. During iteration over form fields, keys ending with [] or keys encountering duplicate entries are accumulated into arrays, while single entries populate scalar string or File values.
const form: BodyData<{ all: true }> = Object.create(null)
formData.forEach((value, key) => {
if (key.endsWith('[]')) {
;((form[key] ??= []) as unknown[]).push(value)
} else if (Array.isArray(form[key])) {
;(form[key] as unknown[]).push(value)
} else if (Object.hasOwn(form, key)) {
form[key] = [form[key] as string | File, value]
} else {
form[key] = value
}
})Sources: src/validator/validator.ts:129-140
For broader utility usage outside validation, standalone body parsing via parseBody supports configuration options defined in ParseBodyOptions. These options control array expansion and dot-notation nesting.
| Option | Type | Default | Description |
|---|---|---|---|
all | boolean | false | Determines whether all fields with multiple values should be parsed as arrays |
dot | boolean | false | Determines whether fields with dot notation should be parsed as nested objects |
Sources: src/utils/body.ts:43-74
Caution
Nested form value parsing guards against prototype pollution attacks by explicitly ignoring any key paths containing __proto__.
Sources: src/utils/body.ts:211-213
Schema validation and execution pipeline
Executing Validation Functions
Once the input data is extracted and parsed according to the target type, the validator invokes the provided validationFunc callback with the assembled value and the active Context instance. This function can be synchronous or asynchronous, returning either a transformed output object, a TypedResponse, a raw Response, or a Promise resolving to any of these types.
export type ValidationFunction<
InputType,
OutputType,
E extends Env = {},
P extends string = string,
> = (
value: InputType,
c: Context<E, P>
) => OutputType | TypedResponse | Promise<OutputType> | Promise<TypedResponse>
Sources: src/validator/validator.ts:14-23
const res = await validationFunc(value as never, c as never)
Sources: src/validator/validator.ts:162-163
Note
The validation function signature accepts unknown inputs for JSON targets or infers input properties based on third-party schema definitions when using utility helpers.
Sources: src/validator/validator.ts:53-63
Handling Validation Outputs
After the validation callback completes, the execution pipeline inspects the returned result to determine whether to short-circuit the request or proceed down the middleware chain. If the result is an instance of Response, the validator immediately returns that response, bypassing subsequent middleware handlers.
if (res instanceof Response) {
return res as ExtractValidationResponse<VF>
}Sources: src/validator/validator.ts:164-166
If the validation function returns a transformed output rather than a response object, the validator stores the validated data in the request context using c.req.addValidatedData(target, res) and delegates control to the next handler by calling await next().
c.req.addValidatedData(target, res as never)
return (await next()) as ExtractValidationResponse<VF>Sources: src/validator/validator.ts:168-170
Tip
The ExtractValidatorOutput conditional type helper unwraps promises and strips out Response or TypedResponse union constituents, ensuring type inference correctly isolates the parsed data payload from error responses.
Sources: src/validator/validator.ts:175-185
Error response and exception dispatching
Handling Request Payload Exceptions
When parsing incoming request bodies such as JSON or multipart form data, malformed payloads trigger explicit HTTP exceptions that short-circuit request handling. If JSON parsing fails due to syntax errors, the validator catches the exception and raises an HTTPException with status code 400 and a descriptive error message.
try {
value = await c.req.json()
} catch {
const message = 'Malformed JSON in request body'
throw new HTTPException(400, { message })
}Sources: src/validator/validator.ts:98-103
Similarly, failures encountered during FormData buffer conversion catch the underlying error and construct a 400 status exception combining a base message with the original error details.
try {
const arrayBuffer = await c.req.arrayBuffer()
formData = await bufferToFormData(arrayBuffer, contentType)
c.req.bodyCache.formData = formData
} catch (e) {
let message = 'Malformed FormData request.'
message += e instanceof Error ? ` ${e.message}` : ` ${String(e)}`
throw new HTTPException(400, { message })
}Sources: src/validator/validator.ts:118-126
Caution
Uncaught exceptions during body consumption throw standardized HTTPException instances with HTTP status 400, preventing internal server crashes from malformed client input.
Sources: src/validator/validator.ts:101-102, src/validator/validator.ts:125-125
Custom Response Dispatching
Validation functions can handle failure conditions directly by returning a Response or TypedResponse instance instead of validated data. When the execution pipeline evaluates the result of the validation callback and detects a Response object, it immediately returns that response to the client.
if (res instanceof Response) {
return res as ExtractValidationResponse<VF>
}Sources: src/validator/validator.ts:164-166
This mechanism allows schema validation libraries or custom callback handlers to dispatch validation error codes, custom JSON error payloads, or redirection responses without throwing unhandled exceptions.
Tip
Returning a Response from a validation function bypasses c.req.addValidatedData and immediately halts middleware execution, returning the custom response directly.
Sources: src/validator/validator.ts:164-166
Related
On This Page
OverviewValidator middleware signature and targetsPublic Middleware APISupported Validation TargetsTarget extraction and decoding mechanismsExtraction and Parsing Call SequencesTarget Extraction ImplementationsPayload parsing and form normalizationProcessing JSON and Form PayloadsFormData Normalization and Key HandlingSchema validation and execution pipelineExecuting Validation FunctionsHandling Validation OutputsError response and exception dispatchingHandling Request Payload ExceptionsCustom Response DispatchingRelated