Skip to content

Commit c36ef2e

Browse files
authored
Merge pull request #239 from AthennaIO/develop
feat: support zod transform on schemas
2 parents bffdd43 + 4174fe3 commit c36ef2e

File tree

6 files changed

+88
-10
lines changed

6 files changed

+88
-10
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@athenna/http",
3-
"version": "5.51.0",
3+
"version": "5.52.0",
44
"description": "The Athenna Http server. Built on top of fastify.",
55
"license": "MIT",
66
"author": "João Lenon <lenon@athenna.io>",

src/kernels/HttpKernel.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,14 @@ export class HttpKernel {
8484

8585
if (swaggerPlugin) {
8686
const openapiConfig = Json.omit(Config.get('openapi', {}), ['paths'])
87-
const pluginConfig = Json.omit(Config.get('http.swagger.configurations', {}), ['swagger'])
88-
const swaggerConfig = Config.get('http.swagger.configurations.swagger', {})
87+
const pluginConfig = Json.omit(
88+
Config.get('http.swagger.configurations', {}),
89+
['swagger']
90+
)
91+
const swaggerConfig = Config.get(
92+
'http.swagger.configurations.swagger',
93+
{}
94+
)
8995

9096
await Server.plugin(swaggerPlugin, {
9197
...pluginConfig,

src/router/RouteSchema.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,31 @@ async function parseSchema(schema: ZodAny, data: any) {
145145
}
146146

147147
function toJsonSchema(schema: ZodAny, io: 'input' | 'output') {
148-
const jsonSchemaMethod =
149-
(schema as any)['~standard']?.jsonSchema?.[io] ||
150-
(schema as any).toJSONSchema
148+
const standardJsonSchemaMethod = (schema as any)['~standard']?.jsonSchema?.[
149+
io
150+
]
151+
152+
if (standardJsonSchemaMethod) {
153+
const jsonSchema = standardJsonSchemaMethod({
154+
target: 'draft-07',
155+
libraryOptions: { unrepresentable: 'any' }
156+
})
157+
158+
delete jsonSchema.$schema
159+
160+
return jsonSchema
161+
}
162+
163+
const jsonSchemaMethod = (schema as any).toJSONSchema
151164

152165
if (!jsonSchemaMethod) {
153166
return {}
154167
}
155168

156169
const jsonSchema = jsonSchemaMethod({
170+
io,
157171
target: 'draft-07',
158-
libraryOptions: { unrepresentable: 'any' }
172+
unrepresentable: 'any'
159173
})
160174

161175
delete jsonSchema.$schema

src/server/ServerImpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ export class ServerImpl extends Macroable {
403403

404404
const normalizedSchema = normalizeRouteSchema(automaticSchema)
405405
const currentConfig = { ...(fastifyOptions.config || {}) }
406-
406+
407407
const currentSwaggerSchema =
408408
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
409409
// @ts-ignore

tests/unit/router/RouteTest.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,64 @@ export default class RouteTest {
143143
})
144144
}
145145

146+
@Test()
147+
public async shouldBeAbleToUseZodTransformSchemasWithoutBreakingSwagger({ assert }: Context) {
148+
Route.post('transform', async ctx => {
149+
await ctx.response.status(201).send({
150+
name: ctx.request.input('name')
151+
})
152+
}).schema({
153+
body: z.object({
154+
name: z.string().transform(value => value.toUpperCase())
155+
}),
156+
response: {
157+
201: z.object({
158+
name: z.string().transform(value => value.toUpperCase())
159+
})
160+
}
161+
})
162+
163+
Route.register()
164+
165+
const response = await Server.request({
166+
path: '/transform',
167+
method: 'post',
168+
payload: { name: 'lenon' }
169+
})
170+
171+
assert.equal(response.statusCode, 201)
172+
assert.deepEqual(response.json(), { name: 'LENON' })
173+
174+
const swagger = await Server.getSwagger()
175+
176+
assert.containSubset(swagger.paths['/transform'], {
177+
post: {
178+
responses: {
179+
'201': {
180+
schema: {
181+
type: 'object',
182+
properties: {
183+
name: {}
184+
}
185+
}
186+
}
187+
},
188+
parameters: [
189+
{
190+
in: 'body',
191+
schema: {
192+
type: 'object',
193+
properties: {
194+
name: { type: 'string' }
195+
},
196+
required: ['name']
197+
}
198+
}
199+
]
200+
}
201+
})
202+
}
203+
146204
@Test()
147205
public async shouldBeAbleToUseExplicitZodCoercionForQuerystringAndParams({ assert }: Context) {
148206
Route.get('users/:id', async ctx => {

0 commit comments

Comments
 (0)