Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions packages/standard-validator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,57 @@ app.post(
)
```

### Default error response

If validation fails and no hook is provided, the middleware responds with `400 Bad Request`. The body contains the original input (`data`) and the schema library's issues (`error`). For the schema above, sending `{ "name": "a", "age": "x" }` returns:

```json
{
"data": {
"name": "a",
"age": "x"
},
"error": [
{
"expected": "number",
"code": "invalid_type",
"path": ["age"],
"message": "Invalid input: expected number, received string"
}
],
"success": false
}
```

The issue objects in `error` come from the underlying schema library (Zod in this example), so their fields vary by library and are not guaranteed to be stable. Also note that `data` echoes the raw request input back to the client. If that is undesirable (for example, the request may contain sensitive values) or clients parse the error body, define your own format with a hook. For example, an [RFC 9457 Problem Details](https://datatracker.ietf.org/doc/html/rfc9457) body:

```ts
app.post(
'/post',
sValidator('json', schema, (result, c) => {
if (!result.success) {
return c.json(
{
type: 'about:blank',
title: 'Bad Request',
status: 400,
detail: 'Request validation failed.',
errors: result.error.map((issue) => ({
detail: issue.message,
pointer: `#/${(issue.path ?? [])
.map((p) => (typeof p === 'object' ? String(p.key) : String(p)))
.join('/')}`,
})),
},
400,
{ 'content-type': 'application/problem+json' }
)
}
})
//...
)
```

### Headers:

Headers are internally transformed to lower-case in Hono. Hence, you will have to make them lower-cased in validation object.
Expand Down
43 changes: 43 additions & 0 deletions packages/zod-validator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ app.post('/author', zValidator('json', schema), (c) => {
})
```

### Default error response

If validation fails and no hook is provided, the middleware responds with `400 Bad Request` and the serialized Zod `safeParse` result as the body. For the schema above, sending `{ "name": "a", "age": "x" }` returns:

```json
{
"success": false,
"error": {
"name": "ZodError",
"message": "[\n {\n \"expected\": \"number\",\n \"code\": \"invalid_type\",\n \"path\": [\n \"age\"\n ],\n \"message\": \"Invalid input: expected number, received string\"\n }\n]"
}
}
```

Note that `error.message` is a JSON string of Zod's issue array, not a nested object. This is the Zod v4 shape; with Zod v3 the same code serializes the issues inline instead (`"error": { "issues": [...], "name": "ZodError" }`). The format is Zod's own serialization and is not guaranteed to be stable across Zod versions. If clients parse the error body, define your own format with a hook (see below).

Hook:

```ts
Expand All @@ -38,6 +54,33 @@ app.post(
)
```

For example, a hook returning an [RFC 9457 Problem Details](https://datatracker.ietf.org/doc/html/rfc9457) body:

```ts
app.post(
'/post',
zValidator('json', schema, (result, c) => {
if (!result.success) {
return c.json(
{
type: 'about:blank',
title: 'Bad Request',
status: 400,
detail: 'Request validation failed.',
errors: result.error.issues.map((issue) => ({
detail: issue.message,
pointer: `#/${issue.path.join('/')}`,
})),
},
400,
{ 'content-type': 'application/problem+json' }
)
}
})
//...
)
```

Throw Error:

throw a zod validate error instead of directly returning an error response.
Expand Down
Loading