Can multiple validator("query", ...) middlewares be combined? #4613
Replies: 2 comments
-
|
Each SolutionsOption 1: Use a single combined validator (Recommended) import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
const querySchema = z.object({
limit: z.coerce.number().optional(),
excluded: z.string().optional(),
// ... all your query params
})
app.get("/", zValidator("query", querySchema), (c) => {
const { limit, excluded } = c.req.valid("query")
return c.text("ok")
})Option 2: Store results in context variables const limitValidator = validator("query", (value, c) => {
const limit = /* validate */
c.set("limit", limit)
return { limit }
})
const excludedValidator = validator("query", (value, c) => {
const excluded = /* validate */
c.set("excluded", excluded)
return { excluded }
})
app.get("/", limitValidator, excludedValidator, (c) => {
const limit = c.get("limit")
const excluded = c.get("excluded")
// or access the last validator's result
// const { excluded } = c.req.valid("query")
return c.text("ok")
})Option 3: Compose validators manually const composeValidators = (...validators) => {
return validator("query", (value, c) => {
let result = {}
for (const v of validators) {
const validated = v(value, c)
result = { ...result, ...validated }
}
return result
})
}
app.get("/", composeValidators(limitValidatorFn, excludedValidatorFn), (c) => {
const { limit, excluded } = c.req.valid("query")
return c.text("ok")
})RecommendationUse Option 1 with a single Zod schema - it's cleaner and gives you full type safety. If this solves your problem, please mark it as the answer! ✅ |
Beta Was this translation helpful? Give feedback.
-
Answer: Combining Hono ValidatorsEach Solution 1: Single combined validator (Recommended)import { zValidator } from "@hono/zod-validator";
import { z } from "zod";
const querySchema = z.object({
limit: z.coerce.number().optional(),
excluded: z.string().optional(),
});
app.get("/", zValidator("query", querySchema), (c) => {
const { limit, excluded } = c.req.valid("query");
return c.json({ limit, excluded });
});Solution 2: Merge schemasconst limitSchema = z.object({ limit: z.coerce.number() });
const excludedSchema = z.object({ excluded: z.string() });
const combinedSchema = limitSchema.merge(excludedSchema);
app.get("/", zValidator("query", combinedSchema), handler);Solution 3: Custom merging middlewareconst mergeValidators = (...validators) => {
return async (c, next) => {
let merged = {};
for (const v of validators) {
await v(c, async () => {});
merged = { ...merged, ...c.req.valid("query") };
}
c.set("mergedQuery", merged);
await next();
};
};
app.get("/", mergeValidators(limitValidator, excludedValidator), (c) => {
const { limit, excluded } = c.get("mergedQuery");
});RecommendationUse Solution 1 or 2 - single schema is cleaner and type-safe. Split validators are better stored as reusable schema fragments that you merge at the route level. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm using
validatorand I want to split query validation into multiple middlewares, but still access a single merged result viac.req.valid("query").Example:
Is
validated("query")supposed to contain results from all query validators, or does eachvalidator("query")overwrite the previous one? If overwriting is expected, what's the recommended way to "compose" query validators (merge results, or use a single validator/schema)?Beta Was this translation helpful? Give feedback.
All reactions