next-openapi-gen 0.10.4 → 1.0.0

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.
Files changed (44) hide show
  1. package/dist/cli.d.ts +4 -0
  2. package/dist/cli.js +8599 -0
  3. package/dist/index.d.ts +18 -0
  4. package/dist/index.js +8645 -26
  5. package/dist/next/index.d.ts +1 -0
  6. package/dist/next/index.js +7965 -0
  7. package/dist/react-router/index.d.ts +1 -0
  8. package/dist/react-router/index.js +7134 -0
  9. package/dist/vite/index.d.ts +1 -0
  10. package/dist/vite/index.js +7134 -0
  11. package/package.json +102 -79
  12. package/{dist/components/rapidoc.js → templates/init/ui/nextjs/rapidoc.tsx} +16 -20
  13. package/templates/init/ui/nextjs/redoc.tsx +11 -0
  14. package/{dist/components/scalar.js → templates/init/ui/nextjs/scalar.tsx} +15 -21
  15. package/{dist/components/stoplight.js → templates/init/ui/nextjs/stoplight.tsx} +11 -17
  16. package/templates/init/ui/nextjs/swagger.tsx +17 -0
  17. package/templates/init/ui/reactrouter/rapidoc.tsx +15 -0
  18. package/templates/init/ui/reactrouter/redoc.tsx +9 -0
  19. package/templates/init/ui/reactrouter/scalar.tsx +14 -0
  20. package/templates/init/ui/reactrouter/stoplight.tsx +10 -0
  21. package/templates/init/ui/reactrouter/swagger.tsx +11 -0
  22. package/templates/init/ui/tanstack/rapidoc.tsx +21 -0
  23. package/templates/init/ui/tanstack/redoc.tsx +14 -0
  24. package/templates/init/ui/tanstack/scalar.tsx +19 -0
  25. package/templates/init/ui/tanstack/stoplight.tsx +15 -0
  26. package/templates/init/ui/tanstack/swagger.tsx +16 -0
  27. package/templates/init/ui/template-types.d.ts +9 -0
  28. package/README.md +0 -1047
  29. package/dist/commands/generate.js +0 -24
  30. package/dist/commands/init.js +0 -194
  31. package/dist/components/redoc.js +0 -17
  32. package/dist/components/swagger.js +0 -21
  33. package/dist/lib/app-router-strategy.js +0 -66
  34. package/dist/lib/drizzle-zod-processor.js +0 -329
  35. package/dist/lib/logger.js +0 -39
  36. package/dist/lib/openapi-generator.js +0 -171
  37. package/dist/lib/pages-router-strategy.js +0 -198
  38. package/dist/lib/route-processor.js +0 -347
  39. package/dist/lib/router-strategy.js +0 -1
  40. package/dist/lib/schema-processor.js +0 -1612
  41. package/dist/lib/utils.js +0 -284
  42. package/dist/lib/zod-converter.js +0 -2133
  43. package/dist/openapi-template.js +0 -99
  44. package/dist/types.js +0 -1
