feat(ata-validator): add ata validator middleware by mertcanaltin · Pull Request #2171 · honojs/middleware · GitHub
Skip to content

feat(ata-validator): add ata validator middleware - #2171

Open
mertcanaltin wants to merge 2 commits into
honojs:mainfrom
mertcanaltin:feat/ata-validator
Open

mertcanaltin wants to merge 2 commits into
honojs:mainfrom
mertcanaltin:feat/ata-validator

Conversation

@mertcanaltin

Copy link
Copy Markdown

This adds @hono/ata-validator, a validator middleware for ata-validator. I'm the maintainer of ata-validator and will maintain this package.

It follows the same shape as @hono/ajv-validator: ataValidator(target, schema, hook?), c.req.valid(target) typed from the schema, and a 400 with { success: false, errors } when validation fails and no hook returns a response. The failure response is part of the route type, like in the standard-validator.

A couple of differences from the ajv one:

  • the schema is a plain JSON Schema literal written as const and the type is inferred from it, no JSONSchemaType<T> needed
  • you can pass a prepared Validator instead of a schema, which is how you get coerceTypes and useDefaults on query strings; the handler then receives the coerced value
  • where new Function is not available (Cloudflare Workers, strict CSP) ata falls back to its interpreted engine, so the middleware works there without any flag. There is a test for this that replaces globalThis.Function with a throwing one.

Tests cover the same cases as ajv-validator plus the hook receiving the error list, a prepared validator with coercion and defaults, and the no-eval case, with Expect<Equal<...>> checks on the route types.

Ran pnpm typecheck, pnpm test, pnpm lint, pnpm build and deno publish --dry-run in the package, pnpm format at the root.

  • Add tests
  • Run tests
  • pnpm changeset at the top of this repo and push the changeset
  • Follow the contribution guide

@changeset-bot

changeset-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

@mertcanaltin

Copy link
Copy Markdown
Author

Some numbers, since the question with a new validator is usually "why another one". Same 7-field object schema (string, integer, array, nested object with a pattern) for every middleware, in-process app.request, 9 rounds of 4000 requests interleaved, medians. hono 4.13.13, Node 25.2.1, Apple M4 Pro. ajv-validator 0.0.2, zod-validator 0.9.1 with zod 4.6.5, valibot-validator 0.6.1 with valibot 1.5.0, typebox-validator 1.1.0 with typebox 1.3.36, ata-validator 1.47.0. "ata compiled" is the compiled entry of this PR with a module from ata build.

Per request:

validator accepts (µs) rejects (µs)
no validation 3.13 3.17
ata 3.59 4.02
ata compiled 3.64 4.08
ajv 3.68 3.79
zod 5.03 8.87
valibot 4.29 6.86
typebox 3.75 12.71

ata reports every error (two here) in the ajv error shape, keyword, instancePath, schemaPath, params and message; the ajv middleware stops at the first one (bare new Ajv(), no allErrors). The ajv middleware throws on format: 'email' because it does not load ajv-formats, so the schema here has no format.

Same thing with Function replaced by one that throws, which is what Workers and a strict CSP do:

validator accepts (µs) rejects (µs)
ata 4.20 5.31 works
ata compiled 3.73 4.14 works
ajv throws at compile
zod 5.14 9.22 works
valibot 4.48 6.86 works
typebox 9.84 15.08 works

Fresh Node process, from the first import to the first validated response, median of 11:

validator ms
no validation 15.0
ata 23.2
ata compiled 15.9
ajv 36.4
zod 31.6
valibot 17.7
typebox 74.0

Bundle for Workers (esbuild, browser platform, es2022, minified, gzip), a Hono app with one validated route:

app gzip
no validation 7.7 KB
ata compiled 9.6 KB
ata 136.4 KB
ajv 46.6 KB
zod 101.2 KB
valibot 10.0 KB
typebox 50.2 KB

The runtime entry carries the whole engine, because a schema that arrives at run time can use any keyword; that is the 136 KB row, and it is why the PR has the compiled entry. A module from ata build imports nothing and the entry imports nothing, so the validated route costs 2 KB over an app with no validation and starts within a millisecond of it, while still being plain JSON Schema with the types generated next to it.

Happy to share the harness, it's four small files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant