openapi-domainify 0.1.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.
- package/LICENSE +21 -0
- package/README.md +303 -0
- package/bin/cli.js +2 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +886 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +808 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# openapi-domainify
|
|
2
|
+
|
|
3
|
+
**Split your OpenAPI spec into domain-based TypeScript services.**
|
|
4
|
+
|
|
5
|
+
Most OpenAPI generators dump everything into a single file or force you to restructure your spec. This tool reads your existing spec and generates modular, domain-separated service classes based on URL path prefixes.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Your config
|
|
9
|
+
domains: [
|
|
10
|
+
{ name: 'auth', prefix: '/auth/' },
|
|
11
|
+
{ name: 'billing', prefix: '/billing/' },
|
|
12
|
+
{ name: 'users', prefix: '/users/' },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
// Generated usage
|
|
16
|
+
api.auth.login({ email, password })
|
|
17
|
+
api.billing.getInvoice(invoiceId)
|
|
18
|
+
api.users.updateProfile(userId, data)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Why This Exists
|
|
24
|
+
|
|
25
|
+
Every OpenAPI TypeScript generator on npm does one of these:
|
|
26
|
+
|
|
27
|
+
| Tool | Approach | Problem |
|
|
28
|
+
|------|----------|---------|
|
|
29
|
+
| `openapi-typescript` | Types only | No service layer |
|
|
30
|
+
| `openapi-fetch` | Single client | One massive file |
|
|
31
|
+
| `@hey-api/openapi-ts` | Tag-based grouping | Requires spec changes |
|
|
32
|
+
| `orval` | React Query focused | Framework lock-in |
|
|
33
|
+
| `openapi-generator` | Mustache templates | 15MB dependency, Java heritage |
|
|
34
|
+
|
|
35
|
+
**openapi-domainify** uses path prefixes from your existing URLs. No spec modifications. No framework coupling. Just TypeScript.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -D openapi-domainify
|
|
43
|
+
# or
|
|
44
|
+
pnpm add -D openapi-domainify
|
|
45
|
+
# or
|
|
46
|
+
bun add -D openapi-domainify
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### 1. Create config file
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx openapi-domainify init
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This creates `domainify.config.ts`:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { defineConfig } from 'openapi-domainify'
|
|
63
|
+
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
// OpenAPI spec source (URL or local file path)
|
|
66
|
+
input: 'https://api.example.com/openapi.json',
|
|
67
|
+
|
|
68
|
+
// Where to write generated code
|
|
69
|
+
output: './src/api',
|
|
70
|
+
|
|
71
|
+
// Domain splitting rules (order matters - first match wins)
|
|
72
|
+
domains: [
|
|
73
|
+
{ name: 'auth', prefix: '/auth/', className: 'Auth' },
|
|
74
|
+
{ name: 'users', prefix: '/users/', className: 'Users' },
|
|
75
|
+
],
|
|
76
|
+
|
|
77
|
+
// Catch-all for unmatched paths
|
|
78
|
+
fallback: { name: 'api', prefix: '/', className: 'Api' },
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Generate
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npx openapi-domainify generate
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Output structure:
|
|
89
|
+
```
|
|
90
|
+
src/api/
|
|
91
|
+
├── index.ts # API client (regenerated each time)
|
|
92
|
+
├── http.ts # HTTP client template (safe to edit)
|
|
93
|
+
├── generated/ # Auto-generated (DO NOT EDIT)
|
|
94
|
+
│ ├── openapi.json
|
|
95
|
+
│ ├── openapi.ts
|
|
96
|
+
│ ├── auth/
|
|
97
|
+
│ │ ├── service.ts
|
|
98
|
+
│ │ └── types.ts
|
|
99
|
+
│ └── users/
|
|
100
|
+
│ ├── service.ts
|
|
101
|
+
│ └── types.ts
|
|
102
|
+
└── overrides/ # Your customizations (safe to edit)
|
|
103
|
+
├── auth/
|
|
104
|
+
│ └── service.ts # Extend/override AuthService
|
|
105
|
+
└── users/
|
|
106
|
+
└── service.ts # Extend/override UsersService
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Overrides
|
|
112
|
+
|
|
113
|
+
When the generated code has issues or you need custom methods, create an override instead of editing generated files:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// overrides/users/service.ts
|
|
117
|
+
import { UsersService as GeneratedUsersService } from '../generated/users/service'
|
|
118
|
+
import type { HttpClient } from '../../http'
|
|
119
|
+
|
|
120
|
+
export class UsersService extends GeneratedUsersService {
|
|
121
|
+
constructor(http: HttpClient) {
|
|
122
|
+
super(http)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Override a broken method
|
|
126
|
+
async getUser(id: string | number) {
|
|
127
|
+
// Custom implementation
|
|
128
|
+
return this.http.get(`/users/${id}`)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Add a method not in the OpenAPI spec
|
|
132
|
+
async customEndpoint() {
|
|
133
|
+
return this.http.post('/users/custom')
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The generator:
|
|
139
|
+
- **Never overwrites** existing override files
|
|
140
|
+
- **Always regenerates** `generated/` and `index.ts`
|
|
141
|
+
- **Auto-detects** if you've customized an override and uses it in `index.ts`
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Generated Code
|
|
146
|
+
|
|
147
|
+
### Service Classes
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// generated/users/service.ts
|
|
151
|
+
import type { HttpClient } from '../../http'
|
|
152
|
+
import type * as T from './types'
|
|
153
|
+
|
|
154
|
+
export class UsersService {
|
|
155
|
+
constructor(private http: HttpClient) {}
|
|
156
|
+
|
|
157
|
+
// GET /users
|
|
158
|
+
users(params?: T.GetUsersQuery): Promise<T.GetUsersResponse> {
|
|
159
|
+
return this.http.get('/users', { params })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// GET /users/{id}
|
|
163
|
+
getUser(id: string | number): Promise<T.GetUsersByIdResponse> {
|
|
164
|
+
return this.http.get(`/users/${id}`)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// POST /users
|
|
168
|
+
createUser(data: T.PostUsersRequest): Promise<T.PostUsersResponse> {
|
|
169
|
+
return this.http.post('/users', data)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Type Extraction
|
|
175
|
+
|
|
176
|
+
Types are extracted directly from your OpenAPI spec using the TypeScript Compiler API:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// generated/users/types.ts
|
|
180
|
+
|
|
181
|
+
// Request types
|
|
182
|
+
export type PostUsersRequest = {
|
|
183
|
+
email: string
|
|
184
|
+
name: string
|
|
185
|
+
role?: 'admin' | 'user'
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Response types
|
|
189
|
+
export type GetUsersResponse = {
|
|
190
|
+
data: Array<{
|
|
191
|
+
id: number
|
|
192
|
+
email: string
|
|
193
|
+
name: string
|
|
194
|
+
}>
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## HTTP Client
|
|
201
|
+
|
|
202
|
+
The generator creates an `http.ts` template with a `FetchHttpClient` implementation. Edit it or replace with your preferred HTTP library:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// http.ts (generated once, safe to edit)
|
|
206
|
+
export interface HttpClient {
|
|
207
|
+
get<T>(url: string, options?: { params?: Record<string, unknown> }): Promise<T>
|
|
208
|
+
post<T>(url: string, body?: Record<string, unknown>): Promise<T>
|
|
209
|
+
put<T>(url: string, body?: Record<string, unknown>): Promise<T>
|
|
210
|
+
patch<T>(url: string, body?: Record<string, unknown>): Promise<T>
|
|
211
|
+
delete<T>(url: string, options?: { params?: Record<string, unknown> }): Promise<T>
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Configuration Reference
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import { defineConfig } from 'openapi-domainify'
|
|
221
|
+
|
|
222
|
+
export default defineConfig({
|
|
223
|
+
// Required: OpenAPI spec source
|
|
224
|
+
input: 'https://api.example.com/openapi.json',
|
|
225
|
+
|
|
226
|
+
// Required: Output directory
|
|
227
|
+
output: './src/api',
|
|
228
|
+
|
|
229
|
+
// Required: Domain splitting rules
|
|
230
|
+
domains: [
|
|
231
|
+
{
|
|
232
|
+
name: 'auth', // Directory name
|
|
233
|
+
prefix: '/auth/', // URL prefix to match
|
|
234
|
+
className: 'Auth' // Generated class name suffix
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
|
|
238
|
+
// Optional: Catch-all for unmatched paths
|
|
239
|
+
fallback: { name: 'api', prefix: '/', className: 'Api' },
|
|
240
|
+
|
|
241
|
+
// Optional: Strip this prefix from all paths
|
|
242
|
+
stripPrefix: '/api/v1',
|
|
243
|
+
|
|
244
|
+
// Optional: Where to save the downloaded spec
|
|
245
|
+
specOutput: './src/api/generated/openapi.json',
|
|
246
|
+
|
|
247
|
+
// Optional: Custom HTTP client import path
|
|
248
|
+
httpClientImport: '../../http',
|
|
249
|
+
|
|
250
|
+
// Optional: Override files directory (relative to output)
|
|
251
|
+
overridesDir: '../overrides',
|
|
252
|
+
|
|
253
|
+
// Optional: Generate index.ts (default: true)
|
|
254
|
+
generateIndex: true,
|
|
255
|
+
})
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Method Naming Convention
|
|
261
|
+
|
|
262
|
+
Generated method names follow RESTful conventions:
|
|
263
|
+
|
|
264
|
+
| HTTP Method | Path | Generated Method |
|
|
265
|
+
|-------------|------|------------------|
|
|
266
|
+
| `GET` | `/users` | `users()` |
|
|
267
|
+
| `GET` | `/users/{id}` | `getUser(id)` |
|
|
268
|
+
| `POST` | `/users` | `createUser(data)` |
|
|
269
|
+
| `PUT` | `/users/{id}` | `updateUser(id, data)` |
|
|
270
|
+
| `PATCH` | `/users/{id}` | `patchUser(id, data)` |
|
|
271
|
+
| `DELETE` | `/users/{id}` | `deleteUser(id)` |
|
|
272
|
+
| `GET` | `/users/{id}/orders` | `getUserOrders(id)` |
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## How It Works
|
|
277
|
+
|
|
278
|
+
1. **Fetch spec** — Downloads OpenAPI JSON from URL or reads local file
|
|
279
|
+
2. **Generate types** — Runs `openapi-typescript` to create base TypeScript types
|
|
280
|
+
3. **Parse with TS Compiler API** — Loads generated types into TypeScript's type checker
|
|
281
|
+
4. **Extract endpoints** — Iterates over `paths` interface, extracting methods, params, bodies
|
|
282
|
+
5. **Group by domain** — Matches each path against configured prefixes
|
|
283
|
+
6. **Generate services** — Creates service classes with fully typed methods
|
|
284
|
+
7. **Generate scaffolding** — Creates override templates (only if they don't exist)
|
|
285
|
+
8. **Wire up index** — Generates `index.ts` that imports from overrides or generated
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Comparison
|
|
290
|
+
|
|
291
|
+
| Feature | openapi-domainify | openapi-fetch | @hey-api/openapi-ts | orval |
|
|
292
|
+
|---------|-------------------|---------------|---------------------|-------|
|
|
293
|
+
| Domain splitting | ✅ Path prefix | ❌ | ⚠️ Tags only | ❌ |
|
|
294
|
+
| No spec changes | ✅ | ✅ | ❌ | ✅ |
|
|
295
|
+
| Override system | ✅ | ❌ | ❌ | ❌ |
|
|
296
|
+
| Framework agnostic | ✅ | ✅ | ✅ | ❌ React Query |
|
|
297
|
+
| Service classes | ✅ | ❌ | ✅ | ✅ |
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## License
|
|
302
|
+
|
|
303
|
+
MIT
|
package/bin/cli.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|