next-openapi-gen 0.3.3 → 0.4.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 CHANGED
@@ -1,13 +1,20 @@
1
1
  # next-openapi-gen
2
2
 
3
- **next-openapi-gen** super fast and easy way to generate OpenAPI 3.0 documentation automatically from API routes in NextJS.
3
+ Automatically generate OpenAPI 3.0 documentation from Next.js projects, with support for both TypeScript types and Zod schemas.
4
4
 
5
- ## Prerequisites
5
+ ## Features
6
6
 
7
- - Next.js >= 14
8
- - Node >= 18
7
+ - ✅ Automatic OpenAPI documentation generation from Next.js code
8
+ - Support for Next.js App Router (including `/api/users/[id]/route.ts` routes)
9
+ - ✅ TypeScript types support
10
+ - ✅ Zod schemas support
11
+ - ✅ JSDoc comments support
12
+ - ✅ Multiple UI interfaces: `Scalar`, `Swagger`, `Redoc`, `Stoplight` and `Rapidoc` available at `/api-docs` url.
13
+ - ✅ Path parameters detection (`/users/{id}`)
14
+ - ✅ Intelligent parameter examples
15
+ - ✅ Intuitive CLI for initialization and documentation generation
9
16
 
10
- ## Interfaces
17
+ ## Supported interfaces
11
18
 
12
19
  - Scalar 🆕
13
20
  - Swagger
@@ -15,182 +22,350 @@
15
22
  - Stoplight Elements
16
23
  - RapiDoc
17
24
 
18
- ## Features
25
+ ## Installation
19
26
 
20
- - **Automatic OpenAPI Generation**: Generate OpenAPI 3.0 documentation from your Next.js routes, automatically parsing TypeScript types for parameters, request bodies and responses. Field comments in TypeScript types are reflected as descriptions in the OpenAPI schema.
21
- - **Complex TypeScript Types**: Use complex TypeScript types, such as `nested objects`, `arrays`, `enums` and `unions` (mapped to anyOf). This enables a more comprehensive representation of data structures directly in the OpenAPI schema.
22
- - **JSDoc-Based Documentation**: Document API routes with optional JSDoc comments, including tags like `@openapi`, `@auth`, `@desc`, `@params`, `@body`, and `@response` to easily define route metadata.
23
- - **Multiple UI Interfaces**: Choose between `Scalar`, `Swagger UI`, `Redoc`, `Stoplight Elements` or `RapiDoc` to visualize your API documentation. Customize the interface to fit your preferences.
24
- - **Real-time Documentation**: As your API evolves, regenerate the OpenAPI documentation with a single command, ensuring your documentation is always up to date.
25
- - **Easy configuration**: Customize generator behavior using the `next.openapi.json` configuration file, allowing for quick adjustments without modifying the code.
27
+ ```bash
28
+ npm install next-openapi-gen --save-dev
29
+ ```
26
30
 
27
- ## Installation
31
+ ## Quick Start
28
32
 
