openapi-sync 2.1.5 → 2.1.7
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 +797 -72
- package/db.json +1 -1
- package/dist/index.js +3 -0
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -1,138 +1,863 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OpenAPI Sync - Comprehensive Documentation
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/openapi-sync)
|
|
4
4
|
[](https://github.com/akintomiwa-fisayo/openapi-sync/blob/main/LICENSE)
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**OpenAPI Sync** is a powerful developer tool that automates the synchronization of your API documentation with your codebase using OpenAPI (formerly Swagger) specifications. It generates TypeScript types, endpoint definitions, and comprehensive documentation from your OpenAPI schema, ensuring your API documentation stays up-to-date with your code.
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
- [Features](#features)
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Quick Start](#quick-start)
|
|
13
|
+
- [Configuration](#configuration)
|
|
14
|
+
- [Usage](#usage)
|
|
15
|
+
- [Generated Output](#generated-output)
|
|
16
|
+
- [API Reference](#api-reference)
|
|
17
|
+
- [Advanced Examples](#advanced-examples)
|
|
18
|
+
- [Troubleshooting](#troubleshooting)
|
|
7
19
|
|
|
8
20
|
## Features
|
|
9
21
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
22
|
+
### 🔄 **Real-time API Synchronization**
|
|
23
|
+
|
|
24
|
+
- Automatically fetches and syncs OpenAPI specifications from remote URLs
|
|
25
|
+
- Supports both JSON and YAML formats
|
|
26
|
+
- Configurable refetch intervals for development environments
|
|
27
|
+
- Smart caching to avoid unnecessary regeneration
|
|
28
|
+
|
|
29
|
+
### 📝 **Automatic Type Generation**
|
|
30
|
+
|
|
31
|
+
- Generates TypeScript interfaces for all API endpoints
|
|
32
|
+
- Creates type definitions for request/response bodies
|
|
33
|
+
- Supports complex nested objects, arrays, and unions
|
|
34
|
+
- Handles nullable types and optional properties
|
|
35
|
+
- Generates shared component types from OpenAPI components
|
|
36
|
+
|
|
37
|
+
### 🔧 **Highly Configurable**
|
|
38
|
+
|
|
39
|
+
- Customizable naming conventions for types and endpoints
|
|
40
|
+
- Flexible output directory structure
|
|
41
|
+
- URL transformation and text replacement rules
|
|
42
|
+
- Configurable documentation generation
|
|
43
|
+
- Support for multiple API specifications
|
|
44
|
+
|
|
45
|
+
### 🛡️ **Enterprise Ready**
|
|
46
|
+
|
|
47
|
+
- Network error handling with exponential backoff retry
|
|
48
|
+
- Schema validation using Redocly OpenAPI Core
|
|
49
|
+
- State persistence to track changes
|
|
50
|
+
- Environment-aware (disables auto-sync in production)
|
|
51
|
+
- TypeScript support with full type safety
|
|
52
|
+
|
|
53
|
+
### 📚 **Rich Documentation**
|
|
54
|
+
|
|
55
|
+
- Generates comprehensive JSDoc comments
|
|
56
|
+
- Includes cURL examples for each endpoint
|
|
57
|
+
- Security scheme documentation
|
|
58
|
+
- Request/response type documentation
|
|
59
|
+
- Markdown-formatted type references
|
|
20
60
|
|
|
21
61
|
## Installation
|
|
22
62
|
|
|
23
|
-
|
|
63
|
+
### NPM Package
|
|
24
64
|
|
|
25
65
|
```bash
|
|
26
66
|
npm install openapi-sync
|
|
27
67
|
```
|
|
28
68
|
|
|
29
|
-
|
|
69
|
+
### Global Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm install -g openapi-sync
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Direct Usage (No Installation)
|
|
30
76
|
|
|
31
77
|
```bash
|
|
32
78
|
npx openapi-sync
|
|
33
79
|
```
|
|
34
80
|
|
|
81
|
+
## Quick Start
|
|
82
|
+
|
|
83
|
+
1. **Create a configuration file** in your project root:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
// openapi.sync.json
|
|
87
|
+
{
|
|
88
|
+
"refetchInterval": 5000,
|
|
89
|
+
"folder": "./src/api",
|
|
90
|
+
"api": {
|
|
91
|
+
"petstore": "https://petstore3.swagger.io/api/v3/openapi.json"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
2. **Run the sync command**:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx openapi-sync
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
3. **Use the generated types and endpoints**:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { getPetById } from "./src/api/petstore/endpoints";
|
|
106
|
+
import { IPet, IGetPetByIdResponse } from "./src/api/petstore/types";
|
|
107
|
+
|
|
108
|
+
// Use the endpoint URL
|
|
109
|
+
const petUrl = getPetById("123"); // Returns: "/pet/123"
|
|
110
|
+
|
|
111
|
+
// Use the generated types
|
|
112
|
+
const pet: IPet = {
|
|
113
|
+
id: 1,
|
|
114
|
+
name: "Fluffy",
|
|
115
|
+
status: "available",
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
35
119
|
## Configuration
|
|
36
120
|
|
|
37
|
-
|
|
121
|
+
OpenAPI Sync supports multiple configuration file formats:
|
|
122
|
+
|
|
123
|
+
- `openapi.sync.json` (JSON format)
|
|
124
|
+
- `openapi.sync.ts` (TypeScript format)
|
|
125
|
+
- `openapi.sync.js` (JavaScript format)
|
|
126
|
+
|
|
127
|
+
### Basic Configuration
|
|
38
128
|
|
|
39
129
|
```json
|
|
40
130
|
{
|
|
41
|
-
"refetchInterval": 5000,
|
|
42
|
-
"folder": "/
|
|
131
|
+
"refetchInterval": 5000,
|
|
132
|
+
"folder": "./src/api",
|
|
43
133
|
"api": {
|
|
44
|
-
"
|
|
45
|
-
"
|
|
134
|
+
"petstore": "https://petstore3.swagger.io/api/v3/openapi.json",
|
|
135
|
+
"jsonplaceholder": "https://jsonplaceholder.typicode.com/openapi.yaml"
|
|
46
136
|
},
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
137
|
+
"server": 0
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Advanced Configuration
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// openapi.sync.ts
|
|
145
|
+
import { IConfig } from "openapi-sync/types";
|
|
146
|
+
|
|
147
|
+
const config: IConfig = {
|
|
148
|
+
refetchInterval: 10000,
|
|
149
|
+
folder: "./src/generated/api",
|
|
150
|
+
api: {
|
|
151
|
+
"main-api": "https://api.example.com/openapi.json",
|
|
152
|
+
"auth-api": "https://auth.example.com/openapi.yaml",
|
|
55
153
|
},
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
154
|
+
server: "https://api.example.com", // Override server URL
|
|
155
|
+
|
|
156
|
+
// Type generation configuration
|
|
157
|
+
types: {
|
|
158
|
+
name: {
|
|
159
|
+
prefix: "I", // Prefix for interface names
|
|
160
|
+
format: (source, data, defaultName) => {
|
|
161
|
+
if (source === "shared") {
|
|
162
|
+
return `${data.name}Type`;
|
|
163
|
+
} else if (source === "endpoint") {
|
|
164
|
+
return `${data.method?.toUpperCase()}${data.path?.replace(
|
|
165
|
+
/\//g,
|
|
166
|
+
"_"
|
|
167
|
+
)}${data.type}`;
|
|
62
168
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
169
|
+
return defaultName;
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
doc: {
|
|
173
|
+
disable: false, // Enable/disable JSDoc generation
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
// Endpoint generation configuration
|
|
178
|
+
endpoints: {
|
|
179
|
+
value: {
|
|
180
|
+
replaceWords: [
|
|
181
|
+
{
|
|
182
|
+
replace: "/api/v\\d+/", // Remove version from URLs
|
|
183
|
+
with: "/",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
replace: "/internal/",
|
|
187
|
+
with: "/",
|
|
188
|
+
type: "endpoint",
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
includeServer: true, // Include server URL in endpoints
|
|
192
|
+
type: "object", // Generate as objects instead of strings
|
|
193
|
+
},
|
|
194
|
+
name: {
|
|
195
|
+
prefix: "API_",
|
|
196
|
+
useOperationId: true, // Use operationId from OpenAPI spec
|
|
197
|
+
format: ({ method, path, summary, operationId }, defaultName) => {
|
|
198
|
+
if (operationId) return operationId;
|
|
199
|
+
return path.replace(/\//g, "_").replace(/{|}/g, "");
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
doc: {
|
|
203
|
+
disable: false,
|
|
204
|
+
showCurl: true, // Include cURL examples in documentation
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export default config;
|
|
67
210
|
```
|
|
68
211
|
|
|
212
|
+
### Configuration Options Reference
|
|
213
|
+
|
|
214
|
+
#### Root Configuration
|
|
215
|
+
|
|
216
|
+
| Property | Type | Description | Default |
|
|
217
|
+
| ----------------- | ------------------------ | --------------------------------------------- | -------- |
|
|
218
|
+
| `refetchInterval` | `number` | Milliseconds between API refetches (dev only) | - |
|
|
219
|
+
| `folder` | `string` | Output directory for generated files | `""` |
|
|
220
|
+
| `api` | `Record<string, string>` | Map of API names to OpenAPI spec URLs | Required |
|
|
221
|
+
| `server` | `number \| string` | Server index or custom server URL | `0` |
|
|
222
|
+
|
|
223
|
+
#### Type Configuration (`types`)
|
|
224
|
+
|
|
225
|
+
| Property | Type | Description |
|
|
226
|
+
| ------------- | ---------- | ---------------------------------- |
|
|
227
|
+
| `name.prefix` | `string` | Prefix for generated type names |
|
|
228
|
+
| `name.format` | `function` | Custom naming function for types |
|
|
229
|
+
| `doc.disable` | `boolean` | Disable JSDoc generation for types |
|
|
230
|
+
|
|
231
|
+
#### Endpoint Configuration (`endpoints`)
|
|
232
|
+
|
|
233
|
+
| Property | Type | Description |
|
|
234
|
+
| --------------------- | ---------------------- | -------------------------------------- |
|
|
235
|
+
| `value.replaceWords` | `IConfigReplaceWord[]` | URL transformation rules |
|
|
236
|
+
| `value.includeServer` | `boolean` | Include server URL in endpoints |
|
|
237
|
+
| `value.type` | `"string" \| "object"` | Output format for endpoints |
|
|
238
|
+
| `name.prefix` | `string` | Prefix for endpoint names |
|
|
239
|
+
| `name.useOperationId` | `boolean` | Use OpenAPI operationId for naming |
|
|
240
|
+
| `name.format` | `function` | Custom naming function for endpoints |
|
|
241
|
+
| `doc.disable` | `boolean` | Disable JSDoc generation for endpoints |
|
|
242
|
+
| `doc.showCurl` | `boolean` | Include cURL examples in documentation |
|
|
243
|
+
|
|
69
244
|
## Usage
|
|
70
245
|
|
|
71
|
-
### CLI
|
|
246
|
+
### CLI Usage
|
|
247
|
+
|
|
248
|
+
#### Basic Commands
|
|
72
249
|
|
|
73
250
|
```bash
|
|
74
|
-
#
|
|
251
|
+
# Run with default configuration
|
|
75
252
|
npx openapi-sync
|
|
76
253
|
|
|
77
|
-
#
|
|
254
|
+
# Run with custom refetch interval
|
|
78
255
|
npx openapi-sync --refreshinterval 30000
|
|
256
|
+
npx openapi-sync -ri 30000
|
|
257
|
+
|
|
258
|
+
# Get help
|
|
259
|
+
npx openapi-sync --help
|
|
79
260
|
```
|
|
80
261
|
|
|
262
|
+
#### CLI Options
|
|
263
|
+
|
|
264
|
+
| Option | Alias | Type | Description |
|
|
265
|
+
| ------------------- | ----- | -------- | ------------------------------------- |
|
|
266
|
+
| `--refreshinterval` | `-ri` | `number` | Override refetch interval from config |
|
|
267
|
+
|
|
81
268
|
### Programmatic Usage
|
|
82
269
|
|
|
270
|
+
#### Basic Usage
|
|
271
|
+
|
|
83
272
|
```typescript
|
|
84
273
|
import { Init } from "openapi-sync";
|
|
85
274
|
|
|
275
|
+
// Initialize with default config
|
|
276
|
+
await Init();
|
|
277
|
+
|
|
86
278
|
// Initialize with custom options
|
|
87
279
|
await Init({
|
|
88
|
-
refetchInterval: 30000,
|
|
280
|
+
refetchInterval: 30000,
|
|
89
281
|
});
|
|
90
282
|
```
|
|
91
283
|
|
|
92
|
-
|
|
284
|
+
#### Advanced Integration
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
import { Init } from "openapi-sync";
|
|
288
|
+
|
|
289
|
+
// In your application startup
|
|
290
|
+
export const initializeAPI = async () => {
|
|
291
|
+
try {
|
|
292
|
+
await Init({
|
|
293
|
+
refetchInterval: process.env.NODE_ENV === "development" ? 5000 : 0,
|
|
294
|
+
});
|
|
295
|
+
console.log("API types synchronized successfully");
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.error("Failed to sync API types:", error);
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// Call during app initialization
|
|
303
|
+
initializeAPI();
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### Function-based Configuration
|
|
93
307
|
|
|
94
|
-
|
|
308
|
+
```typescript
|
|
309
|
+
// openapi.sync.ts
|
|
310
|
+
import { IConfig } from "openapi-sync/types";
|
|
311
|
+
|
|
312
|
+
export default (): IConfig => {
|
|
313
|
+
const baseConfig = {
|
|
314
|
+
refetchInterval: 5000,
|
|
315
|
+
folder: "./src/api",
|
|
316
|
+
api: {},
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// Dynamic configuration based on environment
|
|
320
|
+
if (process.env.NODE_ENV === "development") {
|
|
321
|
+
baseConfig.api = {
|
|
322
|
+
"local-api": "http://localhost:3000/openapi.json",
|
|
323
|
+
};
|
|
324
|
+
} else {
|
|
325
|
+
baseConfig.api = {
|
|
326
|
+
"prod-api": "https://api.production.com/openapi.json",
|
|
327
|
+
};
|
|
328
|
+
}
|
|
95
329
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
4. Endpoint URL constants
|
|
330
|
+
return baseConfig;
|
|
331
|
+
};
|
|
332
|
+
```
|
|
100
333
|
|
|
101
|
-
##
|
|
334
|
+
## Generated Output
|
|
102
335
|
|
|
103
|
-
|
|
336
|
+
OpenAPI Sync generates a structured output in your specified folder:
|
|
104
337
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
-
|
|
111
|
-
|
|
338
|
+
```
|
|
339
|
+
src/api/
|
|
340
|
+
├── petstore/
|
|
341
|
+
│ ├── endpoints.ts # Endpoint URLs and metadata
|
|
342
|
+
│ └── types/
|
|
343
|
+
│ ├── index.ts # Endpoint-specific types
|
|
344
|
+
│ └── shared.ts # Shared component types
|
|
345
|
+
└── auth-api/
|
|
346
|
+
├── endpoints.ts
|
|
347
|
+
└── types/
|
|
348
|
+
├── index.ts
|
|
349
|
+
└── shared.ts
|
|
350
|
+
```
|
|
112
351
|
|
|
113
|
-
|
|
352
|
+
### Generated Endpoints
|
|
353
|
+
|
|
354
|
+
#### String Format (Default)
|
|
355
|
+
|
|
356
|
+
````typescript
|
|
357
|
+
// endpoints.ts
|
|
358
|
+
/**
|
|
359
|
+
* **Method**: `GET`
|
|
360
|
+
* **Summary**: Find pet by ID
|
|
361
|
+
* **Tags**: [pet]
|
|
362
|
+
* **OperationId**: getPetById
|
|
363
|
+
* **Response**:
|
|
364
|
+
* - **200**:
|
|
365
|
+
* ```typescript
|
|
366
|
+
* {
|
|
367
|
+
* "id": number;
|
|
368
|
+
* "name": string;
|
|
369
|
+
* "status": ("available"|"pending"|"sold");
|
|
370
|
+
* }
|
|
371
|
+
* ```
|
|
372
|
+
*
|
|
373
|
+
* ```bash
|
|
374
|
+
* curl -X GET "https://petstore3.swagger.io/api/v3/pet/123" \
|
|
375
|
+
* -H "accept: application/json"
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
export const getPetById = (petId: string) => `/pet/${petId}`;
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* **Method**: `POST`
|
|
382
|
+
* **Summary**: Add a new pet to the store
|
|
383
|
+
*/
|
|
384
|
+
export const addPet = "/pet";
|
|
385
|
+
````
|
|
386
|
+
|
|
387
|
+
#### Object Format
|
|
388
|
+
|
|
389
|
+
````typescript
|
|
390
|
+
// endpoints.ts (with type: "object")
|
|
391
|
+
/**
|
|
392
|
+
* **Method**: `POST`
|
|
393
|
+
* **Summary**: Add a new pet to the store
|
|
394
|
+
* **DTO**:
|
|
395
|
+
* ```typescript
|
|
396
|
+
* {
|
|
397
|
+
* "name": string;
|
|
398
|
+
* "photoUrls": string[];
|
|
399
|
+
* "status": ("available"|"pending"|"sold");
|
|
400
|
+
* }
|
|
401
|
+
* ```
|
|
402
|
+
*/
|
|
403
|
+
export const addPet = {
|
|
404
|
+
method: "POST",
|
|
405
|
+
operationId: "addPet",
|
|
406
|
+
url: "/pet",
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
export const getPetById = {
|
|
410
|
+
method: "GET",
|
|
411
|
+
operationId: "getPetById",
|
|
412
|
+
url: (petId: string) => `/pet/${petId}`,
|
|
413
|
+
};
|
|
414
|
+
````
|
|
415
|
+
|
|
416
|
+
### Generated Types
|
|
417
|
+
|
|
418
|
+
#### Endpoint Types
|
|
114
419
|
|
|
115
|
-
|
|
420
|
+
```typescript
|
|
421
|
+
// types/index.ts
|
|
422
|
+
import * as Shared from "./shared";
|
|
423
|
+
|
|
424
|
+
// Query parameter types
|
|
425
|
+
export type IFindPetsByStatusQuery = {
|
|
426
|
+
status?: "available" | "pending" | "sold";
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// Request body types (DTO)
|
|
430
|
+
export type IAddPetDTO = {
|
|
431
|
+
id?: number;
|
|
432
|
+
name: string;
|
|
433
|
+
category?: Shared.ICategory;
|
|
434
|
+
photoUrls: string[];
|
|
435
|
+
tags?: Shared.ITag[];
|
|
436
|
+
status?: "available" | "pending" | "sold";
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// Response types
|
|
440
|
+
export type IGetPetById200Response = {
|
|
441
|
+
id?: number;
|
|
442
|
+
name: string;
|
|
443
|
+
category?: Shared.ICategory;
|
|
444
|
+
photoUrls: string[];
|
|
445
|
+
tags?: Shared.ITag[];
|
|
446
|
+
status?: "available" | "pending" | "sold";
|
|
447
|
+
};
|
|
448
|
+
```
|
|
116
449
|
|
|
117
|
-
|
|
118
|
-
- Schema validation
|
|
119
|
-
- Type generation error handling
|
|
120
|
-
- State persistence
|
|
450
|
+
#### Shared Component Types
|
|
121
451
|
|
|
122
|
-
|
|
452
|
+
```typescript
|
|
453
|
+
// types/shared.ts
|
|
454
|
+
/**
|
|
455
|
+
* A category for a pet
|
|
456
|
+
*/
|
|
457
|
+
export type ICategory = {
|
|
458
|
+
id?: number;
|
|
459
|
+
name?: string;
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* A tag for a pet
|
|
464
|
+
*/
|
|
465
|
+
export type ITag = {
|
|
466
|
+
id?: number;
|
|
467
|
+
name?: string;
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
export type IPet = {
|
|
471
|
+
id?: number;
|
|
472
|
+
name: string;
|
|
473
|
+
category?: ICategory;
|
|
474
|
+
photoUrls: string[];
|
|
475
|
+
tags?: ITag[];
|
|
476
|
+
status?: "available" | "pending" | "sold";
|
|
477
|
+
};
|
|
478
|
+
```
|
|
123
479
|
|
|
124
|
-
|
|
480
|
+
## API Reference
|
|
125
481
|
|
|
126
|
-
|
|
482
|
+
### Exported Functions
|
|
127
483
|
|
|
128
|
-
|
|
484
|
+
#### `Init(options?: { refetchInterval?: number }): Promise<void>`
|
|
485
|
+
|
|
486
|
+
Initializes OpenAPI sync with the specified configuration.
|
|
487
|
+
|
|
488
|
+
**Parameters:**
|
|
489
|
+
|
|
490
|
+
- `options.refetchInterval` - Override the refetch interval from config file
|
|
491
|
+
|
|
492
|
+
**Example:**
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
import { Init } from "openapi-sync";
|
|
496
|
+
|
|
497
|
+
await Init({ refetchInterval: 10000 });
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Exported Types
|
|
501
|
+
|
|
502
|
+
All types from the `types.ts` file are available for import:
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
import {
|
|
506
|
+
IConfig,
|
|
507
|
+
IOpenApiSpec,
|
|
508
|
+
IOpenApSchemaSpec,
|
|
509
|
+
IConfigReplaceWord,
|
|
510
|
+
} from "openapi-sync/types";
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
## Advanced Examples
|
|
514
|
+
|
|
515
|
+
### Multi-Environment Configuration
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
// openapi.sync.ts
|
|
519
|
+
import { IConfig } from "openapi-sync/types";
|
|
520
|
+
|
|
521
|
+
const getConfig = (): IConfig => {
|
|
522
|
+
const env = process.env.NODE_ENV || "development";
|
|
523
|
+
|
|
524
|
+
const baseConfig: IConfig = {
|
|
525
|
+
refetchInterval: env === "development" ? 5000 : 0,
|
|
526
|
+
folder: "./src/api",
|
|
527
|
+
api: {},
|
|
528
|
+
types: {
|
|
529
|
+
name: {
|
|
530
|
+
prefix: "I",
|
|
531
|
+
format: (source, data, defaultName) => {
|
|
532
|
+
if (source === "endpoint" && data.type === "response") {
|
|
533
|
+
return `${defaultName.replace(/Response$/, "")}Data`;
|
|
534
|
+
}
|
|
535
|
+
return defaultName;
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
switch (env) {
|
|
542
|
+
case "development":
|
|
543
|
+
baseConfig.api = {
|
|
544
|
+
"local-api": "http://localhost:3000/api/openapi.json",
|
|
545
|
+
};
|
|
546
|
+
break;
|
|
547
|
+
case "staging":
|
|
548
|
+
baseConfig.api = {
|
|
549
|
+
"staging-api": "https://staging-api.example.com/openapi.json",
|
|
550
|
+
};
|
|
551
|
+
break;
|
|
552
|
+
case "production":
|
|
553
|
+
baseConfig.api = {
|
|
554
|
+
"prod-api": "https://api.example.com/openapi.json",
|
|
555
|
+
};
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return baseConfig;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
export default getConfig;
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Custom Type Formatting
|
|
566
|
+
|
|
567
|
+
```typescript
|
|
568
|
+
// Advanced type name formatting
|
|
569
|
+
const config: IConfig = {
|
|
570
|
+
// ... other config
|
|
571
|
+
types: {
|
|
572
|
+
name: {
|
|
573
|
+
prefix: "",
|
|
574
|
+
format: (source, data, defaultName) => {
|
|
575
|
+
if (source === "shared") {
|
|
576
|
+
// Shared types: UserProfile, OrderStatus, etc.
|
|
577
|
+
return `${data.name}`;
|
|
578
|
+
} else if (source === "endpoint") {
|
|
579
|
+
const method = data.method?.toUpperCase();
|
|
580
|
+
const cleanPath = data.path
|
|
581
|
+
?.replace(/[{}\/]/g, "_")
|
|
582
|
+
.replace(/_+/g, "_");
|
|
583
|
+
|
|
584
|
+
switch (data.type) {
|
|
585
|
+
case "query":
|
|
586
|
+
return `${method}${cleanPath}Query`;
|
|
587
|
+
case "dto":
|
|
588
|
+
return `${method}${cleanPath}Request`;
|
|
589
|
+
case "response":
|
|
590
|
+
return `${method}${cleanPath}${data.code}Response`;
|
|
591
|
+
default:
|
|
592
|
+
return defaultName;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return defaultName;
|
|
596
|
+
},
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
};
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### URL Transformation Rules
|
|
603
|
+
|
|
604
|
+
```typescript
|
|
605
|
+
const config: IConfig = {
|
|
606
|
+
// ... other config
|
|
607
|
+
endpoints: {
|
|
608
|
+
value: {
|
|
609
|
+
replaceWords: [
|
|
610
|
+
// Remove API versioning from URLs
|
|
611
|
+
{
|
|
612
|
+
replace: "/api/v[0-9]+/",
|
|
613
|
+
with: "/",
|
|
614
|
+
},
|
|
615
|
+
// Remove internal prefixes
|
|
616
|
+
{
|
|
617
|
+
replace: "/internal/",
|
|
618
|
+
with: "/",
|
|
619
|
+
},
|
|
620
|
+
// Transform specific paths
|
|
621
|
+
{
|
|
622
|
+
replace: "/users/profile",
|
|
623
|
+
with: "/profile",
|
|
624
|
+
},
|
|
625
|
+
],
|
|
626
|
+
includeServer: true,
|
|
627
|
+
type: "object",
|
|
628
|
+
},
|
|
629
|
+
name: {
|
|
630
|
+
format: ({ method, path, operationId }, defaultName) => {
|
|
631
|
+
// Use operationId if available, otherwise generate from path
|
|
632
|
+
if (operationId) {
|
|
633
|
+
return operationId.replace(/[^a-zA-Z0-9]/g, "");
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Generate meaningful names from path and method
|
|
637
|
+
const cleanPath = path
|
|
638
|
+
.replace(/^\//, "")
|
|
639
|
+
.replace(/\//g, "_")
|
|
640
|
+
.replace(/{([^}]+)}/g, "By$1")
|
|
641
|
+
.replace(/[^a-zA-Z0-9_]/g, "");
|
|
642
|
+
|
|
643
|
+
return `${method.toLowerCase()}${cleanPath}`;
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
},
|
|
647
|
+
};
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Integration with Build Process
|
|
651
|
+
|
|
652
|
+
#### Package.json Scripts
|
|
653
|
+
|
|
654
|
+
```json
|
|
655
|
+
{
|
|
656
|
+
"scripts": {
|
|
657
|
+
"api:sync": "openapi-sync",
|
|
658
|
+
"api:sync:watch": "openapi-sync --refreshinterval 3000",
|
|
659
|
+
"prebuild": "npm run api:sync",
|
|
660
|
+
"build": "tsc",
|
|
661
|
+
"dev": "concurrently \"npm run api:sync:watch\" \"npm run dev:server\""
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
#### Pre-commit Hook
|
|
667
|
+
|
|
668
|
+
```bash
|
|
669
|
+
#!/bin/sh
|
|
670
|
+
# .husky/pre-commit
|
|
671
|
+
|
|
672
|
+
# Sync API types before commit
|
|
673
|
+
npm run api:sync
|
|
674
|
+
|
|
675
|
+
# Add generated files to commit
|
|
676
|
+
git add src/api/
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
#### CI/CD Integration
|
|
680
|
+
|
|
681
|
+
```yaml
|
|
682
|
+
# .github/workflows/build.yml
|
|
683
|
+
name: Build
|
|
684
|
+
on: [push, pull_request]
|
|
685
|
+
|
|
686
|
+
jobs:
|
|
687
|
+
build:
|
|
688
|
+
runs-on: ubuntu-latest
|
|
689
|
+
steps:
|
|
690
|
+
- uses: actions/checkout@v2
|
|
691
|
+
- uses: actions/setup-node@v2
|
|
692
|
+
with:
|
|
693
|
+
node-version: "16"
|
|
694
|
+
|
|
695
|
+
- name: Install dependencies
|
|
696
|
+
run: npm ci
|
|
697
|
+
|
|
698
|
+
- name: Sync API types
|
|
699
|
+
run: npm run api:sync
|
|
700
|
+
env:
|
|
701
|
+
NODE_ENV: production
|
|
702
|
+
|
|
703
|
+
- name: Build
|
|
704
|
+
run: npm run build
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### Error Handling and Monitoring
|
|
708
|
+
|
|
709
|
+
```typescript
|
|
710
|
+
import { Init } from "openapi-sync";
|
|
711
|
+
|
|
712
|
+
const initializeAPIWithRetry = async (maxRetries = 3) => {
|
|
713
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
714
|
+
try {
|
|
715
|
+
await Init({
|
|
716
|
+
refetchInterval: process.env.NODE_ENV === "development" ? 5000 : 0,
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
console.log("✅ API types synchronized successfully");
|
|
720
|
+
return;
|
|
721
|
+
} catch (error) {
|
|
722
|
+
console.error(`❌ Attempt ${attempt} failed:`, error.message);
|
|
723
|
+
|
|
724
|
+
if (attempt === maxRetries) {
|
|
725
|
+
console.error("🚨 Failed to sync API types after all retries");
|
|
726
|
+
throw error;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Wait before retry
|
|
730
|
+
await new Promise((resolve) => setTimeout(resolve, 2000 * attempt));
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
// Usage in your app
|
|
736
|
+
initializeAPIWithRetry().catch((error) => {
|
|
737
|
+
// Handle critical error - maybe use cached types or exit
|
|
738
|
+
console.error("Critical: Could not sync API types", error);
|
|
739
|
+
process.exit(1);
|
|
740
|
+
});
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
## Troubleshooting
|
|
744
|
+
|
|
745
|
+
### Common Issues
|
|
746
|
+
|
|
747
|
+
#### 1. Configuration File Not Found
|
|
748
|
+
|
|
749
|
+
```
|
|
750
|
+
Error: No config found
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
**Solution:** Ensure you have one of these files in your project root:
|
|
754
|
+
|
|
755
|
+
- `openapi.sync.json`
|
|
756
|
+
- `openapi.sync.ts`
|
|
757
|
+
- `openapi.sync.js`
|
|
758
|
+
|
|
759
|
+
#### 2. Network Timeout Errors
|
|
760
|
+
|
|
761
|
+
```
|
|
762
|
+
Error: timeout of 60000ms exceeded
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
**Solution:** The tool includes automatic retry with exponential backoff. If issues persist:
|
|
766
|
+
|
|
767
|
+
- Check your internet connection
|
|
768
|
+
- Verify the OpenAPI spec URL is accessible
|
|
769
|
+
- Consider increasing timeout in your configuration
|
|
770
|
+
|
|
771
|
+
#### 3. TypeScript Compilation Errors
|
|
772
|
+
|
|
773
|
+
```
|
|
774
|
+
Error: Cannot find module './src/api/petstore/types'
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
**Solution:**
|
|
778
|
+
|
|
779
|
+
- Ensure the sync process completed successfully
|
|
780
|
+
- Check that the `folder` path in config is correct
|
|
781
|
+
- Verify TypeScript can resolve the generated paths
|
|
782
|
+
|
|
783
|
+
#### 4. Invalid OpenAPI Specification
|
|
784
|
+
|
|
785
|
+
```
|
|
786
|
+
Error: Schema validation failed
|
|
787
|
+
```
|
|
129
788
|
|
|
130
|
-
|
|
789
|
+
**Solution:**
|
|
790
|
+
|
|
791
|
+
- Validate your OpenAPI spec using online validators
|
|
792
|
+
- Check for syntax errors in YAML/JSON
|
|
793
|
+
- Ensure the spec follows OpenAPI 3.0+ standards
|
|
794
|
+
|
|
795
|
+
### Performance Optimization
|
|
796
|
+
|
|
797
|
+
#### 1. Reduce Refetch Frequency
|
|
798
|
+
|
|
799
|
+
```json
|
|
800
|
+
{
|
|
801
|
+
"refetchInterval": 30000 // Increase to 30 seconds
|
|
802
|
+
}
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
#### 2. Disable Documentation Generation
|
|
806
|
+
|
|
807
|
+
```json
|
|
808
|
+
{
|
|
809
|
+
"types": { "doc": { "disable": true } },
|
|
810
|
+
"endpoints": { "doc": { "disable": true } }
|
|
811
|
+
}
|
|
812
|
+
```
|
|
131
813
|
|
|
132
|
-
|
|
814
|
+
#### 3. Use Specific Output Folders
|
|
815
|
+
|
|
816
|
+
```json
|
|
817
|
+
{
|
|
818
|
+
"folder": "./src/api" // Specific path instead of root
|
|
819
|
+
}
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
### Debugging
|
|
823
|
+
|
|
824
|
+
#### Enable Verbose Logging
|
|
825
|
+
|
|
826
|
+
```typescript
|
|
827
|
+
// Set environment variable for debugging
|
|
828
|
+
process.env.DEBUG = "openapi-sync:*";
|
|
829
|
+
|
|
830
|
+
import { Init } from "openapi-sync";
|
|
831
|
+
await Init();
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
#### Check Generated State
|
|
835
|
+
|
|
836
|
+
The tool maintains state in `db.json` to track changes:
|
|
837
|
+
|
|
838
|
+
```json
|
|
839
|
+
// db.json
|
|
840
|
+
{
|
|
841
|
+
"petstore": {
|
|
842
|
+
"openapi": "3.0.0",
|
|
843
|
+
"info": { "title": "Petstore API" }
|
|
844
|
+
// ... full OpenAPI spec
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### Getting Help
|
|
850
|
+
|
|
851
|
+
1. **Check the Issues**: [GitHub Issues](https://github.com/akintomiwa-fisayo/openapi-sync/issues)
|
|
852
|
+
2. **Create a Bug Report**: Include your configuration and error logs
|
|
853
|
+
3. **Feature Requests**: Describe your use case and expected behavior
|
|
854
|
+
|
|
855
|
+
---
|
|
856
|
+
|
|
857
|
+
## License
|
|
858
|
+
|
|
859
|
+
This project is licensed under the ISC License - see the [LICENSE](LICENSE) file for details.
|
|
133
860
|
|
|
134
|
-
##
|
|
861
|
+
## Contributing
|
|
135
862
|
|
|
136
|
-
|
|
137
|
-
- Thanks to all contributors and users of this package
|
|
138
|
-
- Flexible CLI Commands: Sync your API at any point in the development process on app start, pre-commit, or via manual triggers.
|
|
863
|
+
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.
|