@dokploy/trpc-openapi 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generator/paths.d.ts.map +1 -1
- package/dist/generator/paths.js +2 -2
- package/dist/generator/paths.js.map +1 -1
- package/dist/generator/schema.d.ts.map +1 -1
- package/dist/generator/schema.js +3 -13
- package/dist/generator/schema.js.map +1 -1
- package/dist/types.d.ts +12 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/procedure.d.ts +4 -3
- package/dist/utils/procedure.d.ts.map +1 -1
- package/dist/utils/procedure.js +29 -7
- package/dist/utils/procedure.js.map +1 -1
- package/package.json +14 -9
- package/assets/trpc-openapi-graph.png +0 -0
- package/assets/trpc-openapi-readme.png +0 -0
- package/assets/trpc-openapi.svg +0 -4
- package/examples/with-express/README.md +0 -11
- package/examples/with-express/package.json +0 -28
- package/examples/with-express/src/database.ts +0 -67
- package/examples/with-express/src/index.ts +0 -27
- package/examples/with-express/src/openapi.ts +0 -13
- package/examples/with-express/src/router.ts +0 -424
- package/examples/with-express/tsconfig.json +0 -102
- package/examples/with-interop/README.md +0 -10
- package/examples/with-interop/package.json +0 -13
- package/examples/with-interop/src/index.ts +0 -17
- package/examples/with-interop/tsconfig.json +0 -103
- package/examples/with-nextjs/.eslintrc.json +0 -3
- package/examples/with-nextjs/README.md +0 -12
- package/examples/with-nextjs/next-env.d.ts +0 -5
- package/examples/with-nextjs/next.config.js +0 -6
- package/examples/with-nextjs/package.json +0 -33
- package/examples/with-nextjs/public/favicon.ico +0 -0
- package/examples/with-nextjs/src/pages/_app.tsx +0 -7
- package/examples/with-nextjs/src/pages/api/[...trpc].ts +0 -18
- package/examples/with-nextjs/src/pages/api/openapi.json.ts +0 -10
- package/examples/with-nextjs/src/pages/api/trpc/[...trpc].ts +0 -9
- package/examples/with-nextjs/src/pages/index.tsx +0 -12
- package/examples/with-nextjs/src/server/database.ts +0 -67
- package/examples/with-nextjs/src/server/openapi.ts +0 -13
- package/examples/with-nextjs/src/server/router.ts +0 -425
- package/examples/with-nextjs/tsconfig.json +0 -24
- package/jest.config.ts +0 -12
- package/pnpm-workspace.yaml +0 -7
- package/src/adapters/express.ts +0 -20
- package/src/adapters/index.ts +0 -3
- package/src/adapters/next.ts +0 -64
- package/src/adapters/node-http/core.ts +0 -203
- package/src/adapters/node-http/errors.ts +0 -45
- package/src/adapters/node-http/input.ts +0 -76
- package/src/adapters/node-http/procedures.ts +0 -64
- package/src/adapters/standalone.ts +0 -19
- package/src/generator/index.ts +0 -51
- package/src/generator/paths.ts +0 -127
- package/src/generator/schema.ts +0 -238
- package/src/index.ts +0 -42
- package/src/types.ts +0 -79
- package/src/utils/method.ts +0 -8
- package/src/utils/path.ts +0 -12
- package/src/utils/procedure.ts +0 -45
- package/src/utils/zod.ts +0 -115
- package/test/adapters/express.test.ts +0 -150
- package/test/adapters/next.test.ts +0 -162
- package/test/adapters/standalone.test.ts +0 -1335
- package/test/generator.test.ts +0 -2897
- package/tsconfig.build.json +0 -4
- package/tsconfig.eslint.json +0 -5
- package/tsconfig.json +0 -19
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
import { TRPCError, initTRPC } from "@trpc/server";
|
|
2
|
-
import { CreateNextContextOptions } from "@trpc/server/adapters/next";
|
|
3
|
-
import jwt from "jsonwebtoken";
|
|
4
|
-
import { OpenApiMeta } from "trpc-openapi";
|
|
5
|
-
import { v4 as uuid } from "uuid";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
|
|
8
|
-
import { Post, User, database } from "./database";
|
|
9
|
-
|
|
10
|
-
const jwtSecret = uuid();
|
|
11
|
-
|
|
12
|
-
export type Context = {
|
|
13
|
-
user: User | null;
|
|
14
|
-
requestId: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const t = initTRPC
|
|
18
|
-
.context<Context>()
|
|
19
|
-
.meta<OpenApiMeta>()
|
|
20
|
-
.create({
|
|
21
|
-
errorFormatter: ({ error, shape }) => {
|
|
22
|
-
if (
|
|
23
|
-
error.code === "INTERNAL_SERVER_ERROR" &&
|
|
24
|
-
process.env.NODE_ENV === "production"
|
|
25
|
-
) {
|
|
26
|
-
return { ...shape, message: "Internal server error" };
|
|
27
|
-
}
|
|
28
|
-
return shape;
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
export const createContext = async ({
|
|
33
|
-
req,
|
|
34
|
-
res,
|
|
35
|
-
}: CreateNextContextOptions): Promise<Context> => {
|
|
36
|
-
const requestId = uuid();
|
|
37
|
-
res.setHeader("x-request-id", requestId);
|
|
38
|
-
|
|
39
|
-
let user: User | null = null;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
if (req.headers.authorization) {
|
|
43
|
-
const token = req.headers.authorization.split(" ")[1];
|
|
44
|
-
const userId = jwt.verify(token, jwtSecret) as string;
|
|
45
|
-
if (userId) {
|
|
46
|
-
user = database.users.find((_user) => _user.id === userId) ?? null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
} catch (cause) {
|
|
50
|
-
console.error(cause);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return { user, requestId };
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const publicProcedure = t.procedure;
|
|
57
|
-
const protectedProcedure = t.procedure.use(({ ctx, next }) => {
|
|
58
|
-
if (!ctx.user) {
|
|
59
|
-
throw new TRPCError({
|
|
60
|
-
message: "User not found",
|
|
61
|
-
code: "UNAUTHORIZED",
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
return next({ ctx: { ...ctx, user: ctx.user } });
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const authRouter = t.router({
|
|
68
|
-
register: publicProcedure
|
|
69
|
-
.meta({
|
|
70
|
-
openapi: {
|
|
71
|
-
method: "POST",
|
|
72
|
-
path: "/auth/register",
|
|
73
|
-
tags: ["auth"],
|
|
74
|
-
summary: "Register as a new user",
|
|
75
|
-
},
|
|
76
|
-
})
|
|
77
|
-
.input(
|
|
78
|
-
z.object({
|
|
79
|
-
email: z.string().email(),
|
|
80
|
-
passcode: z.preprocess(
|
|
81
|
-
(arg) => (typeof arg === "string" ? parseInt(arg) : arg),
|
|
82
|
-
z.number().min(1000).max(9999),
|
|
83
|
-
),
|
|
84
|
-
name: z.string().min(3),
|
|
85
|
-
}),
|
|
86
|
-
)
|
|
87
|
-
.output(
|
|
88
|
-
z.object({
|
|
89
|
-
user: z.object({
|
|
90
|
-
id: z.string().uuid(),
|
|
91
|
-
email: z.string().email(),
|
|
92
|
-
name: z.string().min(3),
|
|
93
|
-
}),
|
|
94
|
-
}),
|
|
95
|
-
)
|
|
96
|
-
.mutation(({ input }) => {
|
|
97
|
-
let user = database.users.find((_user) => _user.email === input.email);
|
|
98
|
-
|
|
99
|
-
if (user) {
|
|
100
|
-
throw new TRPCError({
|
|
101
|
-
message: "User with email already exists",
|
|
102
|
-
code: "UNAUTHORIZED",
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
user = {
|
|
107
|
-
id: uuid(),
|
|
108
|
-
email: input.email,
|
|
109
|
-
passcode: input.passcode,
|
|
110
|
-
name: input.name,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
database.users.push(user);
|
|
114
|
-
|
|
115
|
-
return { user: { id: user.id, email: user.email, name: user.name } };
|
|
116
|
-
}),
|
|
117
|
-
login: publicProcedure
|
|
118
|
-
.meta({
|
|
119
|
-
openapi: {
|
|
120
|
-
method: "POST",
|
|
121
|
-
path: "/auth/login",
|
|
122
|
-
tags: ["auth"],
|
|
123
|
-
summary: "Login as an existing user",
|
|
124
|
-
},
|
|
125
|
-
})
|
|
126
|
-
.input(
|
|
127
|
-
z.object({
|
|
128
|
-
email: z.string().email(),
|
|
129
|
-
passcode: z.preprocess(
|
|
130
|
-
(arg) => (typeof arg === "string" ? parseInt(arg) : arg),
|
|
131
|
-
z.number().min(1000).max(9999),
|
|
132
|
-
),
|
|
133
|
-
}),
|
|
134
|
-
)
|
|
135
|
-
.output(
|
|
136
|
-
z.object({
|
|
137
|
-
token: z.string(),
|
|
138
|
-
}),
|
|
139
|
-
)
|
|
140
|
-
.mutation(({ input }) => {
|
|
141
|
-
const user = database.users.find((_user) => _user.email === input.email);
|
|
142
|
-
|
|
143
|
-
if (!user) {
|
|
144
|
-
throw new TRPCError({
|
|
145
|
-
message: "User with email not found",
|
|
146
|
-
code: "UNAUTHORIZED",
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
if (user.passcode !== input.passcode) {
|
|
150
|
-
throw new TRPCError({
|
|
151
|
-
message: "Passcode was incorrect",
|
|
152
|
-
code: "UNAUTHORIZED",
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
token: jwt.sign(user.id, jwtSecret),
|
|
158
|
-
};
|
|
159
|
-
}),
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
const usersRouter = t.router({
|
|
163
|
-
getUsers: publicProcedure
|
|
164
|
-
.meta({
|
|
165
|
-
openapi: {
|
|
166
|
-
method: "GET",
|
|
167
|
-
path: "/users",
|
|
168
|
-
tags: ["users"],
|
|
169
|
-
summary: "Read all users",
|
|
170
|
-
},
|
|
171
|
-
})
|
|
172
|
-
// .input(z.void())
|
|
173
|
-
// .output(
|
|
174
|
-
// z.object({
|
|
175
|
-
// users: z.array(
|
|
176
|
-
// z.object({
|
|
177
|
-
// id: z.string().uuid(),
|
|
178
|
-
// email: z.string().email(),
|
|
179
|
-
// name: z.string(),
|
|
180
|
-
// }),
|
|
181
|
-
// ),
|
|
182
|
-
// }),
|
|
183
|
-
// )
|
|
184
|
-
.query(() => {
|
|
185
|
-
const users = database.users.map((user) => ({
|
|
186
|
-
id: user.id,
|
|
187
|
-
email: user.email,
|
|
188
|
-
name: user.name,
|
|
189
|
-
}));
|
|
190
|
-
|
|
191
|
-
return { users };
|
|
192
|
-
}),
|
|
193
|
-
getUserById: publicProcedure
|
|
194
|
-
.meta({
|
|
195
|
-
openapi: {
|
|
196
|
-
method: "GET",
|
|
197
|
-
path: "/users/{id}",
|
|
198
|
-
tags: ["users"],
|
|
199
|
-
summary: "Read a user by id",
|
|
200
|
-
},
|
|
201
|
-
})
|
|
202
|
-
.input(
|
|
203
|
-
z.object({
|
|
204
|
-
id: z.string().uuid(),
|
|
205
|
-
}),
|
|
206
|
-
)
|
|
207
|
-
.output(
|
|
208
|
-
z.object({
|
|
209
|
-
user: z.object({
|
|
210
|
-
id: z.string().uuid(),
|
|
211
|
-
email: z.string().email(),
|
|
212
|
-
name: z.string(),
|
|
213
|
-
}),
|
|
214
|
-
}),
|
|
215
|
-
)
|
|
216
|
-
.query(({ input }) => {
|
|
217
|
-
const user = database.users.find((_user) => _user.id === input.id);
|
|
218
|
-
|
|
219
|
-
if (!user) {
|
|
220
|
-
throw new TRPCError({
|
|
221
|
-
message: "User not found",
|
|
222
|
-
code: "NOT_FOUND",
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return { user };
|
|
227
|
-
}),
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
const postsRouter = t.router({
|
|
231
|
-
getPosts: publicProcedure
|
|
232
|
-
.meta({
|
|
233
|
-
openapi: {
|
|
234
|
-
method: "GET",
|
|
235
|
-
path: "/posts",
|
|
236
|
-
tags: ["posts"],
|
|
237
|
-
summary: "Read all posts",
|
|
238
|
-
},
|
|
239
|
-
})
|
|
240
|
-
.input(
|
|
241
|
-
z.object({
|
|
242
|
-
userId: z.string().uuid().optional(),
|
|
243
|
-
}),
|
|
244
|
-
)
|
|
245
|
-
.output(
|
|
246
|
-
z.object({
|
|
247
|
-
posts: z.array(
|
|
248
|
-
z.object({
|
|
249
|
-
id: z.string().uuid(),
|
|
250
|
-
content: z.string(),
|
|
251
|
-
userId: z.string().uuid(),
|
|
252
|
-
}),
|
|
253
|
-
),
|
|
254
|
-
}),
|
|
255
|
-
)
|
|
256
|
-
.query(({ input }) => {
|
|
257
|
-
let posts: Post[] = database.posts;
|
|
258
|
-
|
|
259
|
-
if (input.userId) {
|
|
260
|
-
posts = posts.filter((post) => {
|
|
261
|
-
return post.userId === input.userId;
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return { posts };
|
|
266
|
-
}),
|
|
267
|
-
getPostById: publicProcedure
|
|
268
|
-
.meta({
|
|
269
|
-
openapi: {
|
|
270
|
-
method: "GET",
|
|
271
|
-
path: "/posts/{id}",
|
|
272
|
-
tags: ["posts"],
|
|
273
|
-
summary: "Read a post by id",
|
|
274
|
-
},
|
|
275
|
-
})
|
|
276
|
-
.input(
|
|
277
|
-
z.object({
|
|
278
|
-
id: z.string().uuid(),
|
|
279
|
-
}),
|
|
280
|
-
)
|
|
281
|
-
.output(
|
|
282
|
-
z.object({
|
|
283
|
-
post: z.object({
|
|
284
|
-
id: z.string().uuid(),
|
|
285
|
-
content: z.string(),
|
|
286
|
-
userId: z.string().uuid(),
|
|
287
|
-
}),
|
|
288
|
-
}),
|
|
289
|
-
)
|
|
290
|
-
.query(({ input }) => {
|
|
291
|
-
const post = database.posts.find((_post) => _post.id === input.id);
|
|
292
|
-
|
|
293
|
-
if (!post) {
|
|
294
|
-
throw new TRPCError({
|
|
295
|
-
message: "Post not found",
|
|
296
|
-
code: "NOT_FOUND",
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return { post };
|
|
301
|
-
}),
|
|
302
|
-
createPost: protectedProcedure
|
|
303
|
-
.meta({
|
|
304
|
-
openapi: {
|
|
305
|
-
method: "POST",
|
|
306
|
-
path: "/posts",
|
|
307
|
-
tags: ["posts"],
|
|
308
|
-
protect: true,
|
|
309
|
-
summary: "Create a new post",
|
|
310
|
-
},
|
|
311
|
-
})
|
|
312
|
-
.input(
|
|
313
|
-
z.object({
|
|
314
|
-
content: z.string().min(1).max(140),
|
|
315
|
-
}),
|
|
316
|
-
)
|
|
317
|
-
.output(
|
|
318
|
-
z.object({
|
|
319
|
-
post: z.object({
|
|
320
|
-
id: z.string().uuid(),
|
|
321
|
-
content: z.string(),
|
|
322
|
-
userId: z.string().uuid(),
|
|
323
|
-
}),
|
|
324
|
-
}),
|
|
325
|
-
)
|
|
326
|
-
.mutation(({ input, ctx }) => {
|
|
327
|
-
const post: Post = {
|
|
328
|
-
id: uuid(),
|
|
329
|
-
content: input.content,
|
|
330
|
-
userId: ctx.user.id,
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
database.posts.push(post);
|
|
334
|
-
|
|
335
|
-
return { post };
|
|
336
|
-
}),
|
|
337
|
-
updatePostById: protectedProcedure
|
|
338
|
-
.meta({
|
|
339
|
-
openapi: {
|
|
340
|
-
method: "PUT",
|
|
341
|
-
path: "/posts/{id}",
|
|
342
|
-
tags: ["posts"],
|
|
343
|
-
protect: true,
|
|
344
|
-
summary: "Update an existing post",
|
|
345
|
-
},
|
|
346
|
-
})
|
|
347
|
-
.input(
|
|
348
|
-
z.object({
|
|
349
|
-
id: z.string().uuid(),
|
|
350
|
-
content: z.string().min(1),
|
|
351
|
-
}),
|
|
352
|
-
)
|
|
353
|
-
.output(
|
|
354
|
-
z.object({
|
|
355
|
-
post: z.object({
|
|
356
|
-
id: z.string().uuid(),
|
|
357
|
-
content: z.string(),
|
|
358
|
-
userId: z.string().uuid(),
|
|
359
|
-
}),
|
|
360
|
-
}),
|
|
361
|
-
)
|
|
362
|
-
.mutation(({ input, ctx }) => {
|
|
363
|
-
const post = database.posts.find((_post) => _post.id === input.id);
|
|
364
|
-
|
|
365
|
-
if (!post) {
|
|
366
|
-
throw new TRPCError({
|
|
367
|
-
message: "Post not found",
|
|
368
|
-
code: "NOT_FOUND",
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
if (post.userId !== ctx.user.id) {
|
|
372
|
-
throw new TRPCError({
|
|
373
|
-
message: "Cannot edit post owned by other user",
|
|
374
|
-
code: "FORBIDDEN",
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
post.content = input.content;
|
|
379
|
-
|
|
380
|
-
return { post };
|
|
381
|
-
}),
|
|
382
|
-
deletePostById: protectedProcedure
|
|
383
|
-
.meta({
|
|
384
|
-
openapi: {
|
|
385
|
-
method: "DELETE",
|
|
386
|
-
path: "/posts/{id}",
|
|
387
|
-
tags: ["posts"],
|
|
388
|
-
protect: true,
|
|
389
|
-
summary: "Delete a post",
|
|
390
|
-
},
|
|
391
|
-
})
|
|
392
|
-
.input(
|
|
393
|
-
z.object({
|
|
394
|
-
id: z.string().uuid(),
|
|
395
|
-
}),
|
|
396
|
-
)
|
|
397
|
-
.output(z.null())
|
|
398
|
-
.mutation(({ input, ctx }) => {
|
|
399
|
-
const post = database.posts.find((_post) => _post.id === input.id);
|
|
400
|
-
if (!post) {
|
|
401
|
-
throw new TRPCError({
|
|
402
|
-
message: "Post not found",
|
|
403
|
-
code: "NOT_FOUND",
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
if (post.userId !== ctx.user.id) {
|
|
407
|
-
throw new TRPCError({
|
|
408
|
-
message: "Cannot delete post owned by other user",
|
|
409
|
-
code: "FORBIDDEN",
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
database.posts = database.posts.filter((_post) => _post !== post);
|
|
414
|
-
|
|
415
|
-
return null;
|
|
416
|
-
}),
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
export const appRouter = t.router({
|
|
420
|
-
auth: authRouter,
|
|
421
|
-
users: usersRouter,
|
|
422
|
-
posts: postsRouter,
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
export type AppRouter = typeof appRouter;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es5",
|
|
4
|
-
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
-
"allowJs": true,
|
|
6
|
-
"skipLibCheck": true,
|
|
7
|
-
"strict": true,
|
|
8
|
-
"forceConsistentCasingInFileNames": true,
|
|
9
|
-
"noEmit": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"module": "esnext",
|
|
12
|
-
"moduleResolution": "node",
|
|
13
|
-
"resolveJsonModule": true,
|
|
14
|
-
"isolatedModules": true,
|
|
15
|
-
"jsx": "preserve",
|
|
16
|
-
"incremental": true,
|
|
17
|
-
"baseUrl": ".",
|
|
18
|
-
"paths": {
|
|
19
|
-
"trpc-openapi": ["../../dist"]
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
|
23
|
-
"exclude": ["node_modules"]
|
|
24
|
-
}
|
package/jest.config.ts
DELETED
package/pnpm-workspace.yaml
DELETED
package/src/adapters/express.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Request, Response } from 'express';
|
|
2
|
-
|
|
3
|
-
import { OpenApiRouter } from '../types';
|
|
4
|
-
import {
|
|
5
|
-
CreateOpenApiNodeHttpHandlerOptions,
|
|
6
|
-
createOpenApiNodeHttpHandler,
|
|
7
|
-
} from './node-http/core';
|
|
8
|
-
|
|
9
|
-
export type CreateOpenApiExpressMiddlewareOptions<TRouter extends OpenApiRouter> =
|
|
10
|
-
CreateOpenApiNodeHttpHandlerOptions<TRouter, Request, Response>;
|
|
11
|
-
|
|
12
|
-
export const createOpenApiExpressMiddleware = <TRouter extends OpenApiRouter>(
|
|
13
|
-
opts: CreateOpenApiExpressMiddlewareOptions<TRouter>,
|
|
14
|
-
) => {
|
|
15
|
-
const openApiHttpHandler = createOpenApiNodeHttpHandler(opts);
|
|
16
|
-
|
|
17
|
-
return async (req: Request, res: Response) => {
|
|
18
|
-
await openApiHttpHandler(req, res);
|
|
19
|
-
};
|
|
20
|
-
};
|
package/src/adapters/index.ts
DELETED
package/src/adapters/next.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { TRPCError } from "@trpc/server";
|
|
2
|
-
import type { NextApiRequest, NextApiResponse } from "next";
|
|
3
|
-
|
|
4
|
-
import type { OpenApiErrorResponse, OpenApiRouter } from "../types";
|
|
5
|
-
import { normalizePath } from "../utils/path";
|
|
6
|
-
import {
|
|
7
|
-
type CreateOpenApiNodeHttpHandlerOptions,
|
|
8
|
-
createOpenApiNodeHttpHandler,
|
|
9
|
-
} from "./node-http/core";
|
|
10
|
-
|
|
11
|
-
export type CreateOpenApiNextHandlerOptions<TRouter extends OpenApiRouter> =
|
|
12
|
-
Omit<
|
|
13
|
-
CreateOpenApiNodeHttpHandlerOptions<
|
|
14
|
-
TRouter,
|
|
15
|
-
NextApiRequest,
|
|
16
|
-
NextApiResponse
|
|
17
|
-
>,
|
|
18
|
-
"maxBodySize"
|
|
19
|
-
>;
|
|
20
|
-
|
|
21
|
-
export const createOpenApiNextHandler = <TRouter extends OpenApiRouter>(
|
|
22
|
-
opts: CreateOpenApiNextHandlerOptions<TRouter>,
|
|
23
|
-
) => {
|
|
24
|
-
const openApiHttpHandler = createOpenApiNodeHttpHandler(opts);
|
|
25
|
-
|
|
26
|
-
return async (req: NextApiRequest, res: NextApiResponse) => {
|
|
27
|
-
let pathname: string | null = null;
|
|
28
|
-
if (typeof req.query.trpc === "string") {
|
|
29
|
-
pathname = req.query.trpc;
|
|
30
|
-
} else if (Array.isArray(req.query.trpc)) {
|
|
31
|
-
pathname = req.query.trpc.join("/");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (pathname === null) {
|
|
35
|
-
const error = new TRPCError({
|
|
36
|
-
message:
|
|
37
|
-
'Query "trpc" not found - is the `trpc-openapi` file named `[...trpc].ts`?',
|
|
38
|
-
code: "INTERNAL_SERVER_ERROR",
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
opts.onError?.({
|
|
42
|
-
error,
|
|
43
|
-
type: "unknown",
|
|
44
|
-
path: undefined,
|
|
45
|
-
input: undefined,
|
|
46
|
-
ctx: undefined,
|
|
47
|
-
req,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
res.statusCode = 500;
|
|
51
|
-
res.setHeader("Content-Type", "application/json");
|
|
52
|
-
const body: OpenApiErrorResponse = {
|
|
53
|
-
message: error.message,
|
|
54
|
-
code: error.code,
|
|
55
|
-
};
|
|
56
|
-
res.end(JSON.stringify(body));
|
|
57
|
-
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
req.url = normalizePath(pathname);
|
|
62
|
-
await openApiHttpHandler(req, res);
|
|
63
|
-
};
|
|
64
|
-
};
|