From a217be2481621564d901d813714c71941e8ca8ee Mon Sep 17 00:00:00 2001 From: ambergristle <101149854+ambergristle@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:30:44 +0100 Subject: [PATCH 1/5] docs: add info about `addValidatedData`, and some detail about third-party validators --- docs/guides/validation.md | 52 +++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/docs/guides/validation.md b/docs/guides/validation.md index d07c405a..7b8bd587 100644 --- a/docs/guides/validation.md +++ b/docs/guides/validation.md @@ -30,12 +30,13 @@ app.post( body: body, } }), - //... + // ... ``` Within the handler you can get the validated value with `c.req.valid('form')`. ```ts +// after your middleware... , (c) => { const { body } = c.req.valid('form') // ... do something @@ -162,12 +163,11 @@ app.post( } ``` -## With Zod +## Validator with Zod -You can use [Zod](https://zod.dev), one of third-party validators. -We recommend using a third-party validator. +You can use [Zod](https://zod.dev), or the (typed) validator you prefer, to simplify `validator` callback logic. In essence, this is what our [third-party validators](#with-a-third-party-validator) are doing internally. -Install from the Npm registry. +Install from the NPM registry. ::: code-group @@ -228,9 +228,17 @@ const route = app.post( ) ``` -## Zod Validator Middleware +## Third-party validator middleware +We recommend using one of our [supported third-party validators,](https://hono.dev/docs/middleware/third-party#validators) which internally call `hono/validator`. These libraries make for both a better developer and user experience by simplifying (typed) validation. -You can use the [Zod Validator Middleware](https://github.com/honojs/middleware/tree/main/packages/zod-validator) to make it even easier. +We do our best to support common TypeScript-enabled validators. If you don't see your validator of choice on the list, please [open an issue in the `honojs/middleware` repo.](https://github.com/honojs/middleware/issues) + + +### Zod Validator Middleware + +The [Zod Validator Middleware](https://github.com/honojs/middleware/tree/main/packages/zod-validator) makes it even easier by handling the boilerplate for you! + +Like most of our third-party validator middleware, it takes three parameters: the validation **target**, the validation **callback**, and an optional **hook** for manually handling errors or modifying data after validation. ::: code-group @@ -275,3 +283,33 @@ const route = app.post( } ) ``` + +## How it works + +Validator uses `HonoRequest.addValidatedData` to set valid data in `Context`, making it available in your handler through `c.req.valid`. While the JavaScript implementation might seem straightforward, [`hono/validator` relies on non-trivial generics](https://github.com/honojs/hono/blob/eb86162a9a4472ef86329efe27007caf0afb9284/src/validator/validator.ts) to share validated data types with your handler. + +::: warning +While `c.req.addValidatedData` is a public method, it **must** be used in properly-typed middleware. When used on its own, you will get a type error. + +```typescript +app.get( + "/", + validator('form', /** Your validation hook */), + async (c, next) => { + c.req.addValidatedData('form', { + timestamp: new Date(), + // `addValidatedData` will overwrite target data + ...c.req.valid('form'), + }); + + await next(); + }, + async (c) => { + // Type Error: Argument of type 'string' is not + // assignable to parameter of type 'never' + const body = c.req.valid('form'); + // ... + }, +); +``` +::: From 55bcc1815f928f3e8359cca12821e2b1ba5924d8 Mon Sep 17 00:00:00 2001 From: ambergristle <101149854+ambergristle@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:31:44 +0100 Subject: [PATCH 2/5] docs: add note about proper request validation with hono-openapi --- examples/hono-openapi.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/hono-openapi.md b/examples/hono-openapi.md index 6b818183..ae154c9d 100644 --- a/examples/hono-openapi.md +++ b/examples/hono-openapi.md @@ -42,7 +42,10 @@ const responseSchema = v.string() ### 2. Create Routes -Use `describeRoute` for route documentation and validation: +Use `describeRoute` for route documentation and response validation: + +> [!NOTE] +> Do not use `describeRoute` to define request requirements (e.g., `query` or `json` body). Hono OpenAPI will document those automatically when you use third-party validator middleware. See the example below. ```ts import { Hono } from 'hono' From 97da57c26e426782178057c4d3a4a96d85c37757 Mon Sep 17 00:00:00 2001 From: ambergristle <101149854+ambergristle@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:48:35 +0100 Subject: [PATCH 3/5] docs: simplify example and mention target overwrite explicitly --- docs/guides/validation.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/guides/validation.md b/docs/guides/validation.md index 7b8bd587..ab16a540 100644 --- a/docs/guides/validation.md +++ b/docs/guides/validation.md @@ -294,12 +294,9 @@ While `c.req.addValidatedData` is a public method, it **must** be used in proper ```typescript app.get( "/", - validator('form', /** Your validation hook */), async (c, next) => { c.req.addValidatedData('form', { timestamp: new Date(), - // `addValidatedData` will overwrite target data - ...c.req.valid('form'), }); await next(); @@ -312,4 +309,6 @@ app.get( }, ); ``` + +Also note that the method **overwrites** the target data, if any. If you are validating data with `validator` or third-party validation middleware, you must spread in any of the original data you want to keep. ::: From 90e027ef15e342bdd6090b97a7c5152791959348 Mon Sep 17 00:00:00 2001 From: ambergristle <101149854+ambergristle@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:51:17 +0100 Subject: [PATCH 4/5] chore: remove semis --- docs/guides/validation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/validation.md b/docs/guides/validation.md index ab16a540..9a0b59a4 100644 --- a/docs/guides/validation.md +++ b/docs/guides/validation.md @@ -297,17 +297,17 @@ app.get( async (c, next) => { c.req.addValidatedData('form', { timestamp: new Date(), - }); + }) - await next(); + await next() }, async (c) => { // Type Error: Argument of type 'string' is not // assignable to parameter of type 'never' - const body = c.req.valid('form'); + const body = c.req.valid('form') // ... }, -); +) ``` Also note that the method **overwrites** the target data, if any. If you are validating data with `validator` or third-party validation middleware, you must spread in any of the original data you want to keep. From 3db63d36cb541d4a6b48ad5092e2d339b270002b Mon Sep 17 00:00:00 2001 From: ambergristle <101149854+ambergristle@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:53:06 +0100 Subject: [PATCH 5/5] chore: switch to single-quote --- docs/guides/validation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/validation.md b/docs/guides/validation.md index 9a0b59a4..3ec0670b 100644 --- a/docs/guides/validation.md +++ b/docs/guides/validation.md @@ -293,7 +293,7 @@ While `c.req.addValidatedData` is a public method, it **must** be used in proper ```typescript app.get( - "/", + '/', async (c, next) => { c.req.addValidatedData('form', { timestamp: new Date(),