Skip to content

Commit

Permalink
#177 fix .describe for paramteres not putting the description in the …
Browse files Browse the repository at this point in the history
…correct place
  • Loading branch information
AGalabov committed Oct 17, 2023
1 parent 0cb3c0b commit 890b45a
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 2 deletions.
76 changes: 75 additions & 1 deletion spec/modifiers/describe.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from 'zod';
import { expectSchema } from '../lib/helpers';
import { expectSchema, generateDataForRoute } from '../lib/helpers';

describe('describe', () => {
it('generates OpenAPI schema with description when the .describe method is used', () => {
Expand Down Expand Up @@ -78,4 +78,78 @@ describe('describe', () => {
},
});
});

it('generates an optional query parameter with a provided description', () => {
const { parameters } = generateDataForRoute({
request: {
query: z.object({
test: z.string().optional().describe('Some parameter'),
}),
},
});

expect(parameters).toEqual([
{
in: 'query',
name: 'test',
description: 'Some parameter',
required: false,
schema: {
description: 'Some parameter',
type: 'string',
},
},
]);
});

it('generates a query parameter with a description made optional', () => {
const { parameters } = generateDataForRoute({
request: {
query: z.object({
test: z.string().describe('Some parameter').optional(),
}),
},
});

expect(parameters).toEqual([
{
in: 'query',
name: 'test',
description: 'Some parameter',
required: false,
schema: {
description: 'Some parameter',
type: 'string',
},
},
]);
});

it('generates a query parameter with description from a registered schema', () => {
const schema = z.string().describe('Some parameter').openapi('SomeString');
const { parameters, documentSchemas } = generateDataForRoute({
request: {
query: z.object({ test: schema }),
},
});

expect(documentSchemas).toEqual({
SomeString: {
type: 'string',
description: 'Some parameter',
},
});

expect(parameters).toEqual([
{
in: 'query',
name: 'test',
description: 'Some parameter',
required: true,
schema: {
$ref: '#/components/schemas/SomeString',
},
},
]);
});
});
33 changes: 32 additions & 1 deletion src/openapi-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ export class OpenAPIGenerator {
}

private generateSimpleParameter(zodSchema: ZodTypeAny): BaseParameterObject {
const metadata = this.getMetadata(zodSchema);
const metadata = this.getParamMetadata(zodSchema);
const paramMetadata = metadata?.metadata?.param;

const required =
Expand Down Expand Up @@ -1222,6 +1222,37 @@ export class OpenAPIGenerator {
return omitBy(metadata, isNil);
}

private getParamMetadata<T extends any>(
zodSchema: ZodType<T>
): ZodOpenApiFullMetadata<T> | undefined {
const innerSchema = this.unwrapChained(zodSchema);

const metadata = zodSchema._def.openapi
? zodSchema._def.openapi
: innerSchema._def.openapi;

/**
* Every zod schema can receive a `description` by using the .describe method.
* That description should be used when generating an OpenApi schema.
* The `??` bellow makes sure we can handle both:
* - schema.describe('Test').optional()
* - schema.optional().describe('Test')
*/
const zodDescription = zodSchema.description ?? innerSchema.description;

return {
_internal: metadata?._internal,
metadata: {
...metadata?.metadata,
// A description provided from .openapi() should be taken with higher precedence
param: {
description: zodDescription,
...metadata?.metadata.param,
},
},
};
}

private getMetadata<T extends any>(
zodSchema: ZodType<T>
): ZodOpenApiFullMetadata<T> | undefined {
Expand Down

0 comments on commit 890b45a

Please sign in to comment.