From d246434a2ae7366b414b799546676b77430348ec Mon Sep 17 00:00:00 2001 From: jlenon7 Date: Mon, 30 Mar 2026 22:07:13 -0300 Subject: [PATCH] fix: run zod schema before ajv --- package-lock.json | 4 +-- package.json | 2 +- src/router/Route.ts | 2 +- src/router/RouteSchema.ts | 3 ++- tests/unit/router/RouteTest.ts | 49 +++++++++++++++++++++++++++++++++- 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac1482e..108a9d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@athenna/http", - "version": "5.56.0", + "version": "5.57.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@athenna/http", - "version": "5.56.0", + "version": "5.57.0", "license": "MIT", "devDependencies": { "@athenna/artisan": "^5.11.0", diff --git a/package.json b/package.json index a746e91..c391ded 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/http", - "version": "5.56.0", + "version": "5.57.0", "description": "The Athenna Http server. Built on top of fastify.", "license": "MIT", "author": "João Lenon ", diff --git a/src/router/Route.ts b/src/router/Route.ts index e32ff57..dd3b03b 100644 --- a/src/router/Route.ts +++ b/src/router/Route.ts @@ -352,7 +352,7 @@ export class Route extends Macroable { // @ts-ignore this.route.fastify.config.zod = zod - if (Object.keys(zod.response).length) { + if (Object.keys(swaggerSchema).length) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.route.fastify.config.swaggerSchema = swaggerSchema diff --git a/src/router/RouteSchema.ts b/src/router/RouteSchema.ts index fa227cd..ded3cef 100644 --- a/src/router/RouteSchema.ts +++ b/src/router/RouteSchema.ts @@ -49,8 +49,9 @@ export function normalizeRouteSchema(options: RouteSchemaOptions): { } request[key] = options[key] - schema[key] = toJsonSchema(options[key], 'input') swaggerSchema[key] = toJsonSchema(options[key], 'input') + + delete schema[key] }) if (options.response && Is.Object(options.response)) { diff --git a/tests/unit/router/RouteTest.ts b/tests/unit/router/RouteTest.ts index 914e3df..3d5fdbf 100644 --- a/tests/unit/router/RouteTest.ts +++ b/tests/unit/router/RouteTest.ts @@ -11,7 +11,7 @@ import { Config } from '@athenna/config' import { MyMiddleware } from '#tests/fixtures/middlewares/MyMiddleware' import { Test, AfterEach, BeforeEach, type Context, Cleanup } from '@athenna/test' import { HelloController } from '#tests/fixtures/controllers/HelloController' -import { Route, Server, HttpRouteProvider, HttpServerProvider } from '#src' +import { Route, Server, HttpKernel, HttpRouteProvider, HttpServerProvider } from '#src' import { z } from 'zod' export default class RouteTest { @@ -369,6 +369,53 @@ export default class RouteTest { }) } + @Test() + @Cleanup(() => Config.set('openapi.paths', {})) + @Cleanup(() => Config.set('http.logger.ignoreStatuses', [])) + public async shouldUseZodValidationErrorsForInvalidOpenApiRequestSchemas({ assert }: Context) { + Config.set('http.logger.ignoreStatuses', [422]) + + const kernel = new HttpKernel() + await kernel.registerExceptionHandler() + + Config.set('openapi.paths', { + '/avatars': { + post: { + body: z.object({ + name: z.string(), + siteId: z.string(), + slug: z.string() + }) + } + } + }) + + Route.post('avatars', async ctx => { + await ctx.response.status(201).send({ ok: true }) + }) + + Route.register() + + const response = await Server.request({ + path: '/avatars', + method: 'post', + payload: {} + }) + + const body = response.json() + + assert.equal(response.statusCode, 422) + assert.equal(body.code, 'E_VALIDATION_ERROR') + assert.deepEqual( + body.details.map(({ expected, code, path }) => ({ expected, code, path })), + [ + { expected: 'string', code: 'invalid_type', path: ['name'] }, + { expected: 'string', code: 'invalid_type', path: ['siteId'] }, + { expected: 'string', code: 'invalid_type', path: ['slug'] } + ] + ) + } + @Test() public async shouldBeAbleToHideARouteFromTheSwaggerDocumentation({ assert }: Context) { Route.get('test', new HelloController().index)