29
33
  ```bash
30
- yarn add next-openapi-gen
34
+ # Initialize OpenAPI configuration
35
+ npx next-openapi-gen init --ui scalar --docs-url api-docs
36
+
37
+ # Generate OpenAPI documentation
38
+ npx next-openapi generate
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ During initialization (`npx next-openapi init`), a configuration file `next.openapi.json` will be created in the project's root directory:
44
+
45
+ ```json
46
+ {
47
+ "openapi": "3.0.0",
48
+ "info": {
49
+ "title": "Next.js API",
50
+ "version": "1.0.0",
51
+ "description": "API generated by next-openapi-gen"
52
+ },
53
+ "servers": [
54
+ {
55
+ "url": "http://localhost:3000",
56
+ "description": "Local server"
57
+ }
58
+ ],
59
+ "apiDir": "src/app/api",
60
+ "schemaDir": "src/types",
61
+ "schemaType": "typescript", // or "zod" for Zod schemas
62
+ "outputFile": "openapi.json",
63
+ "docsUrl": "/api-docs",
64
+ "includeOpenApiRoutes": false
65
+ }
66
+ ```
67
+
68
+ ### Configuration Options
69
+
70
+ | Option | Description |
71
+ |-------|------|
72
+ | `apiDir` | Path to the API directory |
73
+ | `schemaDir` | Path to the types/schemas directory |
74
+ | `schemaType` | Schema type: `"typescript"` or `"zod"` |
75
+ | `outputFile` | Path to the OpenAPI output file |
76
+ | `docsUrl` | API documentation URL (for Swagger UI) |
77
+ | `includeOpenApiRoutes` | Whether to include only routes with @openapi tag |
78
+
79
+ ## Documenting Your API
80
+
81
+ ### With TypeScript Types
82
+
83
+ ```typescript
84
+ // src/app/api/users/[id]/route.ts
85
+
86
+ import { NextRequest, NextResponse } from 'next/server';
87
+
88
+ type UserParams = {
89
+ id: string; // User ID
90
+ };
91
+
92
+ type UserResponse = {
93
+ id: string; // User ID
94
+ name: string; // Full name
95
+ email: string; // Email address
96
+ };
97
+
98
+ /**
99
+ * Get user information
100
+ * @desc Fetches detailed user information by ID
101
+ * @pathParams UserParams
102
+ * @response UserResponse
103
+ * @openapi
104
+ */
105
+ export async function GET(
106
+ request: NextRequest,
107
+ { params }: { params: { id: string } }
108
+ ) {
109
+ // Implementation...
110
+ }
111
+ ```
112
+
113
+ ### With Zod Schemas
114
+
115
+ ```typescript
116
+ // src/app/api/products/[id]/route.ts
117
+
118
+ import { NextRequest, NextResponse } from 'next/server';
119
+ import { z } from 'zod';
120
+
121
+ export const ProductParams = z.object({
122
+ id: z.string().describe("Product ID")
123
+ });
124
+
125
+ export const ProductResponse = z.object({
126
+ id: z.string().describe("Product ID"),
127
+ name: z.string().describe("Product name"),
128
+ price: z.number().positive().describe("Product price")
129
+ });
130
+
131
+ /**
132
+ * Get product information
133
+ * @desc Fetches detailed product information by ID
134
+ * @pathParams ProductParams
135
+ * @response ProductResponse
136
+ * @openapi
137
+ */
138
+ export async function GET(
139
+ request: NextRequest,
140
+ { params }: { params: { id: string } }
141
+ ) {
142
+ // Implementation...
143
+ }
31
144
  ```
32
145
 
33
- ## Usage
146
+ ## JSDoc Documentation Tags
147
+
148
+ | Tag | Description |
149
+ |-----|------|
150
+ | `@desc` | Endpoint description |
151
+ | `@pathParams` | Path parameters type/schema |
152
+ | `@params` | Query parameters type/schema |
153
+ | `@body` | Request body type/schema |
154
+ | `@response` | Response type/schema |
155
+ | `@auth` | Authorization type (`bearer`, `basic`, `apikey`) |
156
+ | `@openapi` | Marks the route for inclusion in documentation (if includeOpenApiRoutes is enabled) |
34
157
 
35
- ### Step 1: Initialize Configuration and Setup
158
+ ## CLI Usage
36
159
 
37
- Run the following command to generate the `next.openapi.json` configuration file and automatically set up Scalar UI with `/api-docs` routes:
160
+ ### 1. Initialization
38
161
 
39
162
  ```bash
