@cognisivelabs/openapi-to-express 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sachin Gupta
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,362 @@
1
+ # @cognisivelabs/openapi-to-express
2
+
3
+ Generate Express routes, controller interfaces, and TypeScript types from an OpenAPI spec. Design-first API development — define your contract first, the compiler enforces it.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -D @cognisivelabs/openapi-to-express
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ npx openapi-to-express -i openapi.json -o src
15
+ ```
16
+
17
+ This reads your OpenAPI spec and generates files grouped by **tag**:
18
+
19
+ ```
20
+ src/
21
+ ├── types/
22
+ │ ├── users.types.ts # TypeScript interfaces and enums
23
+ │ └── index.ts # Barrel re-exports
24
+ ├── controllers/
25
+ │ ├── users.controller.interface.ts # UsersController interface
26
+ │ └── index.ts
27
+ └── routes/
28
+ ├── users.routes.ts # Complete Express router
29
+ └── index.ts
30
+ ```
31
+
32
+ Each tag in your spec gets its own types, controller interface, and routes file. Schemas shared across tags go to `common.types.ts` automatically.
33
+
34
+ ## Step-by-Step Usage
35
+
36
+ ### 1. Write your OpenAPI spec
37
+
38
+ ```yaml
39
+ # openapi.yaml
40
+ openapi: "3.0.3"
41
+ info:
42
+ title: User API
43
+ version: "1.0.0"
44
+ paths:
45
+ /users/{id}:
46
+ get:
47
+ operationId: getUserById
48
+ tags: [Users]
49
+ parameters:
50
+ - name: id
51
+ in: path
52
+ required: true
53
+ schema:
54
+ type: string
55
+ responses:
56
+ "200":
57
+ description: User found
58
+ content:
59
+ application/json:
60
+ schema:
61
+ $ref: "#/components/schemas/User"
62
+ /users:
63
+ post:
64
+ operationId: createUser
65
+ tags: [Users]
66
+ requestBody:
67
+ required: true
68
+ content:
69
+ application/json:
70
+ schema:
71
+ $ref: "#/components/schemas/CreateUserRequest"
72
+ responses:
73
+ "201":
74
+ description: User created
75
+ content:
76
+ application/json:
77
+ schema:
78
+ $ref: "#/components/schemas/User"
79
+ components:
80
+ schemas:
81
+ User:
82
+ type: object
83
+ required: [id, name, email]
84
+ properties:
85
+ id:
86
+ type: string
87
+ format: uuid
88
+ name:
89
+ type: string
90
+ email:
91
+ type: string
92
+ format: email
93
+ CreateUserRequest:
94
+ type: object
95
+ required: [name, email]
96
+ properties:
97
+ name:
98
+ type: string
99
+ email:
100
+ type: string
101
+ ```
102
+
103
+ ### 2. Generate code
104
+
105
+ ```bash
106
+ npx openapi-to-express -i openapi.yaml -o src
107
+ ```
108
+
109
+ ### 3. See what was generated
110
+
111
+ **Types** (`src/types/users.types.ts`):
112
+
113
+ ```typescript
114
+ export interface User {
115
+ /** @format uuid */
116
+ id: string;
117
+ name: string;
118
+ /** @format email */
119
+ email: string;
120
+ }
121
+
122
+ export interface CreateUserRequest {
123
+ name: string;
124
+ email: string;
125
+ }
126
+ ```
127
+
128
+ **Controller interface** (`src/controllers/users.controller.interface.ts`):
129
+
130
+ ```typescript
131
+ import type { Request, Response } from "express";
132
+
133
+ export interface UsersController {
134
+ getUserById(req: Request, res: Response): Promise<void>;
135
+ createUser(req: Request, res: Response): Promise<void>;
136
+ }
137
+ ```
138
+
139
+ **Routes** (`src/routes/users.routes.ts`) — lean, one line per endpoint:
140
+
141
+ ```typescript
142
+ import { Router } from "express";
143
+ import type { UsersController } from "../controllers/users.controller.interface";
144
+
145
+ export function createUsersRouter(controller: UsersController, middleware?: any[]): Router {
146
+ const router = Router();
147
+
148
+ if (middleware) {
149
+ middleware.forEach((mw) => router.use(mw));
150
+ }
151
+
152
+ router.get("/users/:id", (req, res) => controller.getUserById(req, res));
153
+ router.post("/users", (req, res) => controller.createUser(req, res));
154
+
155
+ return router;
156
+ }
157
+ ```
158
+
159
+ ### 4. Implement the controller
160
+
161
+ The controller owns the HTTP layer — param extraction, response formatting, error handling:
162
+
163
+ ```typescript
164
+ // src/controllers/users.controller.ts
165
+ import type { Request, Response } from "express";
166
+ import type { UsersController } from "./users.controller.interface";
167
+ import type { User } from "../types/users.types";
168
+
169
+ export class UsersControllerImpl implements UsersController {
170
+ constructor(private readonly userService: UserService) {}
171
+
172
+ async getUserById(req: Request, res: Response): Promise<void> {
173
+ try {
174
+ const id = req.params.id;
175
+ const user = await this.userService.findById(id);
176
+ res.json(user);
177
+ } catch (err: any) {
178
+ res.status(err.status ?? 500).json({ message: err.message });
179
+ }
180
+ }
181
+
182
+ async createUser(req: Request, res: Response): Promise<void> {
183
+ try {
184
+ const user = await this.userService.create(req.body);
185
+ res.status(201).json(user);
186
+ } catch (err: any) {
187
+ res.status(err.status ?? 500).json({ message: err.message });
188
+ }
189
+ }
190
+
191
+ async createUser(request: CreateUserRequest): Promise<User> {
192
+ }
193
+ }
194
+ ```
195
+
196
+ ### 5. Wire it in your server
197
+
198
+ ```typescript
199
+ // src/server.ts
200
+ import express from "express";
201
+ import { createUsersRouter } from "./routes/users.routes";
202
+ import { UsersControllerImpl } from "./controllers/users.controller";
203
+ import { UserServiceImpl } from "./services/user.service";
204
+
205
+ const app = express();
206
+ app.use(express.json());
207
+
208
+ const userService = new UserServiceImpl();
209
+ const controller = new UsersControllerImpl(userService);
210
+ app.use("/api/v1", createUsersRouter(controller));
211
+
212
+ app.listen(3000);
213
+ ```
214
+
215
+ ### 6. When the spec changes
216
+
217
+ ```bash
218
+ # Architect adds a new endpoint to openapi.yaml
219
+ npx openapi-to-express -i openapi.yaml -o src
220
+
221
+ # TypeScript now fails — UsersControllerImpl doesn't implement the new method
222
+ # Developer adds the implementation, tsc passes, contract enforced
223
+ ```
224
+
225
+ ## CLI Options
226
+
227
+ ```
228
+ Usage:
229
+ openapi-to-express --input <spec> --output <dir> [options]
230
+ openapi-to-express (reads from .openapi-to-expressrc.json)
231
+
232
+ Required (unless provided in config file):
233
+ -i, --input <value> OpenAPI spec — file path (.json/.yaml/.yml), URL, or string
234
+ -o, --output <value> Output directory (e.g. "src")
235
+
236
+ Optional:
237
+ --types-dir <name> Folder name for types (default: "types")
238
+ --controllers-dir <name> Folder name for controllers (default: "controllers")
239
+ --routes-dir <name> Folder name for routes (default: "routes")
240
+ --dry-run Show what would be generated without writing files
241
+ -w, --watch Watch spec file and regenerate on changes
242
+ -v, --version Output version number
243
+ -h, --help Show help
244
+
245
+ Examples:
246
+ npx openapi-to-express -i openapi.json -o src
247
+ npx openapi-to-express -i openapi.yaml -o src
248
+ npx openapi-to-express -i https://petstore3.swagger.io/api/v3/openapi.json -o src
249
+ npx openapi-to-express -i openapi.json -o src --types-dir models --controllers-dir interfaces
250
+ npx openapi-to-express -i openapi.json -o src --dry-run
251
+ npx openapi-to-express -i openapi.json -o src --watch
252
+ ```
253
+
254
+ ## Config File
255
+
256
+ Create `.openapi-to-expressrc.json` in your project root to avoid repeating CLI flags:
257
+
258
+ ```json
259
+ {
260
+ "input": "openapi.yaml",
261
+ "output": "src",
262
+ "types-dir": "types",
263
+ "controllers-dir": "controllers",
264
+ "routes-dir": "routes"
265
+ }
266
+ ```
267
+
268
+ Then just run:
269
+
270
+ ```bash
271
+ npx openapi-to-express
272
+ ```
273
+
274
+ CLI flags override config file values.
275
+
276
+ ## Programmatic API
277
+
278
+ ```typescript
279
+ import { generate } from "@cognisivelabs/openapi-to-express";
280
+
281
+ await generate({
282
+ input: "openapi.json",
283
+ output: "src",
284
+ dryRun: false,
285
+ dirs: {
286
+ types: "models",
287
+ controllers: "interfaces",
288
+ routes: "api",
289
+ },
290
+ });
291
+ ```
292
+
293
+ ## Supported OpenAPI Features
294
+
295
+ ### Schemas
296
+
297
+ | Feature | Generated TypeScript |
298
+ |---|---|
299
+ | `type: object` with `properties` | `export interface Name { ... }` |
300
+ | `type: string / number / integer / boolean` | `string`, `number`, `boolean` |
301
+ | `type: array` | `Type[]` |
302
+ | `$ref` | Resolved type name |
303
+ | `enum` (string) | Named `const` object + type alias |
304
+ | `enum` (integer) | Named `const` object with number values |
305
+ | `required` / optional | Required fields, `?` for optional |
306
+ | `nullable: true` | `Type \| null` |
307
+ | `allOf` with `$ref` + properties | `interface Child extends Base { ... }` |
308
+ | `allOf` (pure intersection) | `type AB = A & B` |
309
+ | `oneOf` / `anyOf` | `type Either = A \| B` |
310
+ | `discriminator` | `@discriminator` JSDoc tag |
311
+ | Inline nested objects | `{ field: type; ... }` |
312
+ | `additionalProperties` | `Record<string, Type>` |
313
+ | `format` (date-time, uuid, email, etc.) | `@format` JSDoc annotation |
314
+ | `default` values | `@default` JSDoc annotation |
315
+ | `readOnly` / `writeOnly` | `@readonly` / `@writeOnly` JSDoc |
316
+ | `deprecated` (on schema or property) | `@deprecated` JSDoc |
317
+ | `description` | JSDoc comment |
318
+
319
+ ### Operations
320
+
321
+ | Feature | Generated code |
322
+ |---|---|
323
+ | Path parameters (`/users/{id}`) | Route uses Express `:id` format |
324
+ | Query parameters | Parsed from spec for types generation |
325
+ | Header parameters | Parsed from spec for types generation |
326
+ | `$ref` parameters (`#/components/parameters/...`) | Resolved from components |
327
+ | Request body (`application/json`) | Schema used for types generation |
328
+ | Inline request/response schemas | Auto-named `{OperationId}Request` / `{OperationId}Response` |
329
+ | Response `200`, `201`, `202` | Response type generated |
330
+ | Response `204` No Content | Parsed as `void` response |
331
+ | Error responses (`4xx`, `5xx`) | Error types generated in types file |
332
+ | `summary` / `description` | JSDoc on controller methods |
333
+ | `deprecated` operations | `@deprecated` JSDoc |
334
+ | Tags | One file set per tag |
335
+
336
+ ### Code Organization
337
+
338
+ | Feature | How it works |
339
+ |---|---|
340
+ | Shared schemas | Types used by 2+ tags go to `common.types.ts` |
341
+ | Barrel files | `index.ts` per folder for clean imports |
342
+ | Overwrite protection | Won't overwrite files you've manually modified |
343
+ | Configurable directories | `--types-dir`, `--controllers-dir`, `--routes-dir` |
344
+
345
+ ## What's NOT Generated
346
+
347
+ The generator only produces code that can be derived from the OpenAPI spec. The following are your responsibility:
348
+
349
+ - **Authentication / authorization** — middleware, token validation, user extraction
350
+ - **Service layer** — business logic, database access
351
+ - **Controller implementation** — the class that implements the generated interface, handles param extraction, response formatting, error handling
352
+ - **Validation** — consider [express-openapi-validator](https://www.npmjs.com/package/express-openapi-validator) for request validation from the same spec
353
+
354
+ ## Requirements
355
+
356
+ - Node.js 20+
357
+ - Express 4.x or 5.x in your project
358
+ - TypeScript 5.x
359
+
360
+ ## License
361
+
362
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for openapi-to-express
4
+ *
5
+ * Usage:
6
+ * npx openapi-to-express -i openapi.json -o src
7
+ * npx openapi-to-express (reads from .openapi-to-expressrc.json)
8
+ */
9
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for openapi-to-express
4
+ *
5
+ * Usage:
6
+ * npx openapi-to-express -i openapi.json -o src
7
+ * npx openapi-to-express (reads from .openapi-to-expressrc.json)
8
+ */
9
+ import { readFileSync } from "node:fs";
10
+ import { dirname, join, resolve } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ import { parseArgs } from "node:util";
13
+ import { generate } from "./generate.js";
14
+ import { loadConfig } from "./config.js";
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
17
+ const { values } = parseArgs({
18
+ options: {
19
+ input: { type: "string", short: "i" },
20
+ output: { type: "string", short: "o" },
21
+ "types-dir": { type: "string" },
22
+ "controllers-dir": { type: "string" },
23
+ "routes-dir": { type: "string" },
24
+ "dry-run": { type: "boolean" },
25
+ watch: { type: "boolean", short: "w" },
26
+ version: { type: "boolean", short: "v" },
27
+ help: { type: "boolean", short: "h" },
28
+ },
29
+ strict: true,
30
+ });
31
+ if (values.version) {
32
+ console.log(pkg.version);
33
+ process.exit(0);
34
+ }
35
+ if (values.help) {
36
+ console.log(`
37
+ openapi-to-express v${pkg.version} — Generate server code from OpenAPI specs
38
+
39
+ Usage:
40
+ openapi-to-express --input <spec> --output <dir> [options]
41
+ openapi-to-express (reads from .openapi-to-expressrc.json)
42
+
43
+ Required (unless provided in .openapi-to-expressrc.json):
44
+ -i, --input <value> OpenAPI specification — path (.json/.yaml/.yml), URL, or string content
45
+ -o, --output <value> Output directory (e.g. "src")
46
+
47
+ Optional:
48
+ --types-dir <name> Folder name for types (default: "types")
49
+ --controllers-dir <name> Folder name for controller interfaces (default: "controllers")
50
+ --routes-dir <name> Folder name for routes (default: "routes")
51
+ --dry-run Show what would be generated without writing files
52
+ -w, --watch Watch the spec file and regenerate on changes
53
+ -v, --version Output the version number
54
+ -h, --help Show this help message
55
+
56
+ Config file (.openapi-to-expressrc.json):
57
+ {
58
+ "input": "openapi.json",
59
+ "output": "src",
60
+ "types-dir": "types",
61
+ "controllers-dir": "controllers",
62
+ "routes-dir": "routes"
63
+ }
64
+
65
+ CLI flags override config file values.
66
+
67
+ Examples:
68
+ npx openapi-to-express -i openapi.json -o src
69
+ npx openapi-to-express -i openapi.json -o src --types-dir models
70
+ npx openapi-to-express
71
+ `);
72
+ process.exit(0);
73
+ }
74
+ // Load config file, merge with CLI flags (CLI wins)
75
+ const config = loadConfig() ?? {};
76
+ const input = values.input ?? config.input;
77
+ const output = values.output ?? config.output;
78
+ if (!input || !output) {
79
+ console.error("Error: --input and --output are required (via CLI flags or .openapi-to-expressrc.json).\n");
80
+ console.error("Usage: openapi-to-express --input openapi.json --output src");
81
+ console.error("Run with --help for more info.");
82
+ process.exit(1);
83
+ }
84
+ const typesDir = values["types-dir"] ?? config["types-dir"];
85
+ const controllersDir = values["controllers-dir"] ?? config["controllers-dir"];
86
+ const routesDir = values["routes-dir"] ?? config["routes-dir"];
87
+ const genOptions = {
88
+ input,
89
+ output,
90
+ dryRun: values["dry-run"] ?? false,
91
+ dirs: {
92
+ ...(typesDir && { types: typesDir }),
93
+ ...(controllersDir && { controllers: controllersDir }),
94
+ ...(routesDir && { routes: routesDir }),
95
+ },
96
+ };
97
+ try {
98
+ await generate(genOptions);
99
+ }
100
+ catch (err) {
101
+ console.error(`Error: ${err.message}`);
102
+ if (!values.watch)
103
+ process.exit(1);
104
+ }
105
+ if (values.watch) {
106
+ const { watch: fsWatch } = await import("node:fs");
107
+ const specPath = resolve(input);
108
+ console.log(`\nWatching ${specPath} for changes...\n`);
109
+ let debounce = null;
110
+ fsWatch(specPath, () => {
111
+ if (debounce)
112
+ clearTimeout(debounce);
113
+ debounce = setTimeout(async () => {
114
+ console.log(`\n--- ${new Date().toLocaleTimeString()} — spec changed, regenerating ---\n`);
115
+ try {
116
+ await generate(genOptions);
117
+ }
118
+ catch (err) {
119
+ console.error(`Error: ${err.message}`);
120
+ }
121
+ }, 300);
122
+ });
123
+ }
124
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Loads configuration from .openapi-to-expressrc.json in the current working directory.
3
+ * Returns null if no config file is found.
4
+ */
5
+ export interface ConfigFile {
6
+ input?: string;
7
+ output?: string;
8
+ "types-dir"?: string;
9
+ "controllers-dir"?: string;
10
+ "routes-dir"?: string;
11
+ }
12
+ export declare function loadConfig(cwd?: string): ConfigFile | null;
package/dist/config.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Loads configuration from .openapi-to-expressrc.json in the current working directory.
3
+ * Returns null if no config file is found.
4
+ */
5
+ import { readFileSync, existsSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ const CONFIG_FILE = ".openapi-to-expressrc.json";
8
+ export function loadConfig(cwd = process.cwd()) {
9
+ const configPath = join(cwd, CONFIG_FILE);
10
+ if (!existsSync(configPath))
11
+ return null;
12
+ try {
13
+ const raw = readFileSync(configPath, "utf-8");
14
+ return JSON.parse(raw);
15
+ }
16
+ catch (err) {
17
+ throw new Error(`Failed to parse ${CONFIG_FILE}: ${err.message}`);
18
+ }
19
+ }
20
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,WAAW,GAAG,4BAA4B,CAAC;AAUjD,MAAM,UAAU,UAAU,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAE1C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;IACvC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,WAAW,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Main generation orchestrator.
3
+ *
4
+ * Reads an OpenAPI spec, classifies schemas, and writes all generated files
5
+ * into the target directory with configurable folder names.
6
+ */
7
+ export interface DirectoryConfig {
8
+ /** Folder name for generated types (default: "types") */
9
+ types: string;
10
+ /** Folder name for generated controller interfaces (default: "controllers") */
11
+ controllers: string;
12
+ /** Folder name for generated routes (default: "routes") */
13
+ routes: string;
14
+ }
15
+ export interface GenerateOptions {
16
+ /** OpenAPI specification — can be a file path, URL, or JSON string content */
17
+ input: string;
18
+ /** Output directory (e.g. "src") */
19
+ output: string;
20
+ /** Custom folder names for generated output */
21
+ dirs?: Partial<DirectoryConfig>;
22
+ /** If true, only print what would be generated without writing files */
23
+ dryRun?: boolean;
24
+ }
25
+ export declare function generate(options: GenerateOptions): Promise<void>;