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 +331 -151
- package/dist/components/scalar.js +16 -16
- package/dist/lib/openapi-generator.js +42 -3
- package/dist/lib/route-processor.js +23 -3
- package/dist/lib/schema-processor.js +88 -17
- package/dist/lib/utils.js +12 -12
- package/dist/lib/zod-converter.js +916 -0
- package/dist/openapi-template.js +1 -0
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
# next-openapi-gen
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Automatically generate OpenAPI 3.0 documentation from Next.js projects, with support for both TypeScript types and Zod schemas.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
- Next.js
|
|
8
|
-
-
|
|
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
|
-
##
|
|
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
|
-
##
|
|
25
|
+
## Installation
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
##
|
|
31
|
+
## Quick Start
|
|
28
32
|
|
|
29
33
|
```bash
|
|
30
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
158
|
+
## CLI Usage
|
|
36
159
|
|
|
37
|
-
|
|
160
|
+
### 1. Initialization
|
|
38
161
|
|
|
39
162
|
```bash
|
|
40
|
-
npx next-openapi
|
|
163
|
+
npx next-openapi init
|
|
41
164
|
```
|
|
42
165
|
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
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
|
-
|
|
171
|
+
### 2. Generate Documentation
|
|
48
172
|
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
|
|
173
|
+
```bash
|
|
174
|
+
npx next-openapi generate
|
|
175
|
+
```
|
|
52
176
|
|
|
53
|
-
|
|
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
|
-
|
|
183
|
+
### 3. View API Documentation
|
|
56
184
|
|
|
57
|
-
|
|
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
|
-
|
|
187
|
+
## Examples
|
|
160
188
|
|
|
161
|
-
|
|
189
|
+
### Path Parameters
|
|
162
190
|
|
|
163
|
-
```
|
|
164
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
338
|
+
## Advanced Zod Features
|
|
172
339
|
|
|
173
|
-
|
|
340
|
+
The library supports advanced Zod features such as:
|
|
174
341
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
351
|
+
### Type Aliases with z.infer
|
|
183
352
|
|
|
184
|
-
|
|
353
|
+
```typescript
|
|
354
|
+
// You can use TypeScript with Zod types
|
|
355
|
+
import { z } from 'zod';
|
|
185
356
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
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
|
|
4
|
-
import { cleanSpec } from "./utils
|
|
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.
|
|
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
|
}
|