package/README.md DELETED
@@ -1,1047 +0,0 @@
1
- # next-openapi-gen
2
-
3
- Automatically generate OpenAPI 3.0 documentation from Next.js projects, with support for Zod schemas and TypeScript types.
4
-
5
- ## Features
6
-
7
- - ✅ Automatic OpenAPI 3.0 documentation generation from Next.js App Router and Pages Router 🆕
8
- - ✅ Multiple schema types: `TypeScript`, `Zod`, `Drizzle-Zod`, or `custom YAML/JSON` files
9
- - ✅ Mix schema sources simultaneously - perfect for gradual migrations
10
- - ✅ JSDoc comments with intelligent parameter examples
11
- - ✅ Multiple UI interfaces: `Scalar`, `Swagger`, `Redoc`, `Stoplight`, and `RapiDoc` available at `/api-docs` url
12
- - ✅ Auto-detection of path parameters (e.g., `/users/[id]/route.ts`)
13
- - ✅ Intuitive CLI for quick setup and generation
14
-
15
- ## Supported interfaces
16
-
17
- - Scalar 💡(default)
18
- - Swagger
19
- - Redoc
20
- - Stoplight Elements
21
- - RapiDoc
22
-
23
- ## Installation
24
-
25
- ```bash
26
- npm install next-openapi-gen --save-dev
27
- ```
28
-
29
- ## Quick Start
30
-
31
- ```bash
32
- # Initialize OpenAPI configuration
33
- npx next-openapi-gen init
34
-
35
- # Generate OpenAPI documentation
36
- npx next-openapi-gen generate
37
- ```
38
-
39
- > [!TIP]
40
- > Scalar UI and Zod are set by default
41
-
42
-
43
- ### Init Command Options
44
-
45
- | Option | Choices | Default | Description |
46
- |--------|---------|---------|-------------|
47
- | `--ui` | `scalar`, `swagger`, `redoc`, `stoplight`, `rapidoc`, `none` | `scalar` | UI framework for API docs |
48
- | `--schema` | `zod`, `typescript` | `zod` | Schema validation tool |
49
- | `--docs-url` | any string | `api-docs` | URL path for documentation page |
50
- | `--output` | any path | `next.openapi.json` | Output file for OpenAPI template |
51
-
52
- > [!TIP]
53
- > Use `--ui none` to skip UI setup and only generate the OpenAPI specification file.
54
-
55
- ## Configuration
56
-
57
- During initialization (`npx next-openapi-gen init`), a configuration file `next.openapi.json` will be created in the project's root directory:
58
-
59
- ```json
60
- {
61
- "openapi": "3.0.0",
62
- "info": {
63
- "title": "Next.js API",
64
- "version": "1.0.0",
65
- "description": "API generated by next-openapi-gen"
66
- },
67
- "servers": [
68
- {
69
- "url": "http://localhost:3000",
70
- "description": "Local server"
71
- }
72
- ],
73
- "apiDir": "src/app/api", // or "pages/api" for Pages Router
74
- "routerType": "app", // "app" (default) or "pages" for legacy Pages Router
75
- "schemaDir": "src/types", // or ["src/types", "src/schemas"] for multiple directories
76
- "schemaType": "zod", // or "typescript", or ["zod", "typescript"] for multiple
77
- "schemaFiles": [], // Optional: ["./schemas/models.yaml", "./schemas/api.json"]
78
- "outputFile": "openapi.json",
79
- "outputDir": "./public",
80
- "docsUrl": "/api-docs",
81
- "includeOpenApiRoutes": false,
82
- "ignoreRoutes": [],
83
- "debug": false
84
- }
85
- ```
86
-
87
- ### Configuration Options
88
-
89
- | Option | Description |
90
- | ---------------------- | ----------------------------------------------------------------------------- |
91
- | `apiDir` | Path to the API directory |
92
- | `routerType` | Router type: `"app"` (default) or `"pages"` for legacy Pages Router |
93
- | `schemaDir` | Path to types/schemas directory, or array of paths for multiple directories |
94
- | `schemaType` | Schema type: `"zod"`, `"typescript"`, or `["zod", "typescript"]` for multiple |
95
- | `schemaFiles` | Optional: Array of custom OpenAPI schema files (YAML/JSON) to include |
96
- | `outputFile` | Name of the OpenAPI output file |
97
- | `outputDir` | Directory where OpenAPI file will be generated (default: `"./public"`) |
98
- | `docsUrl` | API documentation URL (for Swagger UI) |
99
- | `includeOpenApiRoutes` | Whether to include only routes with @openapi tag |
100
- | `ignoreRoutes` | Array of route patterns to exclude from documentation (supports wildcards) |
101
- | `defaultResponseSet` | Default error response set for all endpoints |
102
- | `responseSets` | Named sets of error response codes |
103
- | `errorConfig` | Error schema configuration |
104
- | `debug` | Enable detailed logging during generation |
105
-
106
- ## Documenting Your API
107
-
108
- ### With Zod Schemas
109
-
110
- ```typescript
111
- // src/app/api/products/[id]/route.ts
112
-
113
- import { NextRequest, NextResponse } from "next/server";
114
- import { z } from "zod";
115
-
116
- export const ProductParams = z.object({
117
- id: z.string().describe("Product ID"),
118
- });
119
-
120
- export const ProductResponse = z.object({
121
- id: z.string().describe("Product ID"),
122
- name: z.string().describe("Product name"),
123
- price: z.number().positive().describe("Product price"),
124
- });
125
-
126
- /**
127
- * Get product information
128
- * @description Fetches detailed product information by ID
129
- * @pathParams ProductParams
130
- * @response ProductResponse
131
- * @openapi
132
- */
133
- export async function GET(
134
- request: NextRequest,
135
- { params }: { params: { id: string } }
136
- ) {
137
- // Implementation...
138
- }
139
- ```
140
-
141
- ### With TypeScript Types
142
-
143
- ```typescript
144
- // src/app/api/users/[id]/route.ts
145
-
146
- import { NextRequest, NextResponse } from "next/server";
147
-
148
- type UserParams = {
149
- id: string; // User ID
150
- };
151
-
152
- type UserResponse = {
153
- id: string; // User ID
154
- name: string; // Full name
155
- email: string; // Email address
156
- };
157
-
158
- /**
159
- * Get user information
160
- * @description Fetches detailed user information by ID
161
- * @pathParams UserParams
162
- * @response UserResponse
163
- * @openapi
164
- */
165
- export async function GET(
166
- request: NextRequest,
167
- { params }: { params: { id: string } }
168
- ) {
169
- // Implementation...
170
- }
171
- ```
172
-
173
- ### With Drizzle-Zod
174
-
175
- ```typescript
176
- // src/db/schema.ts - Define your Drizzle table
177
- import { pgTable, serial, varchar, text } from "drizzle-orm/pg-core";
178
-
179
- export const posts = pgTable("posts", {
180
- id: serial("id").primaryKey(),
181
- title: varchar("title", { length: 255 }).notNull(),
182
- content: text("content").notNull(),
183
- });
184
-
185
- // src/schemas/post.ts - Generate Zod schema with drizzle-zod
186
- import { createInsertSchema, createSelectSchema } from "drizzle-zod";
187
- import { posts } from "@/db/schema";
188
-
189
- export const CreatePostSchema = createInsertSchema(posts, {
190
- title: (schema) => schema.title.min(5).max(255).describe("Post title"),
191
- content: (schema) => schema.content.min(10).describe("Post content"),
192
- });
193
-
194
- export const PostResponseSchema = createSelectSchema(posts);
195
-
196
- // src/app/api/posts/route.ts - Use in your API route
197
- /**
198
- * Create a new post
199
- * @description Create a new blog post with Drizzle-Zod validation
200
- * @body CreatePostSchema
201
- * @response 201:PostResponseSchema
202
- * @openapi
203
- */
204
- export async function POST(request: NextRequest) {
205
- const body = await request.json();
206
- const validated = CreatePostSchema.parse(body);
207
- // Implementation...
208
- }
209
- ```
210
-
211
- ## JSDoc Documentation Tags
212
-
213
- | Tag | Description |
214
- |------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
215
- | `@description` | Endpoint description |
216
- | `@operationId` | Custom operation ID (overrides auto-generated ID) |
217
- | `@pathParams` | Path parameters type/schema |
218
- | `@params` | Query parameters type/schema (use `@queryParams` if you have prettier-plugin-jsdoc conflicts) |
219
- | `@body` | Request body type/schema |
220
- | `@bodyDescription` | Request body description |
221
- | `@response` | Response type/schema with optional code and description (`User`, `201:User`, `User:Description`, `201:User:Description`) |
222
- | `@responseDescription` | Response description |
223
- | `@responseSet` | Override default response set (`public`, `auth`, `none`) |
224
- | `@add` | Add custom response codes (`409:ConflictResponse`, `429`) |
225
- | `@contentType` | Request body content type (`application/json`, `multipart/form-data`) |
226
- | `@auth` | Authorization type (e.g., `bearer`, `basic`, `apikey`, or a custom type) — supports multiple auths using comma separator (e.g., `bearer, CustomType`) |
227
- | `@tag` | Custom tag |
228
- | `@deprecated` | Marks the route as deprecated |
229
- | `@openapi` | Marks the route for inclusion in documentation (if includeOpenApiRoutes is enabled) |
230
- | `@ignore` | Excludes the route from OpenAPI documentation |
231
- | `@method` | HTTP method for Pages Router (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) - required for Pages Router only |
232
-
233
- ## Pages Router Support 🆕
234
-
235
- The library now supports the legacy Next.js Pages Router. To use it:
236
-
237
- 1. Set `routerType` to `"pages"` in your configuration
238
- 2. Use the `@method` JSDoc tag to specify HTTP methods
239
-
240
- See **[next15-pages-router](./examples/next15-pages-router)** for a complete working example.
241
-
242
- ## CLI Usage
243
-
244
- ### 1. Initialization
245
-
246
- ```bash
247
- npx next-openapi-gen init
248
- ```
249
-
250
- This command will generate following elements:
251
-
252
- - Generate `next.openapi.json` configuration file
253
- - Set up `Scalar` UI for documentation display
254
- - Add `/api-docs` page to display OpenAPI documentation
255
- - Configure `zod` as the default schema tool
256
-
257
- ### 2. Generate Documentation
258
-
259
- ```bash
260
- npx next-openapi-gen generate
261
- ```
262
-
263
- This command will generate OpenAPI documentation based on your API code:
264
-
265
- - Scan API directories for routes
266
- - Analyze types/schemas
267
- - Generate OpenAPI file (`openapi.json`) in specified output directory (default: `public` folder)
268
- - Create Scalar/Swagger UI endpoint and page (if enabled)
269
-
270
- ### 3. View API Documentation
271
-
272
- To see API documenation go to `http://localhost:3000/api-docs`
273
-
274
- ## Examples
275
-
276
- ### Path Parameters
277
-
278
- ```typescript
279
- // src/app/api/users/[id]/route.ts
280
-
281
- // Zod
282
- const UserParams = z.object({
283
- id: z.string().describe("User ID"),
284
- });
285
-
286
- // Or TypeScript
287
- type UserParams = {
288
- id: string; // User ID
289
- };
290
-
291
- /**
292
- * @pathParams UserParams
293
- */
294
- export async function GET() {
295
- // ...
296
- }
297
- ```
298
-
299
- ### Query Parameters
300
-
301
- ```typescript
302
- // src/app/api/users/route.ts
303
-
304
- // Zod
305
- const UsersQueryParams = z.object({
306
- page: z.number().optional().describe("Page number"),
307
- limit: z.number().optional().describe("Results per page"),
308
- search: z.string().optional().describe("Search phrase"),
309
- });
310
-
311
- // Or TypeScript
312
- type UsersQueryParams = {
313
- page?: number; // Page number
314
- limit?: number; // Results per page
315
- search?: string; // Search phrase
316
- };
317
-
318
- /**
319
- * @params UsersQueryParams
320
- */
321
- export async function GET() {
322
- // ...
323
- }
324
- ```
325
-
326
- ### Request Body
327
-
328
- ```typescript
329
- // src/app/api/users/route.ts
330
-
331
- // Zod
332
- const CreateUserBody = z.object({
333
- name: z.string().describe("Full name"),
334
- email: z.string().email().describe("Email address"),
335
- password: z.string().min(8).describe("Password"),
336
- });
337
-
338
- // Or TypeScript
339
- type CreateUserBody = {
340
- name: string; // Full name
341
- email: string; // Email address
342
- password: string; // Password
343
- };
344
-
345
- /**
346
- * @body CreateUserBody
347
- * @bodyDescription User registration data including email and password
348
- */
349
- export async function POST() {
350
- // ...
351
- }
352
- ```
353
-
354
- ### Response
355
-
356
- ```typescript
357
- // src/app/api/users/route.ts
358
-
359
- // Zod
360
- const UserResponse = z.object({
361
- id: z.string().describe("User ID"),
362
- name: z.string().describe("Full name"),
363
- email: z.string().email().describe("Email address"),
364
- createdAt: z.date().describe("Creation date"),
365
- });
366
-
367
- // Or TypeScript
368
- type UserResponse = {
369
- id: string; // User ID
370
- name: string; // Full name
371
- email: string; // Email address
372
- createdAt: Date; // Creation date
373
- };
374
-
375
- /**
376
- * @response UserResponse
377
- * @responseDescription Returns newly created user object
378
- */
379
- export async function GET() {
380
- // ...
381
- }
382
-
383
- // Alternative formats with inline description
384
- /**
385
- * @response UserResponse:Returns user profile data
386
- */
387
- export async function GET() {
388
- // ...
389
- }
390
-
391
- /**
392
- * @response 201:UserResponse:Returns newly created user
393
- */
394
- export async function POST() {
395
- // ...
396
- }
397
-
398
- /**
399
- * @response 204:Empty:User successfully deleted
400
- */
401
- export async function DELETE() {
402
- // ...
403
- }
404
- ```
405
-
406
- ### Authorization
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