Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.

Commit 61f80e4

Browse files
authored
Feat: Example schemas (#309)
1 parent 85dd7fd commit 61f80e4

File tree

5 files changed

+264
-11
lines changed

5 files changed

+264
-11
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ export const openApiDocument = generateOpenApiDocument(appRouter, {
6666

6767
**5. Add an `trpc-openapi` handler to your app.**
6868

69-
We currently support adapters for [`Express`](http://expressjs.com/), [`Next.js`](https://nextjs.org/), [`Serverless`](https://www.serverless.com/) & [`Node:HTTP`](https://nodejs.org/api/http.html).
69+
We currently support adapters for [`Express`](http://expressjs.com/), [`Next.js`](https://nextjs.org/), [`Serverless`](https://www.serverless.com/), [`Fastify`](https://www.fastify.io/), [`Nuxt`](https://nuxtjs.org/) & [`Node:HTTP`](https://nodejs.org/api/http.html).
7070

71-
[`Fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), [`Fastify`](https://www.fastify.io/), [`Nuxt`](https://nuxtjs.org/), [`Workers`](https://workers.cloudflare.com/) & more soon™, PRs are welcomed 🙌.
71+
[`Fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), [`Cloudflare Workers`](https://workers.cloudflare.com/) & more soon™, PRs are welcomed 🙌.
7272

7373
```typescript
7474
import http from 'http';
@@ -179,7 +179,7 @@ Please see [error status codes here](src/adapters/node-http/errors.ts).
179179

180180
## Authorization
181181

182-
To create protected endpoints, add `protect: true` to the `meta.openapi` object of each tRPC procedure. You can then authenticate each request with the `createContext` function using the `Authorization` header with the `Bearer` scheme.
182+
To create protected endpoints, add `protect: true` to the `meta.openapi` object of each tRPC procedure. By default, you can then authenticate each request with the `createContext` function using the `Authorization` header with the `Bearer` scheme. If you wish to authenticate requests using a different/additional methods (such as custom headers, or cookies) this can be overwritten by specifying `securitySchemes` object.
183183

184184
Explore a [complete example here](examples/with-nextjs/src/server/router.ts).
185185

src/generator/paths.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,35 @@ export const getOpenApiPathsObject = (
6666
security: protect ? securitySchemeNames.map((name) => ({ [name]: [] })) : undefined,
6767
...(acceptsRequestBody(method)
6868
? {
69-
requestBody: getRequestBodyObject(inputParser, pathParameters, contentTypes),
69+
requestBody: getRequestBodyObject(
70+
inputParser,
71+
pathParameters,
72+
contentTypes,
73+
openapi.example?.request,
74+
),
7075
parameters: [
7176
...headerParameters,
72-
...(getParameterObjects(inputParser, pathParameters, 'path') || []),
77+
...(getParameterObjects(
78+
inputParser,
79+
pathParameters,
80+
'path',
81+
openapi.example?.request,
82+
) || []),
7383
],
7484
}
7585
: {
7686
requestBody: undefined,
7787
parameters: [
7888
...headerParameters,
79-
...(getParameterObjects(inputParser, pathParameters, 'all') || []),
89+
...(getParameterObjects(
90+
inputParser,
91+
pathParameters,
92+
'all',
93+
openapi.example?.request,
94+
) || []),
8095
],
8196
}),
82-
responses: getResponsesObject(outputParser),
97+
responses: getResponsesObject(outputParser, openapi.example?.response),
8398
...(openapi.deprecated ? { deprecated: openapi.deprecated } : {}),
8499
},
85100
};

src/generator/schema.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const getParameterObjects = (
2424
schema: unknown,
2525
pathParameters: string[],
2626
inType: 'all' | 'path' | 'query',
27+
example: Record<string, any> | undefined,
2728
): OpenAPIV3.ParameterObject[] | undefined => {
2829
if (!instanceofZodType(schema)) {
2930
throw new TRPCError({
@@ -107,6 +108,7 @@ export const getParameterObjects = (
107108
required: isPathParameter || (isRequired && isShapeRequired),
108109
schema: openApiSchemaObject,
109110
description: description,
111+
example: example?.[shapeKey],
110112
};
111113
});
112114
};
@@ -115,6 +117,7 @@ export const getRequestBodyObject = (
115117
schema: unknown,
116118
pathParameters: string[],
117119
contentTypes: OpenApiContentType[],
120+
example: Record<string, any> | undefined,
118121
): OpenAPIV3.RequestBodyObject | undefined => {
119122
if (!instanceofZodType(schema)) {
120123
throw new TRPCError({
@@ -139,8 +142,12 @@ export const getRequestBodyObject = (
139142

140143
// remove path parameters
141144
const mask: Record<string, true> = {};
145+
const dedupedExample = example && { ...example };
142146
pathParameters.forEach((pathParameter) => {
143147
mask[pathParameter] = true;
148+
if (dedupedExample) {
149+
delete dedupedExample[pathParameter];
150+
}
144151
});
145152
const dedupedSchema = unwrappedSchema.omit(mask);
146153

@@ -149,6 +156,7 @@ export const getRequestBodyObject = (
149156
for (const contentType of contentTypes) {
150157
content[contentType] = {
151158
schema: openApiSchemaObject,
159+
example: dedupedExample,
152160
};
153161
}
154162

@@ -158,7 +166,7 @@ export const getRequestBodyObject = (
158166
};
159167
};
160168

161-
export const errorResponseObject = {
169+
export const errorResponseObject: OpenAPIV3.ResponseObject = {
162170
description: 'Error response',
163171
content: {
164172
'application/json': {
@@ -173,19 +181,23 @@ export const errorResponseObject = {
173181
},
174182
};
175183

176-
export const getResponsesObject = (schema: unknown): OpenAPIV3.ResponsesObject => {
184+
export const getResponsesObject = (
185+
schema: unknown,
186+
example: Record<string, any> | undefined,
187+
): OpenAPIV3.ResponsesObject => {
177188
if (!instanceofZodType(schema)) {
178189
throw new TRPCError({
179190
message: 'Output parser expects a Zod validator',
180191
code: 'INTERNAL_SERVER_ERROR',
181192
});
182193
}
183194

184-
const successResponseObject = {
195+
const successResponseObject: OpenAPIV3.ResponseObject = {
185196
description: 'Successful response',
186197
content: {
187198
'application/json': {
188199
schema: zodSchemaToOpenApiSchemaObject(schema),
200+
example,
189201
},
190202
},
191203
};

src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export type OpenApiMeta<TMeta = TRPCMeta> = TMeta & {
2727
headers?: (OpenAPIV3.ParameterBaseObject & { name: string; in?: 'header' })[];
2828
contentTypes?: OpenApiContentType[];
2929
deprecated?: boolean;
30+
example?: {
31+
request?: Record<string, any>;
32+
response?: Record<string, any>;
33+
};
3034
};
3135
};
3236

0 commit comments

Comments
 (0)