Skip to content

Commit 4665e0f

Browse files
robhungRobert Hung
andauthored
fix(openapi): correctly add style: deepObject for optional objects (#482)
Co-authored-by: Robert Hung <robert@dovetailapp.com>
1 parent 813de29 commit 4665e0f

2 files changed

Lines changed: 79 additions & 2 deletions

File tree

libs/ts-rest/open-api/src/lib/ts-rest-open-api.spec.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,75 @@ describe('ts-rest-open-api', () => {
619619
});
620620
});
621621

622+
it('works with zod optional query parameters', () => {
623+
const routerWithRefine = c.router({
624+
endpointWithZodRefine: {
625+
method: 'GET',
626+
path: '/optional',
627+
responses: {
628+
200: c.type<null>(),
629+
},
630+
query: z.object({
631+
foo: z
632+
.object({
633+
baz: z.string().describe('Baz').optional(),
634+
bar: z.string().describe('Bar').optional(),
635+
})
636+
.describe('Foo')
637+
.optional(),
638+
}),
639+
},
640+
});
641+
642+
const schema = generateOpenApi(routerWithRefine, {
643+
info: { title: 'Blog API', version: '0.1' },
644+
});
645+
646+
expect(schema).toEqual({
647+
info: {
648+
title: 'Blog API',
649+
version: '0.1',
650+
},
651+
openapi: '3.0.2',
652+
paths: {
653+
'/optional': {
654+
get: {
655+
deprecated: undefined,
656+
description: undefined,
657+
parameters: [
658+
{
659+
description: 'Foo',
660+
in: 'query',
661+
name: 'foo',
662+
schema: {
663+
properties: {
664+
bar: {
665+
description: 'Bar',
666+
type: 'string',
667+
},
668+
baz: {
669+
description: 'Baz',
670+
type: 'string',
671+
},
672+
},
673+
type: 'object',
674+
},
675+
style: 'deepObject',
676+
},
677+
],
678+
responses: {
679+
'200': {
680+
description: '200',
681+
},
682+
},
683+
summary: undefined,
684+
tags: [],
685+
},
686+
},
687+
},
688+
});
689+
});
690+
622691
it('works with zod transform', () => {
623692
const routerWithTransform = c.router({
624693
endpointWithZodTransform: {

libs/ts-rest/open-api/src/lib/ts-rest-open-api.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,13 @@ const getQueryParametersFromZod = (zodObject: unknown, jsonQuery = false) => {
130130

131131
return Object.entries(zodShape).map(([key, value]) => {
132132
const { description, ...schema } = getOpenApiSchemaFromZod(value)!;
133-
const isObject = (value as z.ZodTypeAny)._def.typeName === 'ZodObject';
133+
const isObject = (obj: z.ZodTypeAny) => {
134+
while (obj._def.innerType) {
135+
obj = obj._def.innerType;
136+
}
137+
138+
return obj._def.typeName === 'ZodObject';
139+
};
134140
const isRequired = !(value as z.ZodTypeAny).isOptional();
135141

136142
return {
@@ -147,7 +153,9 @@ const getQueryParametersFromZod = (zodObject: unknown, jsonQuery = false) => {
147153
},
148154
}
149155
: {
150-
...(isObject && { style: 'deepObject' as const }),
156+
...(isObject(value as z.ZodTypeAny) && {
157+
style: 'deepObject' as const,
158+
}),
151159
schema: schema,
152160
}),
153161
};

0 commit comments

Comments
 (0)