40
- npx next-openapi-gen init --ui scalar --docs-url api-docs
163
+ npx next-openapi init
41
164
  ```
42
165
 
43
- Parameters:
44
- - **ui**: `scalar` | `swagger` | `redoc` | `stoplight` | `rapidoc`
45
- - **docs-url**: url on which api docs will be visible
166
+ This command will generate following elements:
167
+ - Generate `next.openapi.json` configuration file
168
+ - Install UI interface (default `Scalar`)
169
+ - Add `/api-docs` page to display OpenAPI documentation
46
170
 
47
- This command does the following:
171
+ ### 2. Generate Documentation
48
172
 
49
- - Generates a `next.openapi.json` file, which stores the OpenAPI configuration for your project.
50
- - Installs Scalar UI to provide an API documentation interface.
51
- - Adds an `/api-docs` route in the Next.js app for visualizing the generated OpenAPI documentation.
173
+ ```bash
174
+ npx next-openapi generate
175
+ ```
52
176
 
53
- ### Step 2: Add JSDoc Comments to Your API Routes
177
+ This command will generate OpenAPI documentation based on your API code:
178
+ - Scan API directories for routes
179
+ - Analyze types/schemas
180
+ - Generate OpenAPI file (`openapi.json`) in `public` folder
181
+ - Create Swagger/Scalar UI endpoint and page (if enabled)
54
182
 
55
- Annotate your API routes using JSDoc comments. Here's an example:
183
+ ### 3. View API Documentation
56
184
 
57
- <div align="center">
58
- <table>
59
- <tr>
60
- <th>Login route</th>
61
- <th>Scalar / Swagger</th>
62
- </tr>
63
- <tr>
64
- <td>
65
-
66
- ```typescript
67
- //app/api/auth/login/route.ts
68
-
69
- type LoginBody = {
70
- email: string; // user email
71
- password: string; // user password
72
- };
73
-
74
- type LoginResponse = {
75
- token: string; // auth token
76
- refresh_token: string; // refresh token
77
- };
78
-
79
- /**
80
- * Authenticate as a user.
81
- * @desc: Login a user
82
- * @body: LoginBody
83
- * @response: LoginResponse
84
- */
85
- export async function POST(req: Request) {
86
- ...
87
- }
88
- ```
89
- </td>
90
- <td>
91
- <img width="340" alt="api-login-scalar" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-login-scalar.png" alt-text="api-login"/>
92
- <br/><br/><br/>
93
- <img width="340" alt="api-login-swagger" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-login-swagger.png" alt-text="api-login-swagger"/>
94
- </td>
95
- </tr>
96
-
97
- <tr>
98
- <th>Users route</th>
99
- <th>Scalar / Swagger</th>
100
- </tr>
101
- <tr>
102
- <td>
103
-
104
- ```typescript
105
- //app/api/users/route.ts
106
-
107
- enum ROLE {
108
- OWNER,
109
- MEMBER,
110
- }
111
-
112
- type User = {
113
- id: number;
114
- name: string;
115
- email: string;
116
- role: ROLE;
117
- address: Address;
118
- };
119
-
120
- type Address = {
121
- line1: string;
122
- line2?: string;
123
- city: string;
124
- postalCode: string;
125
- };
126
-
127
- type UsersParams = {
128
- search: string; // search by
129
- role?: ROLE; // filter by role
130
- page?: number; // page number
131
- };
132
-
133
- type UsersResponse = {
134
- page?: number;
135
- count?: number;
136
- data: User[];
137
- };
138
-
139
- /**
140
- * List all users.
141
- * @auth: bearer
142
- * @params: UsersParams
143
- * @response: UsersResponse
144
- */
145
- export async function GET(req: Request) {
146
- ...
147
- }
148
- ```
149
- </td>
150
- <td>
151
- <img width="340" alt="api-users-scalar" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-users-scalar.png" alt-text="api-users-scalar"/>
152
- <br/><br/><br/>
153
- <img width="340" alt="api-users-swagger" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-users-swagger.png" alt-text="api-users-swagger"/>
154
- </td>
155
- </tr>
156
- </table>
157
- </div>
185
+ To see API documenation go to `http://localhost:3000/api-docs`
158
186
 
159
- ### Step 3: Generate the OpenAPI Specification
187
+ ## Examples
160
188
 
161
- Run the following command to generate the OpenAPI schema based on your API routes:
189
+ ### Path Parameters
162
190
 
