Skip to content

Commit

Permalink
Feat: Add response headers to OpenApiMeta (trpc#334)
Browse files Browse the repository at this point in the history
  • Loading branch information
AarthiT authored Jun 30, 2023
1 parent 9c4eac4 commit 9012a43
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/generator/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const getOpenApiPathsObject = (
) || []),
],
}),
responses: getResponsesObject(outputParser, openapi.example?.response),
responses: getResponsesObject(outputParser, openapi.example?.response, openapi.responseHeaders),
...(openapi.deprecated ? { deprecated: openapi.deprecated } : {}),
},
};
Expand Down
2 changes: 2 additions & 0 deletions src/generator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export const errorResponseObject: OpenAPIV3.ResponseObject = {
export const getResponsesObject = (
schema: unknown,
example: Record<string, any> | undefined,
headers: Record<string, OpenAPIV3.HeaderObject | OpenAPIV3.ReferenceObject> | undefined
): OpenAPIV3.ResponsesObject => {
if (!instanceofZodType(schema)) {
throw new TRPCError({
Expand All @@ -199,6 +200,7 @@ export const getResponsesObject = (

const successResponseObject: OpenAPIV3.ResponseObject = {
description: 'Successful response',
headers: headers,
content: {
'application/json': {
schema: zodSchemaToOpenApiSchemaObject(schema),
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type OpenApiMeta<TMeta = TRPCMeta> = TMeta & {
request?: Record<string, any>;
response?: Record<string, any>;
};
responseHeaders?: Record<string, OpenAPIV3.HeaderObject | OpenAPIV3.ReferenceObject>;
};
};

Expand Down
122 changes: 122 additions & 0 deletions test/generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -616,6 +617,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -652,6 +654,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -701,6 +704,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -766,6 +770,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -945,6 +950,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -1001,6 +1007,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -1036,6 +1043,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
}
Expand All @@ -1061,6 +1069,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
}
Expand Down Expand Up @@ -1092,6 +1101,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1122,6 +1132,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1157,6 +1168,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1186,6 +1198,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1249,6 +1262,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
expect(openApiDocument.paths['/optional-object']!.get!.parameters).toMatchInlineSnapshot(`
Expand Down Expand Up @@ -1293,6 +1307,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1357,6 +1372,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
expect(openApiDocument.paths['/optional-object']!.post!.requestBody).toMatchInlineSnapshot(`
Expand Down Expand Up @@ -1402,6 +1418,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1445,6 +1462,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1681,6 +1699,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -1722,6 +1741,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -2075,6 +2095,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});
Expand Down Expand Up @@ -2316,6 +2337,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -2363,6 +2385,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -2410,6 +2433,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
},
"default": Object {
"$ref": "#/components/responses/error",
Expand Down Expand Up @@ -2704,6 +2728,7 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
expect(openApiDocument.paths['/mutation-example/{name}']!.post!.parameters)
Expand Down Expand Up @@ -2769,6 +2794,103 @@ describe('generator', () => {
},
},
"description": "Successful response",
"headers": undefined,
}
`);
});

test('with response headers', () => {
const appRouter = t.router({
queryExample: t.procedure
.meta({
openapi: {
method: 'GET',
path: '/query-example/{name}',
responseHeaders: {
"X-RateLimit-Limit": {
description: "Request limit per hour.",
schema: {
type: "integer"
}
},
"X-RateLimit-Remaining": {
description: "The number of requests left for the time window.",
schema: {
type: "integer"
}
}
}
},
})
.input(z.object({ name: z.string(), greeting: z.string() }))
.output(z.object({ output: z.string() }))
.query(({ input }) => ({
output: `${input.greeting} ${input.name}`,
}))
});

const openApiDocument = generateOpenApiDocument(appRouter, defaultDocOpts);

expect(openApiSchemaValidator.validate(openApiDocument).errors).toEqual([]);
expect(openApiDocument.paths['/query-example/{name}']!.get!.parameters).toMatchInlineSnapshot(`
Array [
Object {
"description": undefined,
"example": undefined,
"in": "path",
"name": "name",
"required": true,
"schema": Object {
"type": "string",
},
},
Object {
"description": undefined,
"example": undefined,
"in": "query",
"name": "greeting",
"required": true,
"schema": Object {
"type": "string",
},
},
]
`);
expect(openApiDocument.paths['/query-example/{name}']!.get!.responses[200])
.toMatchInlineSnapshot(`
Object {
"content": Object {
"application/json": Object {
"example": undefined,
"schema": Object {
"additionalProperties": false,
"properties": Object {
"output": Object {
"type": "string",
},
},
"required": Array [
"output",
],
"type": "object",
},
},
},
"description": "Successful response",
"headers": Object {
"X-RateLimit-Limit": Object {
"description": "Request limit per hour.",
"schema": Object {
"type": "integer",
},
},
"X-RateLimit-Remaining": Object {
"description": "The number of requests left for the time window.",
"schema": Object {
"type": "integer",
},
},
},
}
`);
});
Expand Down

0 comments on commit 9012a43

Please sign in to comment.