next-openapi-gen 0.10.5 → 1.0.1
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/README.md +407 -1047
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +8599 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +8645 -26
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.js +7965 -0
- package/dist/react-router/index.d.ts +1 -0
- package/dist/react-router/index.js +7134 -0
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.js +7134 -0
- package/package.json +103 -79
- package/{dist/components/rapidoc.js → templates/init/ui/nextjs/rapidoc.tsx} +16 -20
- package/templates/init/ui/nextjs/redoc.tsx +11 -0
- package/{dist/components/scalar.js → templates/init/ui/nextjs/scalar.tsx} +15 -21
- package/{dist/components/stoplight.js → templates/init/ui/nextjs/stoplight.tsx} +11 -17
- package/templates/init/ui/nextjs/swagger.tsx +17 -0
- package/templates/init/ui/reactrouter/rapidoc.tsx +15 -0
- package/templates/init/ui/reactrouter/redoc.tsx +9 -0
- package/templates/init/ui/reactrouter/scalar.tsx +14 -0
- package/templates/init/ui/reactrouter/stoplight.tsx +10 -0
- package/templates/init/ui/reactrouter/swagger.tsx +11 -0
- package/templates/init/ui/tanstack/rapidoc.tsx +21 -0
- package/templates/init/ui/tanstack/redoc.tsx +14 -0
- package/templates/init/ui/tanstack/scalar.tsx +19 -0
- package/templates/init/ui/tanstack/stoplight.tsx +15 -0
- package/templates/init/ui/tanstack/swagger.tsx +16 -0
- package/templates/init/ui/template-types.d.ts +9 -0
- package/dist/commands/generate.js +0 -24
- package/dist/commands/init.js +0 -194
- package/dist/components/redoc.js +0 -17
- package/dist/components/swagger.js +0 -21
- package/dist/lib/app-router-strategy.js +0 -66
- package/dist/lib/drizzle-zod-processor.js +0 -329
- package/dist/lib/logger.js +0 -39
- package/dist/lib/openapi-generator.js +0 -171
- package/dist/lib/pages-router-strategy.js +0 -198
- package/dist/lib/route-processor.js +0 -349
- package/dist/lib/router-strategy.js +0 -1
- package/dist/lib/schema-processor.js +0 -1612
- package/dist/lib/utils.js +0 -283
- package/dist/lib/zod-converter.js +0 -2133
- package/dist/openapi-template.js +0 -99
- package/dist/types.js +0 -1
package/README.md
CHANGED
|
@@ -1,1047 +1,407 @@
|
|
|
1
|
-
# next-openapi-gen
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
- Swagger
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
```typescript
|
|
409
|
-
// src/app/api/protected/route.ts
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* @auth bearer
|
|
413
|
-
*/
|
|
414
|
-
export async function GET() {
|
|
415
|
-
// ...
|
|
416
|
-
}
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### Deprecated
|
|
420
|
-
|
|
421
|
-
```typescript
|
|
422
|
-
// src/app/api/v1/route.ts
|
|
423
|
-
|
|
424
|
-
// Zod
|
|
425
|
-
const UserSchema = z.object({
|
|
426
|
-
id: z.string(),
|
|
427
|
-
name: z.string(),
|
|
428
|
-
fullName: z.string().optional().describe("@deprecated Use name instead"),
|
|
429
|
-
email: z.string().email(),
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
// Or TypeScript
|
|
433
|
-
type UserResponse = {
|
|
434
|
-
id: string;
|
|
435
|
-
name: string;
|
|
436
|
-
/** @deprecated Use firstName and lastName instead */
|
|
437
|
-
fullName?: string;
|
|
438
|
-
email: string;
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* @body UserSchema
|
|
443
|
-
* @response UserResponse
|
|
444
|
-
*/
|
|
445
|
-
export async function GET() {
|
|
446
|
-
// ...
|
|
447
|
-
}
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
### Custom Operation ID
|
|
451
|
-
|
|
452
|
-
```typescript
|
|
453
|
-
// src/app/api/users/[id]/route.ts
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Get user by ID
|
|
457
|
-
* @operationId getUserById
|
|
458
|
-
* @pathParams UserParams
|
|
459
|
-
* @response UserResponse
|
|
460
|
-
*/
|
|
461
|
-
export async function GET() {
|
|
462
|
-
// ...
|
|
463
|
-
}
|
|
464
|
-
// Generates: operationId: "getUserById" instead of auto-generated "get-users-{id}"
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
### File Uploads / Multipart Form Data
|
|
468
|
-
|
|
469
|
-
```typescript
|
|
470
|
-
// src/app/api/upload/route.ts
|
|
471
|
-
|
|
472
|
-
// Zod
|
|
473
|
-
const FileUploadSchema = z.object({
|
|
474
|
-
file: z.custom<File>().describe("Image file (PNG/JPG)"),
|
|
475
|
-
description: z.string().optional().describe("File description"),
|
|
476
|
-
category: z.string().describe("File category"),
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
// Or TypeScript
|
|
480
|
-
type FileUploadFormData = {
|
|
481
|
-
file: File;
|
|
482
|
-
description?: string;
|
|
483
|
-
category: string;
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* @body FileUploadSchema
|
|
488
|
-
* @contentType multipart/form-data
|
|
489
|
-
*/
|
|
490
|
-
export async function POST() {
|
|
491
|
-
// ...
|
|
492
|
-
}
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
## Response Management
|
|
496
|
-
|
|
497
|
-
### Zero Config + Response Sets
|
|
498
|
-
|
|
499
|
-
Configure reusable error sets in `next.openapi.json`:
|
|
500
|
-
|
|
501
|
-
```json
|
|
502
|
-
{
|
|
503
|
-
"defaultResponseSet": "common",
|
|
504
|
-
"responseSets": {
|
|
505
|
-
"common": ["400", "401", "500"],
|
|
506
|
-
"public": ["400", "500"],
|
|
507
|
-
"auth": ["400", "401", "403", "500"]
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
### Usage Examples
|
|
513
|
-
|
|
514
|
-
```typescript
|
|
515
|
-
/**
|
|
516
|
-
* Auto-default responses
|
|
517
|
-
* @response UserResponse
|
|
518
|
-
* @openapi
|
|
519
|
-
*/
|
|
520
|
-
export async function GET() {}
|
|
521
|
-
// Generates: 200:UserResponse + common errors (400, 401, 500)
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* With custom description inline
|
|
525
|
-
* @response UserResponse:Complete user profile information
|
|
526
|
-
* @openapi
|
|
527
|
-
*/
|
|
528
|
-
export async function GET() {}
|
|
529
|
-
// Generates: 200:UserResponse (with custom description) + common errors
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Override response set
|
|
533
|
-
* @response ProductResponse
|
|
534
|
-
* @responseSet public
|
|
535
|
-
* @openapi
|
|
536
|
-
*/
|
|
537
|
-
export async function GET() {}
|
|
538
|
-
// Generates: 200:ProductResponse + public errors (400, 500)
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* Add custom responses with description
|
|
542
|
-
* @response 201:UserResponse:User created successfully
|
|
543
|
-
* @add 409:ConflictResponse
|
|
544
|
-
* @openapi
|
|
545
|
-
*/
|
|
546
|
-
export async function POST() {}
|
|
547
|
-
// Generates: 201:UserResponse (with custom description) + common errors + 409:ConflictResponse
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Combine multiple sets
|
|
551
|
-
* @response UserResponse
|
|
552
|
-
* @responseSet auth,crud
|
|
553
|
-
* @add 429:RateLimitResponse
|
|
554
|
-
* @openapi
|
|
555
|
-
*/
|
|
556
|
-
export async function PUT() {}
|
|
557
|
-
// Combines: auth + crud errors + custom 429
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
### Error Schema Configuration
|
|
561
|
-
|
|
562
|
-
#### Define consistent error schemas using templates:
|
|
563
|
-
|
|
564
|
-
```json
|
|
565
|
-
{
|
|
566
|
-
"defaultResponseSet": "common",
|
|
567
|
-
"responseSets": {
|
|
568
|
-
"common": ["400", "500"],
|
|
569
|
-
"auth": ["400", "401", "403", "500"],
|
|
570
|
-
"public": ["400", "500"]
|
|
571
|
-
},
|
|
572
|
-
"errorConfig": {
|
|
573
|
-
"template": {
|
|
574
|
-
"type": "object",
|
|
575
|
-
"properties": {
|
|
576
|
-
"error": {
|
|
577
|
-
"type": "string",
|
|
578
|
-
"example": "{{ERROR_MESSAGE}}"
|
|
579
|
-
},
|
|
580
|
-
"code": {
|
|
581
|
-
"type": "string",
|
|
582
|
-
"example": "{{ERROR_CODE}}"
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
},
|
|
586
|
-
"codes": {
|
|
587
|
-
"400": {
|
|
588
|
-
"description": "Bad Request",
|
|
589
|
-
"variables": {
|
|
590
|
-
"ERROR_MESSAGE": "Invalid request parameters",
|
|
591
|
-
"ERROR_CODE": "BAD_REQUEST"
|
|
592
|
-
}
|
|
593
|
-
},
|
|
594
|
-
"401": {
|
|
595
|
-
"description": "Unauthorized",
|
|
596
|
-
"variables": {
|
|
597
|
-
"ERROR_MESSAGE": "Authentication required",
|
|
598
|
-
"ERROR_CODE": "UNAUTHORIZED"
|
|
599
|
-
}
|
|
600
|
-
},
|
|
601
|
-
"403": {
|
|
602
|
-
"description": "Forbidden",
|
|
603
|
-
"variables": {
|
|
604
|
-
"ERROR_MESSAGE": "Access denied",
|
|
605
|
-
"ERROR_CODE": "FORBIDDEN"
|
|
606
|
-
}
|
|
607
|
-
},
|
|
608
|
-
"404": {
|
|
609
|
-
"description": "Not Found",
|
|
610
|
-
"variables": {
|
|
611
|
-
"ERROR_MESSAGE": "Resource not found",
|
|
612
|
-
"ERROR_CODE": "NOT_FOUND"
|
|
613
|
-
}
|
|
614
|
-
},
|
|
615
|
-
"500": {
|
|
616
|
-
"description": "Internal Server Error",
|
|
617
|
-
"variables": {
|
|
618
|
-
"ERROR_MESSAGE": "An unexpected error occurred",
|
|
619
|
-
"ERROR_CODE": "INTERNAL_ERROR"
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
## Ignoring Routes
|
|
628
|
-
|
|
629
|
-
You can exclude routes from OpenAPI documentation in two ways:
|
|
630
|
-
|
|
631
|
-
### Using @ignore Tag
|
|
632
|
-
|
|
633
|
-
Add the `@ignore` tag to any route you want to exclude:
|
|
634
|
-
|
|
635
|
-
```typescript
|
|
636
|
-
// src/app/api/internal/route.ts
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* Internal route - not for documentation
|
|
640
|
-
* @ignore
|
|
641
|
-
*/
|
|
642
|
-
export async function GET() {
|
|
643
|
-
// This route will not appear in OpenAPI documentation
|
|
644
|
-
}
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
### Using ignoreRoutes Configuration
|
|
648
|
-
|
|
649
|
-
Add patterns to your `next.openapi.json` configuration file to exclude multiple routes at once:
|
|
650
|
-
|
|
651
|
-
```json
|
|
652
|
-
{
|
|
653
|
-
"openapi": "3.0.0",
|
|
654
|
-
"info": {
|
|
655
|
-
"title": "Next.js API",
|
|
656
|
-
"version": "1.0.0"
|
|
657
|
-
},
|
|
658
|
-
"apiDir": "src/app/api",
|
|
659
|
-
"ignoreRoutes": ["/internal/*", "/debug", "/admin/test/*"]
|
|
660
|
-
}
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
Pattern matching supports wildcards:
|
|
664
|
-
|
|
665
|
-
- `/internal/*` - Ignores all routes under `/internal/`
|
|
666
|
-
- `/debug` - Ignores only the `/debug` route
|
|
667
|
-
- `/admin/*/temp` - Ignores routes like `/admin/users/temp`, `/admin/posts/temp`
|
|
668
|
-
|
|
669
|
-
## Advanced Usage
|
|
670
|
-
|
|
671
|
-
### Automatic Path Parameter Detection
|
|
672
|
-
|
|
673
|
-
The library automatically detects path parameters and generates documentation for them:
|
|
674
|
-
|
|
675
|
-
```typescript
|
|
676
|
-
// src/app/api/users/[id]/posts/[postId]/route.ts
|
|
677
|
-
|
|
678
|
-
// Will automatically detect 'id' and 'postId' parameters
|
|
679
|
-
export async function GET() {
|
|
680
|
-
// ...
|
|
681
|
-
}
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
If no type/schema is provided for path parameters, a default schema will be generated.
|
|
685
|
-
|
|
686
|
-
### Intelligent Examples
|
|
687
|
-
|
|
688
|
-
The library generates intelligent examples for parameters based on their name:
|
|
689
|
-
|
|
690
|
-
| Parameter name | Example |
|
|
691
|
-
| -------------- | ---------------------------------------- |
|
|
692
|
-
| `id`, `*Id` | `"123"` or `123` |
|
|
693
|
-
| `slug` | `"example-slug"` |
|
|
694
|
-
| `uuid` | `"123e4567-e89b-12d3-a456-426614174000"` |
|
|
695
|
-
| `email` | `"user@example.com"` |
|
|
696
|
-
| `name` | `"example-name"` |
|
|
697
|
-
| `date` | `"2023-01-01"` |
|
|
698
|
-
|
|
699
|
-
### TypeScript Generics Support
|
|
700
|
-
|
|
701
|
-
The library supports TypeScript generic types and automatically resolves them during documentation generation:
|
|
702
|
-
|
|
703
|
-
```typescript
|
|
704
|
-
// src/app/api/llms/route.ts
|
|
705
|
-
|
|
706
|
-
import { NextResponse } from "next/server";
|
|
707
|
-
|
|
708
|
-
// Define generic response wrapper
|
|
709
|
-
type MyApiSuccessResponseBody<T> = T & {
|
|
710
|
-
success: true;
|
|
711
|
-
httpCode: string;
|
|
712
|
-
};
|
|
713
|
-
|
|
714
|
-
// Define specific response data
|
|
715
|
-
type LLMSResponse = {
|
|
716
|
-
llms: Array<{
|
|
717
|
-
id: string;
|
|
718
|
-
name: string;
|
|
719
|
-
provider: string;
|
|
720
|
-
isDefault: boolean;
|
|
721
|
-
}>;
|
|
722
|
-
};
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Get list of available LLMs
|
|
726
|
-
* @description Get list of available LLMs with success wrapper
|
|
727
|
-
* @response 200:MyApiSuccessResponseBody<LLMSResponse>
|
|
728
|
-
* @openapi
|
|
729
|
-
*/
|
|
730
|
-
export async function GET() {
|
|
731
|
-
return NextResponse.json({
|
|
732
|
-
success: true,
|
|
733
|
-
httpCode: "200",
|
|
734
|
-
llms: [
|
|
735
|
-
{
|
|
736
|
-
id: "gpt-5",
|
|
737
|
-
name: "GPT-5",
|
|
738
|
-
provider: "OpenAI",
|
|
739
|
-
isDefault: true,
|
|
740
|
-
},
|
|
741
|
-
],
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
```
|
|
745
|
-
|
|
746
|
-
### TypeScript Utility Types Support
|
|
747
|
-
|
|
748
|
-
The library supports TypeScript utility types for extracting types from functions:
|
|
749
|
-
|
|
750
|
-
```typescript
|
|
751
|
-
// src/app/api/products/route.utils.ts
|
|
752
|
-
export async function getProductById(id: string): Promise<{
|
|
753
|
-
product: Product;
|
|
754
|
-
fetchedAt: string;
|
|
755
|
-
}> {
|
|
756
|
-
// Implementation...
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
export function createProduct(
|
|
760
|
-
data: { name: string; price: number },
|
|
761
|
-
options: { notify: boolean }
|
|
762
|
-
): { success: boolean; productId: string } {
|
|
763
|
-
// Implementation...
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// src/types/product-types.ts
|
|
767
|
-
|
|
768
|
-
// Extract return type from async functions
|
|
769
|
-
export type ProductResponse = Awaited<ReturnType<typeof getProductById>>;
|
|
770
|
-
|
|
771
|
-
// Extract return type from sync functions
|
|
772
|
-
export type CreateResult = ReturnType<typeof createProduct>;
|
|
773
|
-
|
|
774
|
-
// Extract parameter types as tuple
|
|
775
|
-
export type CreateProductParams = Parameters<typeof createProduct>;
|
|
776
|
-
|
|
777
|
-
// Extract specific parameter using indexed access
|
|
778
|
-
export type ProductData = Parameters<typeof createProduct>[0];
|
|
779
|
-
export type ProductOptions = Parameters<typeof createProduct>[1];
|
|
780
|
-
|
|
781
|
-
// Use with generic types
|
|
782
|
-
interface ApiResponse<T> {
|
|
783
|
-
success: boolean;
|
|
784
|
-
data: T;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
export type ProductApiResponse = ApiResponse<ProductResponse>;
|
|
788
|
-
|
|
789
|
-
/**
|
|
790
|
-
* @response ProductApiResponse
|
|
791
|
-
* @openapi
|
|
792
|
-
*/
|
|
793
|
-
export async function GET() {
|
|
794
|
-
// Fully typed response automatically documented
|
|
795
|
-
}
|
|
796
|
-
```
|
|
797
|
-
|
|
798
|
-
**Supported utility types:**
|
|
799
|
-
- `Awaited<T>` - Unwraps Promise types
|
|
800
|
-
- `ReturnType<typeof func>` - Extracts function return type
|
|
801
|
-
- `Parameters<typeof func>` - Extracts function parameters as tuple
|
|
802
|
-
- `Parameters<typeof func>[N]` - Indexed access to specific parameter
|
|
803
|
-
- Generic interfaces like `ApiResponse<T>` with type parameter substitution
|
|
804
|
-
|
|
805
|
-
## Advanced Zod Features
|
|
806
|
-
|
|
807
|
-
The library supports advanced Zod features such as:
|
|
808
|
-
|
|
809
|
-
### Validation Chains
|
|
810
|
-
|
|
811
|
-
```typescript
|
|
812
|
-
// Zod validation chains are properly converted to OpenAPI schemas
|
|
813
|
-
const EmailSchema = z
|
|
814
|
-
.string()
|
|
815
|
-
.email()
|
|
816
|
-
.min(5)
|
|
817
|
-
.max(100)
|
|
818
|
-
.describe("Email address");
|
|
819
|
-
|
|
820
|
-
// Converts to OpenAPI with email format, minLength and maxLength
|
|
821
|
-
```
|
|
822
|
-
|
|
823
|
-
### Type Aliases with z.infer
|
|
824
|
-
|
|
825
|
-
```typescript
|
|
826
|
-
// You can use TypeScript with Zod types
|
|
827
|
-
import { z } from "zod";
|
|
828
|
-
|
|
829
|
-
const UserSchema = z.object({
|
|
830
|
-
id: z.string().uuid(),
|
|
831
|
-
name: z.string().min(2),
|
|
832
|
-
});
|
|
833
|
-
|
|
834
|
-
// Use z.infer to create a TypeScript type
|
|
835
|
-
type User = z.infer<typeof UserSchema>;
|
|
836
|
-
|
|
837
|
-
// The library will be able to recognize this schema by reference `UserSchema` or `User` type.
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
### Factory Functions (Schema Generators)
|
|
841
|
-
|
|
842
|
-
The library automatically detects and expands Zod factory functions - any function that returns a Zod schema:
|
|
843
|
-
|
|
844
|
-
```typescript
|
|
845
|
-
// Define reusable schema factory
|
|
846
|
-
export function createPaginatedSchema<T extends z.ZodTypeAny>(dataSchema: T) {
|
|
847
|
-
return z.object({
|
|
848
|
-
data: z.array(dataSchema).describe("Array of items"),
|
|
849
|
-
pagination: z.object({
|
|
850
|
-
nextCursor: z.string().nullable(),
|
|
851
|
-
hasMore: z.boolean(),
|
|
852
|
-
limit: z.number().int().positive(),
|
|
853
|
-
}),
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// Use in your schemas - automatically expanded in OpenAPI
|
|
858
|
-
export const PaginatedUsersSchema = createPaginatedSchema(UserSchema);
|
|
859
|
-
export const PaginatedProductsSchema = createPaginatedSchema(ProductSchema);
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
Factory functions work with any naming convention and support:
|
|
863
|
-
- Generic type parameters
|
|
864
|
-
- Inline schemas as arguments
|
|
865
|
-
- Imported schemas
|
|
866
|
-
- Multiple factory patterns in the same project
|
|
867
|
-
|
|
868
|
-
### Schema Composition with `.extend()`
|
|
869
|
-
|
|
870
|
-
Zod's `.extend()` method allows you to build upon existing schemas:
|
|
871
|
-
|
|
872
|
-
```typescript
|
|
873
|
-
// src/schemas/user.ts
|
|
874
|
-
|
|
875
|
-
// Base user schema
|
|
876
|
-
export const BaseUserSchema = z.object({
|
|
877
|
-
id: z.string().uuid().describe("User ID"),
|
|
878
|
-
email: z.string().email().describe("Email address"),
|
|
879
|
-
});
|
|
880
|
-
|
|
881
|
-
// Extend with additional fields
|
|
882
|
-
export const UserProfileSchema = BaseUserSchema.extend({
|
|
883
|
-
name: z.string().describe("Full name"),
|
|
884
|
-
bio: z.string().optional().describe("User biography"),
|
|
885
|
-
});
|
|
886
|
-
|
|
887
|
-
// Multiple levels of extension
|
|
888
|
-
export const AdminUserSchema = UserProfileSchema.extend({
|
|
889
|
-
role: z.enum(["admin", "moderator"]).describe("Admin role"),
|
|
890
|
-
permissions: z.array(z.string()).describe("Permission list"),
|
|
891
|
-
});
|
|
892
|
-
|
|
893
|
-
export const UserIdParams = z.object({
|
|
894
|
-
id: z.string().uuid().describe("User ID"),
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
// src/app/api/users/[id]/route.ts
|
|
898
|
-
|
|
899
|
-
/**
|
|
900
|
-
* Get user profile
|
|
901
|
-
* @pathParams UserIdParams
|
|
902
|
-
* @response UserProfileSchema
|
|
903
|
-
* @openapi
|
|
904
|
-
*/
|
|
905
|
-
export async function GET(
|
|
906
|
-
request: NextRequest,
|
|
907
|
-
{ params }: { params: { id: string } }
|
|
908
|
-
) {
|
|
909
|
-
// Returns: { id, email, name, bio? }
|
|
910
|
-
}
|
|
911
|
-
```
|
|
912
|
-
|
|
913
|
-
### Drizzle-Zod Support
|
|
914
|
-
|
|
915
|
-
The library fully supports **drizzle-zod** for generating Zod schemas from Drizzle ORM table definitions. This provides a single source of truth for your database schema, validation, and API documentation.
|
|
916
|
-
|
|
917
|
-
**Supported Functions:**
|
|
918
|
-
|
|
919
|
-
- `createInsertSchema()` - Generate schema for inserts
|
|
920
|
-
- `createSelectSchema()` - Generate schema for selects
|
|
921
|
-
- `createUpdateSchema()` - Generate schema for updates
|
|
922
|
-
|
|
923
|
-
**Features:**
|
|
924
|
-
|
|
925
|
-
- ✅ Automatic field extraction from refinements
|
|
926
|
-
- ✅ Validation method conversion (min, max, email, url, etc.)
|
|
927
|
-
- ✅ Optional/nullable field detection
|
|
928
|
-
- ✅ Intelligent type mapping based on field names
|
|
929
|
-
- ✅ Full OpenAPI schema generation
|
|
930
|
-
|
|
931
|
-
**Example:**
|
|
932
|
-
|
|
933
|
-
```typescript
|
|
934
|
-
import { createInsertSchema } from "drizzle-zod";
|
|
935
|
-
import { posts } from "@/db/schema";
|
|
936
|
-
|
|
937
|
-
export const CreatePostSchema = createInsertSchema(posts, {
|
|
938
|
-
title: (schema) => schema.title.min(5).max(255),
|
|
939
|
-
content: (schema) => schema.content.min(10),
|
|
940
|
-
published: (schema) => schema.published.optional(),
|
|
941
|
-
});
|
|
942
|
-
```
|
|
943
|
-
|
|
944
|
-
See the [complete Drizzle-Zod example](./examples/next15-app-drizzle-zod) for a full working implementation with a blog API.
|
|
945
|
-
|
|
946
|
-
## Multiple Schema Types Support 🆕
|
|
947
|
-
|
|
948
|
-
Use **multiple schema types simultaneously** in a single project - perfect for gradual migrations, combining hand-written schemas with generated ones (protobuf, GraphQL), or using existing OpenAPI specs.
|
|
949
|
-
|
|
950
|
-
### Configuration
|
|
951
|
-
|
|
952
|
-
```json
|
|
953
|
-
{
|
|
954
|
-
"schemaType": ["zod", "typescript"],
|
|
955
|
-
"schemaDir": "./src/schemas",
|
|
956
|
-
"schemaFiles": ["./schemas/external-api.yaml"]
|
|
957
|
-
}
|
|
958
|
-
```
|
|
959
|
-
|
|
960
|
-
### Schema Resolution Priority
|
|
961
|
-
|
|
962
|
-
1. **Custom files** (highest) - from `schemaFiles` array
|
|
963
|
-
2. **Zod schemas** (medium) - if `"zod"` in `schemaType`
|
|
964
|
-
3. **TypeScript types** (fallback) - if `"typescript"` in `schemaType`
|
|
965
|
-
|
|
966
|
-
### Common Use Cases
|
|
967
|
-
|
|
968
|
-
```json
|
|
969
|
-
// Gradual TypeScript → Zod migration
|
|
970
|
-
{ "schemaType": ["zod", "typescript"] }
|
|
971
|
-
|
|
972
|
-
// Zod + protobuf schemas
|
|
973
|
-
{
|
|
974
|
-
"schemaType": ["zod"],
|
|
975
|
-
"schemaFiles": ["./proto/schemas.yaml"]
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// Everything together
|
|
979
|
-
{
|
|
980
|
-
"schemaType": ["zod", "typescript"],
|
|
981
|
-
"schemaFiles": ["./openapi-models.yaml"]
|
|
982
|
-
}
|
|
983
|
-
```
|
|
984
|
-
|
|
985
|
-
Custom schema files support YAML/JSON in OpenAPI 3.0 format. See **[next15-app-mixed-schemas](./examples/next15-app-mixed-schemas)** for a complete working example.
|
|
986
|
-
|
|
987
|
-
## Examples
|
|
988
|
-
|
|
989
|
-
Explore complete demo projects in the **[examples](./examples/)** directory, covering integrations with Zod, TypeScript, Drizzle and documentation tools like Scalar and Swagger.
|
|
990
|
-
|
|
991
|
-
### 🚀 Run an Example
|
|
992
|
-
|
|
993
|
-
```bash
|
|
994
|
-
cd examples/next15-app-zod
|
|
995
|
-
npm install
|
|
996
|
-
npx next-openapi-gen generate
|
|
997
|
-
npm run dev
|
|
998
|
-
```
|
|
999
|
-
|
|
1000
|
-
Then open `http://localhost:3000/api-docs` to view the generated docs.
|
|
1001
|
-
|
|
1002
|
-
## Available UI providers
|
|
1003
|
-
|
|
1004
|
-
<div align="center">
|
|
1005
|
-
<table>
|
|
1006
|
-
<thead>
|
|
1007
|
-
<th>Scalar</th>
|
|
1008
|
-
<th>Swagger</th>
|
|
1009
|
-
<th>Redoc</th>
|
|
1010
|
-
<th>Stoplight Elements</th>
|
|
1011
|
-
<th>RapiDoc</th>
|
|
1012
|
-
</thead>
|
|
1013
|
-
<tbody>
|
|
1014
|
-
<tr>
|
|
1015
|
-
<td>
|
|
1016
|
-
<img width="320" alt="scalar" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/scalar.png" alt-text="scalar">
|
|
1017
|
-
</td>
|
|
1018
|
-
<td>
|
|
1019
|
-
<img width="320" alt="swagger" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/swagger.png" alt-text="swagger">
|
|
1020
|
-
</td>
|
|
1021
|
-
<td>
|
|
1022
|
-
<img width="320" alt="redoc" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/redoc.png" alt-text="redoc">
|
|
1023
|
-
</td>
|
|
1024
|
-
<td>
|
|
1025
|
-
<img width="320" alt="stoplight" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/stoplight.png" alt-text="stoplight">
|
|
1026
|
-
</td>
|
|
1027
|
-
<td>
|
|
1028
|
-
<img width="320" alt="rapidoc" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/rapidoc.png" alt-text="rapidoc">
|
|
1029
|
-
</td>
|
|
1030
|
-
</tr>
|
|
1031
|
-
</tbody>
|
|
1032
|
-
</table>
|
|
1033
|
-
</div>
|
|
1034
|
-
|
|
1035
|
-
## Contributing
|
|
1036
|
-
|
|
1037
|
-
We welcome contributions! 🎉
|
|
1038
|
-
|
|
1039
|
-
Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
1040
|
-
|
|
1041
|
-
## Changelog
|
|
1042
|
-
|
|
1043
|
-
See [CHANGELOG.md](CHANGELOG.md) for release history and changes.
|
|
1044
|
-
|
|
1045
|
-
## License
|
|
1046
|
-
|
|
1047
|
-
MIT
|
|
1
|
+
# next-openapi-gen
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/next-openapi-gen)
|
|
4
|
+
[](https://github.com/tazo90/next-openapi-gen/actions/workflows/ci.yml)
|
|
5
|
+
[](https://github.com/tazo90/next-openapi-gen)
|
|
6
|
+
|
|
7
|
+
Generate OpenAPI `3.0`, `3.1`, and `3.2` from the routes and schemas you already have.
|
|
8
|
+
|
|
9
|
+
`next-openapi-gen` scans Next.js, TanStack Router, and React Router route handlers, reads JSDoc metadata, and generates an OpenAPI spec plus an optional docs UI. It is built for real codebases that use Zod, TypeScript, drizzle-zod, or reusable OpenAPI fragments, including mixed-schema migrations.
|
|
10
|
+
|
|
11
|
+
[Quick start](#quick-start) • [Docs index](./docs/README.md) • [Example apps](#example-apps) • [Validation and coverage](#validation-and-coverage)
|
|
12
|
+
|
|
13
|
+
## Why teams use it
|
|
14
|
+
|
|
15
|
+
- Keep OpenAPI close to your handlers instead of maintaining a separate manual spec.
|
|
16
|
+
- Reuse existing `zod`, `typescript`, `drizzle-zod`, and YAML/JSON OpenAPI fragments in one pipeline.
|
|
17
|
+
- Target `3.0`, `3.1`, or `3.2` from the same route metadata with version-aware finalization.
|
|
18
|
+
- Ship interactive docs quickly with built-in UI scaffolding for Scalar, Swagger, Redoc, Stoplight Elements, or RapiDoc.
|
|
19
|
+
- Fall back on checker-assisted App Router response inference when explicit `@response` tags are missing.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
### Requirements
|
|
24
|
+
|
|
25
|
+
- Node.js `>=24`
|
|
26
|
+
- A supported app framework:
|
|
27
|
+
- Next.js using App Router or Pages Router
|
|
28
|
+
- TanStack Router
|
|
29
|
+
- React Router
|
|
30
|
+
|
|
31
|
+
### Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pnpm add -D next-openapi-gen
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install --save-dev next-openapi-gen
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
yarn add --dev next-openapi-gen
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Initialize and generate
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Next.js is the default framework
|
|
49
|
+
pnpm exec openapi-gen init
|
|
50
|
+
|
|
51
|
+
# Or choose another supported framework
|
|
52
|
+
pnpm exec openapi-gen init --framework tanstack
|
|
53
|
+
pnpm exec openapi-gen init --framework react-router
|
|
54
|
+
|
|
55
|
+
# Scans your routes and writes the spec once
|
|
56
|
+
pnpm exec openapi-gen generate
|
|
57
|
+
|
|
58
|
+
# Keeps the spec fresh during local development
|
|
59
|
+
pnpm exec openapi-gen generate --watch
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
> [!TIP]
|
|
63
|
+
> Use `--ui none` during `init` if you only want the generated OpenAPI file.
|
|
64
|
+
>
|
|
65
|
+
> The package name is still `next-openapi-gen` during the transition. Config
|
|
66
|
+
> discovery also accepts the new `openapi-gen.config.ts` and
|
|
67
|
+
> `openapi-gen.config.json` aliases, while `next-openapi.config.*` and
|
|
68
|
+
> `next.openapi.json` continue to work with deprecation warnings. The legacy
|
|
69
|
+
> `next-openapi-gen` binary still works too, but `openapi-gen` is the preferred
|
|
70
|
+
> CLI name going forward.
|
|
71
|
+
|
|
72
|
+
Need the full setup flow, config walkthrough, or production notes? See
|
|
73
|
+
[docs/getting-started.md](./docs/getting-started.md).
|
|
74
|
+
|
|
75
|
+
### What you get
|
|
76
|
+
|
|
77
|
+
- `next.openapi.json` in your project root
|
|
78
|
+
- `public/openapi.json` by default
|
|
79
|
+
- `/api-docs` with your selected UI provider by default
|
|
80
|
+
|
|
81
|
+
## Framework support
|
|
82
|
+
|
|
83
|
+
| Framework | Setup path | Notes |
|
|
84
|
+
| --------------- | ----------------------------------------------------- | -------------------------------------------------------------- |
|
|
85
|
+
| Next.js | `pnpm exec openapi-gen init` | Supports App Router and Pages Router |
|
|
86
|
+
| TanStack Router | `pnpm exec openapi-gen init --framework tanstack` | Uses the public `next-openapi-gen/vite` plugin surface |
|
|
87
|
+
| React Router | `pnpm exec openapi-gen init --framework react-router` | Uses the public `next-openapi-gen/react-router` plugin surface |
|
|
88
|
+
|
|
89
|
+
## Minimal example
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { NextRequest } from "next/server";
|
|
93
|
+
import { z } from "zod";
|
|
94
|
+
|
|
95
|
+
export const ProductParams = z.object({
|
|
96
|
+
id: z.string().describe("Product ID"),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export const ProductResponse = z.object({
|
|
100
|
+
id: z.string(),
|
|
101
|
+
name: z.string(),
|
|
102
|
+
price: z.number().positive(),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get product information
|
|
107
|
+
* @description Fetch a product by ID
|
|
108
|
+
* @pathParams ProductParams
|
|
109
|
+
* @response ProductResponse
|
|
110
|
+
* @openapi
|
|
111
|
+
*/
|
|
112
|
+
export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
|
|
113
|
+
return Response.json({ id: params.id, name: "Keyboard", price: 99 });
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Why `next-openapi-gen` is different
|
|
118
|
+
|
|
119
|
+
| Capability | Why it matters |
|
|
120
|
+
| ------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| Framework-aware route scanning | Covers Next.js, TanStack Router, and React Router with one generator and shared docs story. |
|
|
122
|
+
| Mixed schema sources | Combine `zod`, `typescript`, `schemaFiles`, and drizzle-zod-backed schemas during gradual migrations. |
|
|
123
|
+
| OpenAPI `3.0` / `3.1` / `3.2` targets | Keep one authoring flow while emitting version-aware output for newer spec features. |
|
|
124
|
+
| Response inference | Infer typed App Router responses when `@response` is omitted, while still letting explicit tags win. |
|
|
125
|
+
| Docs UI scaffolding | Generate a docs page fast instead of stopping at a JSON file. |
|
|
126
|
+
|
|
127
|
+
## Common workflows
|
|
128
|
+
|
|
129
|
+
### Start with Zod or TypeScript
|
|
130
|
+
|
|
131
|
+
Use one schema system if your app is already consistent:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"schemaType": "zod",
|
|
136
|
+
"schemaDir": "src/schemas"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Migrate gradually with mixed schema sources
|
|
141
|
+
|
|
142
|
+
Use multiple schema types in the same project when you are moving from TypeScript to Zod or merging generated and hand-authored schemas:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"schemaType": ["zod", "typescript"],
|
|
147
|
+
"schemaDir": "./src/schemas",
|
|
148
|
+
"schemaFiles": ["./schemas/external-api.yaml"]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Resolution priority is:
|
|
153
|
+
|
|
154
|
+
1. `schemaFiles`
|
|
155
|
+
2. `zod`
|
|
156
|
+
3. `typescript`
|
|
157
|
+
|
|
158
|
+
See [apps/next-app-mixed-schemas](./apps/next-app-mixed-schemas) for a full working example.
|
|
159
|
+
For more adoption patterns, see
|
|
160
|
+
[docs/workflows-and-integrations.md](./docs/workflows-and-integrations.md).
|
|
161
|
+
|
|
162
|
+
### Generate docs from Drizzle schemas
|
|
163
|
+
|
|
164
|
+
`next-openapi-gen` works well with `drizzle-zod`, so your database schema, validation, and API docs can share the same source of truth.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
|
168
|
+
import { posts } from "@/db/schema";
|
|
169
|
+
|
|
170
|
+
export const CreatePostSchema = createInsertSchema(posts, {
|
|
171
|
+
title: (schema) => schema.title.min(5).max(255),
|
|
172
|
+
content: (schema) => schema.content.min(10),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
export const PostResponseSchema = createSelectSchema(posts);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
See [apps/next-app-drizzle-zod](./apps/next-app-drizzle-zod) for the full CRUD example.
|
|
179
|
+
|
|
180
|
+
### Rely on inference when you want less annotation
|
|
181
|
+
|
|
182
|
+
If you omit `@response`, App Router handlers can infer responses from typed `NextResponse.json(...)` and `Response.json(...)` returns.
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import { NextResponse } from "next/server";
|
|
186
|
+
|
|
187
|
+
type SearchResponse = {
|
|
188
|
+
total: number;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Search events
|
|
193
|
+
* @responseDescription Search result
|
|
194
|
+
* @openapi
|
|
195
|
+
*/
|
|
196
|
+
export async function POST(): Promise<NextResponse<SearchResponse>> {
|
|
197
|
+
return NextResponse.json({ total: 3 });
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Explicit `@response` tags still take precedence when you want stable schema names or exact response codes.
|
|
202
|
+
|
|
203
|
+
## Configuration
|
|
204
|
+
|
|
205
|
+
`init` creates a `next.openapi.json` file like this:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"openapi": "3.0.0",
|
|
210
|
+
"info": {
|
|
211
|
+
"title": "Next.js API",
|
|
212
|
+
"version": "1.0.0",
|
|
213
|
+
"description": "API generated by next-openapi-gen"
|
|
214
|
+
},
|
|
215
|
+
"apiDir": "src/app/api",
|
|
216
|
+
"routerType": "app",
|
|
217
|
+
"schemaDir": "src/schemas",
|
|
218
|
+
"schemaType": "zod",
|
|
219
|
+
"schemaFiles": [],
|
|
220
|
+
"outputFile": "openapi.json",
|
|
221
|
+
"outputDir": "./public",
|
|
222
|
+
"docsUrl": "api-docs",
|
|
223
|
+
"includeOpenApiRoutes": false,
|
|
224
|
+
"ignoreRoutes": [],
|
|
225
|
+
"debug": false
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Version guidance:
|
|
230
|
+
|
|
231
|
+
- Use `3.0.0` when you want the broadest downstream tooling compatibility.
|
|
232
|
+
- Use `3.1.0` when you want JSON Schema 2020-12-aligned output such as `jsonSchemaDialect`.
|
|
233
|
+
- Use `3.2.0` when you want first-class `querystring`, enhanced tag metadata, sequential media, and richer example objects.
|
|
234
|
+
|
|
235
|
+
### Important options
|
|
236
|
+
|
|
237
|
+
| Option | Purpose |
|
|
238
|
+
| ------------------------------------- | ---------------------------------------------------------------- |
|
|
239
|
+
| `openapi` | Target `3.0.0`, `3.1.0`, or `3.2.0` output |
|
|
240
|
+
| `apiDir` | Route directory to scan |
|
|
241
|
+
| `routerType` | `"app"` or `"pages"` |
|
|
242
|
+
| `schemaDir` | Directory or directories to search for schemas/types |
|
|
243
|
+
| `schemaType` | `"zod"`, `"typescript"`, or both |
|
|
244
|
+
| `schemaFiles` | YAML/JSON OpenAPI fragments to merge into the generated document |
|
|
245
|
+
| `includeOpenApiRoutes` | Only include handlers tagged with `@openapi` |
|
|
246
|
+
| `ignoreRoutes` | Exclude routes with wildcard support |
|
|
247
|
+
| `defaultResponseSet` / `responseSets` | Reusable error-response groups |
|
|
248
|
+
| `errorConfig` | Shared error schema templates |
|
|
249
|
+
|
|
250
|
+
For a fuller setup guide, Pages Router notes, response sets, and route exclusion
|
|
251
|
+
patterns, see [docs/getting-started.md](./docs/getting-started.md).
|
|
252
|
+
|
|
253
|
+
## JSDoc tags you will use most
|
|
254
|
+
|
|
255
|
+
| Tag | Purpose |
|
|
256
|
+
| -------------------------- | ---------------------------------------------------------------- |
|
|
257
|
+
| `@pathParams` | Path parameter schema or type |
|
|
258
|
+
| `@params` / `@queryParams` | Query parameter schema or type |
|
|
259
|
+
| `@body` | Request body schema or type |
|
|
260
|
+
| `@response` | Response schema, code, and optional description |
|
|
261
|
+
| `@responseDescription` | Response description without redefining the schema |
|
|
262
|
+
| `@auth` | Security requirement(s), including comma-separated alternatives |
|
|
263
|
+
| `@contentType` | Request content type such as `multipart/form-data` |
|
|
264
|
+
| `@examples` | Request, response, and querystring examples |
|
|
265
|
+
| `@openapi` | Explicit inclusion marker when `includeOpenApiRoutes` is enabled |
|
|
266
|
+
| `@ignore` | Exclude a route from generation |
|
|
267
|
+
| `@method` | Required HTTP method tag for Pages Router handlers |
|
|
268
|
+
|
|
269
|
+
For the complete tag guide and usage recipes, see
|
|
270
|
+
[docs/jsdoc-reference.md](./docs/jsdoc-reference.md).
|
|
271
|
+
|
|
272
|
+
OpenAPI `3.2`-specific tags such as `@querystring`, `@tagSummary`, `@tagKind`,
|
|
273
|
+
and sequential media annotations are documented in the same guide and shown in
|
|
274
|
+
[apps/next-app-zod](./apps/next-app-zod).
|
|
275
|
+
|
|
276
|
+
## Compatibility
|
|
277
|
+
|
|
278
|
+
| Area | Support |
|
|
279
|
+
| --------------- | ------------------------------------------------------------ |
|
|
280
|
+
| Frameworks | Next.js, TanStack Router, React Router |
|
|
281
|
+
| Next.js routers | App Router and Pages Router |
|
|
282
|
+
| OpenAPI targets | `3.0`, `3.1`, `3.2` |
|
|
283
|
+
| Schema sources | `zod`, `typescript`, drizzle-zod output, YAML/JSON fragments |
|
|
284
|
+
| Docs UIs | Scalar, Swagger, Redoc, Stoplight Elements, RapiDoc |
|
|
285
|
+
|
|
286
|
+
For Pages Router projects, set `routerType` to `"pages"` and annotate handlers with `@method`. See [apps/next-pages-router](./apps/next-pages-router).
|
|
287
|
+
|
|
288
|
+
For the supported Zod 4 surface and known gaps, see
|
|
289
|
+
[docs/zod4-support-matrix.md](./docs/zod4-support-matrix.md).
|
|
290
|
+
|
|
291
|
+
## Framework integrations
|
|
292
|
+
|
|
293
|
+
Use the integration that matches your framework:
|
|
294
|
+
|
|
295
|
+
- `next-openapi-gen/next`: Next.js adapter helpers such as `createNextOpenApiAdapter`
|
|
296
|
+
- `next-openapi-gen/vite`: Vite plugin surface used by the TanStack example app
|
|
297
|
+
- `next-openapi-gen/react-router`: React Router plugin surface
|
|
298
|
+
|
|
299
|
+
The main package export also exposes `generateProject`, `watchProject`, and
|
|
300
|
+
config helpers when you want to script generation directly.
|
|
301
|
+
|
|
302
|
+
## Example apps
|
|
303
|
+
|
|
304
|
+
Use the checked-in examples to evaluate the tool in realistic setups:
|
|
305
|
+
|
|
306
|
+
- [apps/next-app-zod](./apps/next-app-zod): Zod-first App Router example
|
|
307
|
+
- [apps/next-app-next-config](./apps/next-app-next-config): typed config example targeting OpenAPI `3.1`
|
|
308
|
+
- [apps/next-app-typescript](./apps/next-app-typescript): TypeScript-first example
|
|
309
|
+
- [apps/next-app-mixed-schemas](./apps/next-app-mixed-schemas): mixed schema migration example
|
|
310
|
+
- [apps/next-app-drizzle-zod](./apps/next-app-drizzle-zod): Drizzle + drizzle-zod CRUD example
|
|
311
|
+
- [apps/next-app-sandbox](./apps/next-app-sandbox): edge-case route and exclusion playground
|
|
312
|
+
- [apps/next-app-ts-config](./apps/next-app-ts-config): typed config loading example
|
|
313
|
+
- [apps/next-app-adapter](./apps/next-app-adapter): Next adapter integration smoke example
|
|
314
|
+
- [apps/next-pages-router](./apps/next-pages-router): legacy Pages Router support
|
|
315
|
+
- [apps/tanstack-app](./apps/tanstack-app): TanStack Router framework parity example
|
|
316
|
+
- [apps/react-router-app](./apps/react-router-app): React Router framework parity example
|
|
317
|
+
- [apps/next-app-scalar](./apps/next-app-scalar), [apps/next-app-swagger](./apps/next-app-swagger): docs UI variants
|
|
318
|
+
|
|
319
|
+
### Run an example
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
pnpm install
|
|
323
|
+
cd apps/next-app-zod
|
|
324
|
+
pnpm exec openapi-gen generate
|
|
325
|
+
pnpm dev
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Then open `http://localhost:3000/api-docs`.
|
|
329
|
+
|
|
330
|
+
## Validation and coverage
|
|
331
|
+
|
|
332
|
+
This repo is not just a demo. The CI pipeline covers:
|
|
333
|
+
|
|
334
|
+
- formatting and linting
|
|
335
|
+
- workspace builds
|
|
336
|
+
- unit tests
|
|
337
|
+
- integration tests
|
|
338
|
+
- coverage reporting
|
|
339
|
+
- Playwright E2E runs across an app matrix
|
|
340
|
+
|
|
341
|
+
For the detailed version matrix and validation notes, see:
|
|
342
|
+
|
|
343
|
+
- [docs/openapi-version-coverage.md](./docs/openapi-version-coverage.md)
|
|
344
|
+
- [docs/zod4-support-matrix.md](./docs/zod4-support-matrix.md)
|
|
345
|
+
|
|
346
|
+
The checked-in examples intentionally span different goals: most apps stay on
|
|
347
|
+
`3.0` as the conservative default, `apps/next-app-next-config` demonstrates a
|
|
348
|
+
typed `3.1` config, and `apps/next-app-zod` showcases richer `3.2` route and
|
|
349
|
+
document features.
|
|
350
|
+
|
|
351
|
+
## Available UI providers
|
|
352
|
+
|
|
353
|
+
| Scalar | Swagger | Redoc | Stoplight Elements | RapiDoc |
|
|
354
|
+
| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
355
|
+
|  |  |  |  |  |
|
|
356
|
+
|
|
357
|
+
## Advanced docs
|
|
358
|
+
|
|
359
|
+
Use these deeper references when you need more than the quick start:
|
|
360
|
+
|
|
361
|
+
- [docs/README.md](./docs/README.md): docs index
|
|
362
|
+
- [docs/getting-started.md](./docs/getting-started.md): setup, config, framework defaults, watch mode, and production notes
|
|
363
|
+
- [docs/jsdoc-reference.md](./docs/jsdoc-reference.md): full route tag reference and examples
|
|
364
|
+
- [docs/workflows-and-integrations.md](./docs/workflows-and-integrations.md): framework integrations, mixed schemas, drizzle-zod, and downstream workflows
|
|
365
|
+
- [docs/faq.md](./docs/faq.md): troubleshooting and common questions
|
|
366
|
+
- [docs/openapi-version-coverage.md](./docs/openapi-version-coverage.md): version-specific behavior, validation strategy, and generated vs preserved fields
|
|
367
|
+
- [docs/zod4-support-matrix.md](./docs/zod4-support-matrix.md): tested Zod 4 coverage and known boundaries
|
|
368
|
+
- [docs/example-app-coverage-plan.md](./docs/example-app-coverage-plan.md): example app roles, coverage goals, and expansion roadmap
|
|
369
|
+
- [apps](./apps): complete runnable examples
|
|
370
|
+
|
|
371
|
+
## CLI
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
pnpm exec openapi-gen init
|
|
375
|
+
pnpm exec openapi-gen generate
|
|
376
|
+
pnpm exec openapi-gen generate --watch
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### `init` options
|
|
380
|
+
|
|
381
|
+
| Option | Choices | Default |
|
|
382
|
+
| ------------- | ------------------------------------------------------------ | ------------------- |
|
|
383
|
+
| `--framework` | `next`, `tanstack`, `react-router` | `next` |
|
|
384
|
+
| `--ui` | `scalar`, `swagger`, `redoc`, `stoplight`, `rapidoc`, `none` | `scalar` |
|
|
385
|
+
| `--schema` | `zod`, `typescript` | `zod` |
|
|
386
|
+
| `--docs-url` | any string | `api-docs` |
|
|
387
|
+
| `--output` | any path | `next.openapi.json` |
|
|
388
|
+
|
|
389
|
+
### `generate` options
|
|
390
|
+
|
|
391
|
+
| Option | Purpose |
|
|
392
|
+
| ------------ | --------------------------------------------- |
|
|
393
|
+
| `--config` | Use a specific config file |
|
|
394
|
+
| `--template` | Merge a specific OpenAPI template or fragment |
|
|
395
|
+
| `--watch` | Regenerate when routes or schema files change |
|
|
396
|
+
|
|
397
|
+
## Contributing
|
|
398
|
+
|
|
399
|
+
Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup, commit conventions, and workflow details.
|
|
400
|
+
|
|
401
|
+
## Changelog
|
|
402
|
+
|
|
403
|
+
See [CHANGELOG.md](./CHANGELOG.md) for release history and recent changes.
|
|
404
|
+
|
|
405
|
+
## License
|
|
406
|
+
|
|
407
|
+
MIT
|