163
- ```bash
164
- npx next-openapi-gen generate
191
+ ```typescript
192
+ // src/app/api/users/[id]/route.ts
193
+
194
+ // TypeScript
195
+ type UserParams = {
196
+ id: string; // User ID
197
+ };
198
+
199
+ // Or Zod
200
+ const UserParams = z.object({
201
+ id: z.string().describe("User ID")
202
+ });
203
+
204
+ /**
205
+ * @pathParams UserParams
206
+ */
207
+ export async function GET() {
208
+ // ...
209
+ }
210
+ ```
211
+
212
+ ### Query Parameters
213
+
214
+ ```typescript
215
+ // src/app/api/users/route.ts
216
+
217
+ // TypeScript
218
+ type UsersQueryParams = {
219
+ page?: number; // Page number
220
+ limit?: number; // Results per page
221
+ search?: string; // Search phrase
222
+ };
223
+
224
+ // Or Zod
225
+ const UsersQueryParams = z.object({
226
+ page: z.number().optional().describe("Page number"),
227
+ limit: z.number().optional().describe("Results per page"),
228
+ search: z.string().optional().describe("Search phrase")
229
+ });
230
+
231
+ /**
232
+ * @params UsersQueryParams
233
+ */
234
+ export async function GET() {
235
+ // ...
236
+ }
237
+ ```
238
+
239
+ ### Request Body
240
+
241
+ ```typescript
242
+ // src/app/api/users/route.ts
243
+
244
+ // TypeScript
245
+ type CreateUserBody = {
246
+ name: string; // Full name
247
+ email: string; // Email address
248
+ password: string; // Password
249
+ };
250
+
251
+ // Or Zod
252
+ const CreateUserBody = z.object({
253
+ name: z.string().describe("Full name"),
254
+ email: z.string().email().describe("Email address"),
255
+ password: z.string().min(8).describe("Password")
256
+ });
257
+
258
+ /**
259
+ * @body CreateUserBody
260
+ */
261
+ export async function POST() {
262
+ // ...
263
+ }
264
+ ```
265
+
266
+ ### Response
267
+
268
+ ```typescript
269
+ // src/app/api/users/route.ts
270
+
271
+ // TypeScript
272
+ type UserResponse = {
273
+ id: string; // User ID
274
+ name: string; // Full name
275
+ email: string; // Email address
276
+ createdAt: Date; // Creation date
277
+ };
278
+
279
+ // Or Zod
280
+ const UserResponse = z.object({
281
+ id: z.string().describe("User ID"),
282
+ name: z.string().describe("Full name"),
283
+ email: z.string().email().describe("Email address"),
284
+ createdAt: z.date().describe("Creation date")
285
+ });
286
+
287
+ /**
288
+ * @response UserResponse
289
+ */
290
+ export async function GET() {
291
+ // ...
292
+ }
293
+ ```
294
+
295
+ ### Authorization
296
+
297
+ ```typescript
298
+ // src/app/api/protected/route.ts
299
+
300
+ /**
301
+ * @auth bearer
302
+ */
303
+ export async function GET() {
304
+ // ...
305
+ }
306
+ ```
307
+
308
+ ## Advanced Usage
309
+
310
+ ### Automatic Path Parameter Detection
311
+
312
+ The library automatically detects path parameters and generates documentation for them:
313
+
314
+ ```typescript
315
+ // src/app/api/users/[id]/posts/[postId]/route.ts
316
+
317
+ // Will automatically detect 'id' and 'postId' parameters
318
+ export async function GET() {
319
+ // ...
320
+ }
165
321
  ```
166
322
 
167
- This command processes all your API routes, extracts the necessary information from JSDoc comments, and generates the OpenAPI schema, typically saved to a `openapi.json` file in the `public` folder.
323
+ If no type/schema is provided for path parameters, a default schema will be generated.
324
+
325
+ ### Intelligent Examples
326
+
327
+ The library generates intelligent examples for parameters based on their name:
168
328
 
169
- ### Step 4: View API Documentation
329
+ | Parameter name | Example |
330
+ |----------------|----------|
331
+ | `id`, `*Id` | `"123"` or `123` |
332
+ | `slug` | `"example-slug"` |
333
+ | `uuid` | `"123e4567-e89b-12d3-a456-426614174000"` |
334
+ | `email` | `"user@example.com"` |
335
+ | `name` | `"example-name"` |
336
+ | `date` | `"2023-01-01"` |
170
337
 
171
- With the `/api-docs` route generated from the init command, you can now access your API documentation through Scalar UI by navigating to `http://localhost:3000/api-docs`.
338
+ ## Advanced Zod Features
172
339
 
173
- ## JSDoc tags
340
+ The library supports advanced Zod features such as:
174
341
 
175
- - `@openapi`: Marks the route for inclusion in the OpenAPI specification.
176
- - `@auth`: Specifies authentication type used for API route (`basic`, `bearer`, `apikey`).
177
- - `@desc`: Provides a detailed description of the API route.
178
- - `@params`: Specifies the TypeScript interface for the query parameters.
179
- - `@body`: Specifies the TypeScript interface for the request body.
180
- - `@response`: Specifies the TypeScript interface for the response.
342
+ ### Validation Chains
343
+
344
+ ```typescript
345
+ // Zod validation chains are properly converted to OpenAPI schemas
346
+ const EmailSchema = z.string().email().min(5).max(100).describe("Email address");
347
+
348
+ // Converts to OpenAPI with email format, minLength and maxLength
349
+ ```
181
350
 
182
- ## Configuration Options
351
+ ### Type Aliases with z.infer
183
352
 
184
- The `next.openapi.json` file allows you to configure the behavior of the OpenAPI generator, including options such as:
353
+ ```typescript
354
+ // You can use TypeScript with Zod types
355
+ import { z } from 'zod';
185
356
 
186
- - **apiDir**: (default: `./src/app/api`) The directory where your API routes are stored.
187
- - **schemaDir**: (default: `./src`) The directory where your schema definitions are stored.
188
- - **docsUrl**: (default: `./api-docs`) Route where OpenAPI UI is available.
189
- - **ui**: (default: `scalar`) OpenAPI UI interface.
190
- - **outputFile**: (default: `./openapi.json`) The file where the generated OpenAPI specification will be saved in `public` folder.
191
- - **includeOpenApiRoutes**: (default: `false`) When `true`, the generator will only include routes that have the `@openapi` tag in their JSDoc comments.
357
+ const UserSchema = z.object({
358
+ id: z.string().uuid(),
359
+ name: z.string().min(2)
360
+ });
192
361
 
193
- ## Interface providers
362
+ // Use z.infer to create a TypeScript type
363
+ type User = z.infer<typeof UserSchema>;
364
+
365
+ // The library will be able to recognize this schema by reference
366
+ ```
367
+
368
+ ## Available UI providers
194
369
 
