Skip to content

Commit

Permalink
Merge branch 'master' of github.com:asteasolutions/zod-to-openapi int…
Browse files Browse the repository at this point in the history
…o enhancement/#99-automatic-registration
  • Loading branch information
AGalabov committed May 2, 2023
2 parents f92f982 + 38b74cb commit 825f5f4
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 14 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions spec/routes/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,50 @@ const routeTests = ({

expect(responses['204']).toEqual({ description: 'Success' });
});

it('can generate response headers', () => {
const registry = new OpenAPIRegistry();

registry[registerFunction]({
method: 'get',
path: '/',
responses: {
204: {
description: 'Success',
headers: z.object({
'Set-Cookie': z.string().openapi({
example: 'token=test',
description: 'Some string value',
param: {
description: 'JWT session cookie',
},
}),
}),
},
},
});

const document = new OpenAPIGenerator(
registry.definitions,
'3.0.0'
).generateDocument(testDocConfig);
const responses = document[rootDocPath]?.['/'].get.responses;

expect(responses['204']).toEqual({
description: 'Success',
headers: {
'Set-Cookie': {
schema: {
type: 'string',
example: 'token=test',
description: 'Some string value',
},
description: 'JWT session cookie',
required: true,
},
},
});
});
});

it('can generate paths with multiple examples', () => {
Expand Down
56 changes: 49 additions & 7 deletions src/openapi-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
ResponseObject,
ContentObject,
DiscriminatorObject,
HeadersObject,
BaseParameterObject,
} from 'openapi3-ts';
import type {
AnyZodObject,
Expand Down Expand Up @@ -330,6 +332,24 @@ export class OpenAPIGenerator {
];
}

private generateSimpleParameter(
zodSchema: ZodSchema<any>
): BaseParameterObject {
const metadata = this.getMetadata(zodSchema);
const paramMetadata = metadata?.metadata?.param;

const required =
!this.isOptionalSchema(zodSchema) && !zodSchema.isNullable();

const schema = this.generateSchemaWithRef(zodSchema);

return {
schema,
required,
...(paramMetadata ? this.buildParameterMetadata(paramMetadata) : {}),
};
}

private generateParameter(zodSchema: ZodSchema<any>): ParameterObject {
const metadata = this.getMetadata(zodSchema);

Expand All @@ -349,17 +369,12 @@ export class OpenAPIGenerator {
});
}

const required =
!this.isOptionalSchema(zodSchema) && !zodSchema.isNullable();

const schema = this.generateSchemaWithRef(zodSchema);
const baseParameter = this.generateSimpleParameter(zodSchema);

return {
...baseParameter,
in: paramLocation,
name: paramName,
schema,
required,
...(paramMetadata ? this.buildParameterMetadata(paramMetadata) : {}),
};
}

Expand Down Expand Up @@ -571,18 +586,45 @@ export class OpenAPIGenerator {

private getResponse({
content,
headers,
...rest
}: ResponseConfig): ResponseObject | ReferenceObject {
const responseContent = content
? { content: this.getBodyContent(content) }
: {};

if (!headers) {
return {
...rest,
...responseContent,
};
}

const responseHeaders = this.getResponseHeaders(headers);

return {
...rest,
headers: responseHeaders,
...responseContent,
};
}

private getResponseHeaders(
headers: HeadersObject | AnyZodObject
): HeadersObject {
if (!isZodType(headers, 'ZodObject')) {
return headers;
}

const schemaShape = headers._def.shape();

const responseHeaders = mapValues(schemaShape, _ =>
this.generateSimpleParameter(_)
);

return responseHeaders;
}

private getBodyContent(content: ZodContentObject): ContentObject {
return mapValues(content, config => {
if (!isAnyZodType(config.schema)) {
Expand Down
2 changes: 1 addition & 1 deletion src/openapi-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export interface ZodRequestBody {

export interface ResponseConfig {
description: string;
headers?: HeadersObject;
headers?: AnyZodObject | HeadersObject;
links?: LinksObject;
content?: ZodContentObject;
}
Expand Down

0 comments on commit 825f5f4

Please sign in to comment.