195
370
  <div align="center">
196
371
  <table>
@@ -221,3 +396,8 @@ The `next.openapi.json` file allows you to configure the behavior of the OpenAPI
221
396
  </tr>
222
397
  </tbody>
223
398
  </table>
399
+ </div>
400
+
401
+ ## License
402
+
403
+ MIT
@@ -1,20 +1,20 @@
1
1
  export const scalarDeps = ["@scalar/api-reference-react", "ajv"];
2
2
  export function ScalarUI(outputFile) {
3
- return `
4
- "use client";
5
-
6
- import { ApiReferenceReact } from "@scalar/api-reference-react";
7
-
8
- import "@scalar/api-reference-react/style.css";
9
-
10
- export default function ApiDocsPage() {
11
- return (
12
- <ApiReferenceReact
13
- configuration={{
14
- url: "/${outputFile}",
15
- }}
16
- />
17
- );
18
- }
3
+ return `
4
+ "use client";
5
+
6
+ import { ApiReferenceReact } from "@scalar/api-reference-react";
7
+
8
+ import "@scalar/api-reference-react/style.css";
9
+
10
+ export default function ApiDocsPage() {
11
+ return (
12
+ <ApiReferenceReact
13
+ configuration={{
14
+ url: "/${outputFile}",
15
+ }}
16
+ />
17
+ );
18
+ }
19
19
  `;
20
20
  }
@@ -1,7 +1,7 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
- import { RouteProcessor } from "./route-processor.js";
4
- import { cleanSpec } from "./utils.js";
3
+ import { RouteProcessor } from "./route-processor";
4
+ import { cleanSpec } from "./utils";
5
5
  export class OpenApiGenerator {
6
6
  config;
7
7
  template;
@@ -14,7 +14,7 @@ export class OpenApiGenerator {
14
14
  }
15
15
  getConfig() {
16
16
  // @ts-ignore
17
- const { apiDir, schemaDir, docsUrl, ui, outputFile, includeOpenApiRoutes } = this.template;
17
+ const { apiDir, schemaDir, docsUrl, ui, outputFile, includeOpenApiRoutes, schemaType = "typescript", } = this.config;
18
18
  return {
19
19
  apiDir,
20
20
  schemaDir,
@@ -22,12 +22,51 @@ export class OpenApiGenerator {
22
22
  ui,
23
23
  outputFile,
24
24
  includeOpenApiRoutes,
25
+ schemaType,
25
26
  };
26
27
  }
27
28
  generate() {
28
29
  const { apiDir } = this.config;
30
+ // Check if app router structure exists
31
+ let appRouterApiDir = "";
32
+ if (fs.existsSync(path.join(path.dirname(apiDir), "app", "api"))) {
33
+ appRouterApiDir = path.join(path.dirname(apiDir), "app", "api");
34
+ console.log(`Found app router API directory at ${appRouterApiDir}`);
35
+ }
36
+ // Scan pages router routes
29
37
  this.routeProcessor.scanApiRoutes(apiDir);
38
+ // If app router directory exists, scan it as well
39
+ if (appRouterApiDir) {
40
+ this.routeProcessor.scanApiRoutes(appRouterApiDir);
41
+ }
30
42
  this.template.paths = this.routeProcessor.getSwaggerPaths();
43
+ // Add server URL for examples if not already defined
44
+ if (!this.template.servers || this.template.servers.length === 0) {
45
+ this.template.servers = [
46
+ {
47
+ url: this.template.basePath || "",
48
+ description: "API server",
49
+ },
50
+ ];
51
+ }
52
+ // Ensure there's a components section if not already defined
53
+ if (!this.template.components) {
54
+ this.template.components = {};
55
+ }
56
+ // Add schemas section if not already defined
57
+ if (!this.template.components.schemas) {
58
+ this.template.components.schemas = {};
59
+ }
60
+ // Get defined schemas from the processor
61
+ const definedSchemas = this.routeProcessor
62
+ .getSchemaProcessor()
63
+ .getDefinedSchemas();
64
+ if (definedSchemas && Object.keys(definedSchemas).length > 0) {
65
+ this.template.components.schemas = {
66
+ ...this.template.components.schemas,
67
+ ...definedSchemas,
68
+ };
69
+ }
31
70
  const openapiSpec = cleanSpec(this.template);
32
71
  return openapiSpec;
33
72
  }