@powerduck/openapi-codegen 0.5.1 → 0.5.2
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 +253 -434
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,90 +1,36 @@
|
|
|
1
1
|
# @powerduck/openapi-codegen
|
|
2
2
|
|
|
3
|
-
Generate runnable HTTP request examples from OpenAPI documents
|
|
3
|
+
Generate runnable HTTP request examples from OpenAPI documents. Supports 21 languages and 41 language/client combinations. Browser-compatible, zero runtime dependencies.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@powerduck/openapi-codegen)
|
|
6
|
+
[](https://github.com/PowerDuckie/openapi-codegen/blob/main/LICENSE)
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## Links
|
|
8
9
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- **Security schemes** — API key, HTTP bearer, HTTP basic
|
|
15
|
-
- **Body types** — JSON, plain-text, URL-encoded form, multipart form-data
|
|
16
|
-
- **$ref resolution** — in-document JSON Pointer references with circular detection
|
|
17
|
-
- **Example generation** — automatic example values from JSON Schema
|
|
18
|
-
- **TypeScript declarations** — full type safety
|
|
19
|
-
- **Highly optimized** — no `JSON.parse`/`JSON.stringify` deep cloning, structured reference handling
|
|
20
|
-
|
|
21
|
-
## Supported Languages and Clients
|
|
22
|
-
|
|
23
|
-
Use the exact `language` and `client` identifiers shown below when calling `generate()`. Identifiers are case-sensitive.
|
|
24
|
-
|
|
25
|
-
| Language | `language` | Supported `client` values |
|
|
26
|
-
| ----------------- | ------------ | ----------------------------------------------------------------- |
|
|
27
|
-
| C | `c` | `libcurl` |
|
|
28
|
-
| C# | `csharp` | `httpclient`, `restsharp` |
|
|
29
|
-
| Clojure | `clojure` | `clj-http` |
|
|
30
|
-
| Dart | `dart` | `http` |
|
|
31
|
-
| F# | `fsharp` | `httpclient` |
|
|
32
|
-
| Go | `go` | `new-request` |
|
|
33
|
-
| HTTP request file | `http` | `http1` |
|
|
34
|
-
| Java | `java` | `asynchttp`, `java-net-http`, `okhttp`, `unirest` |
|
|
35
|
-
| JavaScript | `javascript` | `fetch`, `axios`, `ofetch`, `jquery`, `xhr` |
|
|
36
|
-
| Kotlin | `kotlin` | `okhttp` |
|
|
37
|
-
| Node.js | `node` | `fetch`, `axios`, `ofetch`, `undici` |
|
|
38
|
-
| Objective-C | `objc` | `nsurlsession` |
|
|
39
|
-
| OCaml | `ocaml` | `cohttp` |
|
|
40
|
-
| PHP | `php` | `curl`, `guzzle`, `laravel-http` |
|
|
41
|
-
| PowerShell | `powershell` | `invoke-webrequest`, `invoke-restmethod` |
|
|
42
|
-
| Python | `python` | `http-client`, `requests`, `aiohttp`, `httpx-sync`, `httpx-async` |
|
|
43
|
-
| R | `r` | `httr2` |
|
|
44
|
-
| Ruby | `ruby` | `net-http` |
|
|
45
|
-
| Rust | `rust` | `reqwest` |
|
|
46
|
-
| Shell | `shell` | `curl`, `wget`, `httpie` |
|
|
47
|
-
| Swift | `swift` | `nsurlsession` |
|
|
48
|
-
|
|
49
|
-
> Generator availability does not imply that every client can represent every OpenAPI operation. For example, GNU Wget cannot safely construct arbitrary `multipart/form-data` requests. Use `shell/curl` or `shell/httpie` for multipart uploads.
|
|
50
|
-
|
|
51
|
-
## Requirements
|
|
52
|
-
|
|
53
|
-
- Node.js 18 or later (for Node.js usage)
|
|
54
|
-
- A parsed OpenAPI document (JavaScript object)
|
|
55
|
-
- Modern browser with Fetch API (for browser usage)
|
|
56
|
-
|
|
57
|
-
## Installation
|
|
58
|
-
|
|
59
|
-
Using npm:
|
|
10
|
+
- [Official Website](https://www.powerduck.com/opensource/openapi-codegen.html)
|
|
11
|
+
- [Documentation](https://www.powerduck.com/docs/openapi-codegen/introduction)
|
|
12
|
+
- [Live Demo](https://www.powerduck.com/demo/openapi-codegen.html)
|
|
13
|
+
- [GitHub](https://github.com/PowerDuckie/openapi-codegen)
|
|
14
|
+
- [npm](https://www.npmjs.com/package/@powerduck/openapi-codegen)
|
|
60
15
|
|
|
61
|
-
|
|
62
|
-
npm install @powerduck/openapi-codegen
|
|
63
|
-
```
|
|
16
|
+
---
|
|
64
17
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
pnpm add @powerduck/openapi-codegen
|
|
69
|
-
```
|
|
18
|
+
## Quick Start
|
|
70
19
|
|
|
71
|
-
|
|
20
|
+
### Install
|
|
72
21
|
|
|
73
22
|
```bash
|
|
74
|
-
|
|
23
|
+
npm install @powerduck/openapi-codegen
|
|
75
24
|
```
|
|
76
25
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
### ESM (import)
|
|
26
|
+
### Generate from a document
|
|
80
27
|
|
|
81
28
|
```typescript
|
|
82
29
|
import { generate } from "@powerduck/openapi-codegen";
|
|
83
|
-
import document from "./openapi.json" with { type: "json" };
|
|
84
30
|
|
|
85
31
|
const code = generate({
|
|
86
|
-
document,
|
|
87
|
-
path: "/
|
|
32
|
+
document: openApiDocument,
|
|
33
|
+
path: "/pets/{id}",
|
|
88
34
|
method: "get",
|
|
89
35
|
language: "javascript",
|
|
90
36
|
client: "fetch",
|
|
@@ -93,7 +39,7 @@ const code = generate({
|
|
|
93
39
|
console.log(code);
|
|
94
40
|
```
|
|
95
41
|
|
|
96
|
-
### CommonJS
|
|
42
|
+
### CommonJS equivalent
|
|
97
43
|
|
|
98
44
|
```javascript
|
|
99
45
|
const { generate } = require("@powerduck/openapi-codegen");
|
|
@@ -103,8 +49,8 @@ const document = JSON.parse(fs.readFileSync("./openapi.json", "utf8"));
|
|
|
103
49
|
|
|
104
50
|
const code = generate({
|
|
105
51
|
document,
|
|
106
|
-
path: "/
|
|
107
|
-
method: "
|
|
52
|
+
path: "/pets",
|
|
53
|
+
method: "post",
|
|
108
54
|
language: "python",
|
|
109
55
|
client: "requests",
|
|
110
56
|
});
|
|
@@ -112,68 +58,7 @@ const code = generate({
|
|
|
112
58
|
console.log(code);
|
|
113
59
|
```
|
|
114
60
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
## Authentication
|
|
118
|
-
|
|
119
|
-
Provide credentials through `securityValues`:
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
import { generate } from "@powerduck/openapi-codegen";
|
|
123
|
-
|
|
124
|
-
const code = generate({
|
|
125
|
-
document,
|
|
126
|
-
path: "/users/{id}",
|
|
127
|
-
method: "get",
|
|
128
|
-
language: "javascript",
|
|
129
|
-
client: "fetch",
|
|
130
|
-
securityValues: {
|
|
131
|
-
bearerAuth: "YOUR_ACCESS_TOKEN",
|
|
132
|
-
apiKey: "YOUR_API_KEY",
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
console.log(code);
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
The keys in `securityValues` must match the security scheme names defined in the OpenAPI document.
|
|
140
|
-
|
|
141
|
-
**Security note:** Do not commit real credentials to source control.
|
|
142
|
-
|
|
143
|
-
## Multipart Uploads
|
|
144
|
-
|
|
145
|
-
```typescript
|
|
146
|
-
import { generate } from "@powerduck/openapi-codegen";
|
|
147
|
-
|
|
148
|
-
const code = generate({
|
|
149
|
-
document,
|
|
150
|
-
path: "/upload/{id}",
|
|
151
|
-
method: "post",
|
|
152
|
-
language: "shell",
|
|
153
|
-
client: "curl",
|
|
154
|
-
securityValues: {
|
|
155
|
-
bearerAuth: "YOUR_ACCESS_TOKEN",
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
console.log(code);
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
Generated multipart examples may include placeholder file paths:
|
|
163
|
-
|
|
164
|
-
```text
|
|
165
|
-
/tmp/file.bin
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Replace all placeholder paths before running the generated code.
|
|
169
|
-
|
|
170
|
-
Some clients cannot safely represent every OpenAPI request. Generation may throw a descriptive error when the selected client is incompatible with an operation.
|
|
171
|
-
|
|
172
|
-
For example, `shell/wget` does not support arbitrary multipart generation. Use `shell/curl` or `shell/httpie` instead.
|
|
173
|
-
|
|
174
|
-
## Discover Available Generators
|
|
175
|
-
|
|
176
|
-
Use `list()` to inspect every installed language/client combination:
|
|
61
|
+
### List available generators
|
|
177
62
|
|
|
178
63
|
```typescript
|
|
179
64
|
import { list } from "@powerduck/openapi-codegen";
|
|
@@ -183,38 +68,28 @@ for (const { language, client } of list()) {
|
|
|
183
68
|
}
|
|
184
69
|
```
|
|
185
70
|
|
|
186
|
-
|
|
71
|
+
### Provide credentials
|
|
187
72
|
|
|
188
73
|
```typescript
|
|
189
|
-
import { generate, list } from "@powerduck/openapi-codegen";
|
|
190
|
-
|
|
191
|
-
const generator = list().find(
|
|
192
|
-
({ language, client }) => language === "javascript" && client === "fetch",
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
if (!generator) {
|
|
196
|
-
throw new Error("The requested generator is not available");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
74
|
const code = generate({
|
|
200
75
|
document,
|
|
201
|
-
path: "/
|
|
76
|
+
path: "/pets/{id}",
|
|
202
77
|
method: "get",
|
|
203
|
-
language:
|
|
204
|
-
client:
|
|
78
|
+
language: "javascript",
|
|
79
|
+
client: "fetch",
|
|
80
|
+
securityValues: {
|
|
81
|
+
bearerAuth: "YOUR_ACCESS_TOKEN",
|
|
82
|
+
apiKey: "YOUR_API_KEY",
|
|
83
|
+
},
|
|
205
84
|
});
|
|
206
|
-
|
|
207
|
-
console.log(code);
|
|
208
85
|
```
|
|
209
86
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
Override the server URL from the OpenAPI document:
|
|
87
|
+
### Override the server URL
|
|
213
88
|
|
|
214
89
|
```typescript
|
|
215
90
|
const code = generate({
|
|
216
91
|
document,
|
|
217
|
-
path: "/
|
|
92
|
+
path: "/pets",
|
|
218
93
|
method: "get",
|
|
219
94
|
language: "shell",
|
|
220
95
|
client: "curl",
|
|
@@ -222,363 +97,307 @@ const code = generate({
|
|
|
222
97
|
});
|
|
223
98
|
```
|
|
224
99
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
### `generate(options)`
|
|
228
|
-
|
|
229
|
-
Generates an HTTP request example for an OpenAPI operation.
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
const code = generate({
|
|
233
|
-
document,
|
|
234
|
-
path,
|
|
235
|
-
method,
|
|
236
|
-
language,
|
|
237
|
-
client,
|
|
238
|
-
securityValues,
|
|
239
|
-
serverUrl,
|
|
240
|
-
softRefMode,
|
|
241
|
-
});
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
#### Options
|
|
100
|
+
---
|
|
245
101
|
|
|
246
|
-
|
|
247
|
-
| ---------------- | ----------------------------- | -------: | -------------------------------------------- |
|
|
248
|
-
| `document` | `unknown` (OpenAPI object) | Yes* | Parsed OpenAPI document |
|
|
249
|
-
| `path` | `string` | Yes* | Exact OpenAPI path template |
|
|
250
|
-
| `method` | `string` | Yes* | HTTP operation method |
|
|
251
|
-
| `language` | `string` | Yes | Target language identifier |
|
|
252
|
-
| `client` | `string` | Yes | Target HTTP client identifier |
|
|
253
|
-
| `securityValues` | `Record<string, string>` | No | Credentials for named security schemes |
|
|
254
|
-
| `serverUrl` | `string` | No | Override server URL from document |
|
|
255
|
-
| `softRefMode` | `boolean` | No | Soft mode for $ref resolution (no throws) |
|
|
256
|
-
| `request` | `RequestIR` | Yes* | Pre-normalized request (alternative to doc) |
|
|
257
|
-
|
|
258
|
-
\* Either `document` + `path` + `method` OR `request` must be provided.
|
|
102
|
+
## Features
|
|
259
103
|
|
|
260
|
-
|
|
104
|
+
- **21 languages, 41 clients** — JavaScript, Python, Go, Java, Ruby, PHP, C#, Rust, Swift, Kotlin, Dart, and more
|
|
105
|
+
- **Full OpenAPI parameter serialization** — path, query, header, cookie parameters with style/explode rules (form, spaceDelimited, pipeDelimited, label, matrix, simple, deepObject)
|
|
106
|
+
- **All body types** — JSON, form-urlencoded, multipart/form-data (text + file fields), XML, text, binary
|
|
107
|
+
- **Security resolution** — Bearer, Basic, API key (header/query/cookie), with `securityValues` for credentials
|
|
108
|
+
- **`$ref` resolution** — in-document JSON Pointer resolution with soft mode for broken/circular refs
|
|
109
|
+
- **Example generation** — generates realistic example values from JSON Schema (respects `example`, `enum`, `const`, `default`, `oneOf`/`anyOf`/`allOf`, types, formats, constraints)
|
|
110
|
+
- **Plugin system** — register custom generators through a simple plugin API
|
|
111
|
+
- **Direct RequestIR** — skip normalization entirely by building a `RequestIR` yourself
|
|
112
|
+
- **Browser-compatible** — zero Node.js dependencies, works in browsers, Edge Functions, and Node.js
|
|
113
|
+
- **Dual ESM/CJS builds** — works with `import` and `require`, with bundled TypeScript declarations
|
|
261
114
|
|
|
262
|
-
|
|
115
|
+
---
|
|
263
116
|
|
|
264
|
-
|
|
117
|
+
## GenerateOptions
|
|
265
118
|
|
|
266
|
-
|
|
119
|
+
```typescript
|
|
120
|
+
interface GenerateOptions {
|
|
121
|
+
language: string; // Target language identifier (case-sensitive)
|
|
122
|
+
client: string; // Target HTTP client identifier
|
|
123
|
+
request?: RequestIR; // Pre-normalized request; skips normalize
|
|
124
|
+
document?: unknown; // A parsed OpenAPI document object
|
|
125
|
+
path?: string; // Exact OpenAPI path template, e.g. "/pets/{id}"
|
|
126
|
+
method?: string; // HTTP method, e.g. "get" / "post"
|
|
127
|
+
serverUrl?: string; // Override the server URL from the document
|
|
128
|
+
securityValues?: Record<string, string>; // Credentials keyed by security scheme name
|
|
129
|
+
softRefMode?: boolean; // Do not throw on broken/circular $refs
|
|
130
|
+
}
|
|
131
|
+
```
|
|
267
132
|
|
|
268
|
-
|
|
269
|
-
- The language/client combination is unknown
|
|
270
|
-
- The OpenAPI document is invalid or unsupported
|
|
271
|
-
- Required generation data cannot be resolved
|
|
272
|
-
- The selected client cannot safely represent the request
|
|
273
|
-
- A circular $ref is detected (unless `softRefMode` is enabled)
|
|
133
|
+
> Either `request` alone, or `document` + `path` + `method`, must be provided. When `request` is supplied, `document`, `path`, `method`, `serverUrl`, `securityValues`, and `softRefMode` are ignored.
|
|
274
134
|
|
|
275
|
-
|
|
135
|
+
### Input validation errors
|
|
276
136
|
|
|
277
|
-
|
|
278
|
-
try {
|
|
279
|
-
const code = generate({
|
|
280
|
-
document,
|
|
281
|
-
path: "/users/{id}",
|
|
282
|
-
method: "get",
|
|
283
|
-
language: "javascript",
|
|
284
|
-
client: "fetch",
|
|
285
|
-
});
|
|
137
|
+
`generate()` throws when required input is missing:
|
|
286
138
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
139
|
+
- `TypeError: generate() requires an options object`
|
|
140
|
+
- `Error: Unsupported generator: <language>/<client>`
|
|
141
|
+
- `TypeError: generate() requires either a 'request' or a 'document' option`
|
|
142
|
+
- `TypeError: generate() requires a 'path' option when using 'document'`
|
|
143
|
+
- `TypeError: generate() requires a 'method' option when using 'document'`
|
|
290
144
|
|
|
291
|
-
|
|
292
|
-
process.exitCode = 1;
|
|
293
|
-
}
|
|
294
|
-
```
|
|
145
|
+
---
|
|
295
146
|
|
|
296
|
-
|
|
147
|
+
## Top-level API
|
|
297
148
|
|
|
298
|
-
|
|
149
|
+
| Export | Signature | Description |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `generate` | `(options: GenerateOptions) => string` | Generate runnable source code for one operation |
|
|
152
|
+
| `register` | `(generator: Generator) => void` | Register a custom generator |
|
|
153
|
+
| `get` | `(language: string, client: string) => Generator \| undefined` | Look up a generator |
|
|
154
|
+
| `list` | `() => Array<{ language: string; client: string }>` | List all registered generators |
|
|
155
|
+
| `use` | `(plugin: Plugin) => void` | Apply a plugin that registers generators |
|
|
156
|
+
| `registerBuiltins` | `() => void` | Register all built-in generators (auto-called on import) |
|
|
157
|
+
| `normalize` | `(options) => NormalizedRequest` | Turn a document + path + method into a normalized request |
|
|
158
|
+
| `builtinGenerators` | `Generator[]` | The raw array of all built-in generator definitions |
|
|
299
159
|
|
|
300
|
-
|
|
301
|
-
const generators = list();
|
|
302
|
-
```
|
|
160
|
+
Built-ins are registered automatically when the module loads, so calling `registerBuiltins()` manually is optional.
|
|
303
161
|
|
|
304
|
-
|
|
162
|
+
---
|
|
305
163
|
|
|
306
|
-
|
|
307
|
-
interface GeneratorDescriptor {
|
|
308
|
-
language: string;
|
|
309
|
-
client: string;
|
|
310
|
-
}
|
|
311
|
-
```
|
|
164
|
+
## Built-in Generators (21 languages, 41 clients)
|
|
312
165
|
|
|
313
|
-
|
|
166
|
+
| Language | `language` | `client` values |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| C | `c` | `libcurl` |
|
|
169
|
+
| C# | `csharp` | `httpclient`, `restsharp` |
|
|
170
|
+
| Clojure | `clojure` | `clj-http` |
|
|
171
|
+
| Dart | `dart` | `http` |
|
|
172
|
+
| F# | `fsharp` | `httpclient` |
|
|
173
|
+
| Go | `go` | `new-request` |
|
|
174
|
+
| HTTP request file | `http` | `http1` |
|
|
175
|
+
| Java | `java` | `asynchttp`, `java-net-http`, `okhttp`, `unirest` |
|
|
176
|
+
| JavaScript | `javascript` | `axios`, `fetch`, `jquery`, `ofetch`, `xhr` |
|
|
177
|
+
| Kotlin | `kotlin` | `okhttp` |
|
|
178
|
+
| Node.js | `node` | `axios`, `fetch`, `ofetch`, `undici` |
|
|
179
|
+
| Objective-C | `objc` | `nsurlsession` |
|
|
180
|
+
| OCaml | `ocaml` | `cohttp` |
|
|
181
|
+
| PHP | `php` | `curl`, `guzzle`, `laravel-http` |
|
|
182
|
+
| PowerShell | `powershell` | `invoke-restmethod`, `invoke-webrequest` |
|
|
183
|
+
| Python | `python` | `aiohttp`, `http-client`, `httpx-async`, `httpx-sync`, `requests` |
|
|
184
|
+
| R | `r` | `httr2` |
|
|
185
|
+
| Ruby | `ruby` | `net-http` |
|
|
186
|
+
| Rust | `rust` | `reqwest` |
|
|
187
|
+
| Shell | `shell` | `curl`, `httpie`, `wget` |
|
|
188
|
+
| Swift | `swift` | `nsurlsession` |
|
|
314
189
|
|
|
315
|
-
|
|
190
|
+
> Generator availability does not mean every client can represent every operation. For example, `shell/wget` cannot safely build arbitrary `multipart/form-data` requests; use `shell/curl` or `shell/httpie` instead.
|
|
316
191
|
|
|
317
|
-
|
|
318
|
-
const generator = get("javascript", "fetch");
|
|
319
|
-
```
|
|
192
|
+
---
|
|
320
193
|
|
|
321
|
-
|
|
194
|
+
## Custom Generator
|
|
322
195
|
|
|
323
|
-
|
|
196
|
+
Implement the `Generator` interface and call `register`:
|
|
324
197
|
|
|
325
198
|
```typescript
|
|
326
|
-
import { register } from "@powerduck/openapi-codegen";
|
|
199
|
+
import { register, generate } from "@powerduck/openapi-codegen";
|
|
200
|
+
import type { RequestIR } from "@powerduck/openapi-codegen";
|
|
327
201
|
|
|
328
202
|
register({
|
|
329
|
-
language: "
|
|
203
|
+
language: "mylang",
|
|
330
204
|
client: "my-client",
|
|
331
|
-
generate:
|
|
332
|
-
|
|
333
|
-
|
|
205
|
+
generate(request: RequestIR): string {
|
|
206
|
+
return [
|
|
207
|
+
`// ${request.method} ${request.baseUrl}${request.path}`,
|
|
208
|
+
`mylang.request(${JSON.stringify({
|
|
209
|
+
method: request.method,
|
|
210
|
+
url: request.baseUrl + request.path,
|
|
211
|
+
})})`,
|
|
212
|
+
].join("\n");
|
|
334
213
|
},
|
|
335
214
|
});
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
## OpenAPI Document Input
|
|
339
|
-
|
|
340
|
-
Pass a parsed JavaScript object rather than a JSON or YAML source string.
|
|
341
|
-
|
|
342
|
-
### JSON
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
import { readFile } from "node:fs/promises";
|
|
346
|
-
import { generate } from "@powerduck/openapi-codegen";
|
|
347
|
-
|
|
348
|
-
const source = await readFile("./openapi.json", "utf8");
|
|
349
|
-
const document = JSON.parse(source);
|
|
350
215
|
|
|
351
216
|
const code = generate({
|
|
352
217
|
document,
|
|
353
|
-
path: "/pets
|
|
218
|
+
path: "/pets",
|
|
354
219
|
method: "get",
|
|
355
|
-
language: "
|
|
356
|
-
client: "
|
|
220
|
+
language: "mylang",
|
|
221
|
+
client: "my-client",
|
|
357
222
|
});
|
|
358
|
-
|
|
359
|
-
console.log(code);
|
|
360
223
|
```
|
|
361
224
|
|
|
362
|
-
|
|
225
|
+
---
|
|
363
226
|
|
|
364
|
-
|
|
227
|
+
## Plugin
|
|
365
228
|
|
|
366
|
-
|
|
367
|
-
npm install yaml
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
Parse the document before passing it to `generate()`:
|
|
229
|
+
A plugin bundles one or more generator registrations through `use()`:
|
|
371
230
|
|
|
372
231
|
```typescript
|
|
373
|
-
import {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
232
|
+
import { use, generate } from "@powerduck/openapi-codegen";
|
|
233
|
+
|
|
234
|
+
use({
|
|
235
|
+
name: "internal-generators",
|
|
236
|
+
register(api) {
|
|
237
|
+
api.register({
|
|
238
|
+
language: "go",
|
|
239
|
+
client: "our-wrapper",
|
|
240
|
+
generate(request) {
|
|
241
|
+
return `// go wrapper for ${request.method} ${request.path}`;
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
api.register({
|
|
245
|
+
language: "ruby",
|
|
246
|
+
client: "our-wrapper",
|
|
247
|
+
generate(request) {
|
|
248
|
+
return `# ruby wrapper for ${request.method} ${request.path}`;
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
});
|
|
379
253
|
|
|
380
254
|
const code = generate({
|
|
381
255
|
document,
|
|
382
|
-
path: "/pets
|
|
256
|
+
path: "/pets",
|
|
383
257
|
method: "get",
|
|
384
|
-
language: "
|
|
385
|
-
client: "
|
|
258
|
+
language: "go",
|
|
259
|
+
client: "our-wrapper",
|
|
386
260
|
});
|
|
387
|
-
|
|
388
|
-
console.log(code);
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
## Browser Usage
|
|
392
|
-
|
|
393
|
-
The library is fully browser-compatible with zero Node.js dependencies:
|
|
394
|
-
|
|
395
|
-
```html
|
|
396
|
-
<!DOCTYPE html>
|
|
397
|
-
<html>
|
|
398
|
-
<head>
|
|
399
|
-
<title>API Code Generator</title>
|
|
400
|
-
</head>
|
|
401
|
-
<body>
|
|
402
|
-
<script type="module">
|
|
403
|
-
import { generate, list } from "https://esm.sh/@powerduck/openapi-codegen";
|
|
404
|
-
|
|
405
|
-
const document = {
|
|
406
|
-
openapi: "3.1.0",
|
|
407
|
-
info: { title: "Demo API", version: "1.0.0" },
|
|
408
|
-
paths: {
|
|
409
|
-
"/hello": {
|
|
410
|
-
get: {
|
|
411
|
-
responses: { "200": { description: "OK" } },
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
};
|
|
416
|
-
|
|
417
|
-
const code = generate({
|
|
418
|
-
document,
|
|
419
|
-
path: "/hello",
|
|
420
|
-
method: "get",
|
|
421
|
-
language: "javascript",
|
|
422
|
-
client: "fetch",
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
console.log(code);
|
|
426
|
-
</script>
|
|
427
|
-
</body>
|
|
428
|
-
</html>
|
|
429
261
|
```
|
|
430
262
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
Generated examples are intended to be readable, runnable starting points. Depending on the selected language and client, they may include:
|
|
263
|
+
---
|
|
434
264
|
|
|
435
|
-
|
|
436
|
-
- HTTP status validation
|
|
437
|
-
- Response body output
|
|
438
|
-
- Resource cleanup
|
|
439
|
-
- Runtime and dependency notes
|
|
440
|
-
- Placeholder multipart file paths
|
|
441
|
-
- Environment-specific proxy or TLS behavior
|
|
265
|
+
## Generate from a Direct RequestIR
|
|
442
266
|
|
|
443
|
-
|
|
267
|
+
Skip `normalize` entirely by building a `RequestIR` yourself:
|
|
444
268
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
- Supply authentication credentials securely
|
|
449
|
-
- Configure certificate trust
|
|
450
|
-
- Configure proxies
|
|
451
|
-
- Adjust timeout and redirect policies
|
|
452
|
-
- Add application-specific response parsing
|
|
269
|
+
```typescript
|
|
270
|
+
import { generate } from "@powerduck/openapi-codegen";
|
|
271
|
+
import type { RequestIR } from "@powerduck/openapi-codegen";
|
|
453
272
|
|
|
454
|
-
|
|
273
|
+
const request: RequestIR = {
|
|
274
|
+
method: "GET",
|
|
275
|
+
baseUrl: "https://api.example.com",
|
|
276
|
+
path: "/users/{id}",
|
|
277
|
+
parameters: [
|
|
278
|
+
{ name: "id", in: "path", value: 123 },
|
|
279
|
+
{ name: "limit", in: "query", value: 10, style: "form", explode: true },
|
|
280
|
+
],
|
|
281
|
+
headers: [
|
|
282
|
+
{ name: "Accept", in: "header", value: "application/json" },
|
|
283
|
+
],
|
|
284
|
+
body: undefined,
|
|
285
|
+
security: [],
|
|
286
|
+
};
|
|
455
287
|
|
|
456
|
-
|
|
288
|
+
const code = generate({
|
|
289
|
+
request,
|
|
290
|
+
language: "python",
|
|
291
|
+
client: "requests",
|
|
292
|
+
});
|
|
293
|
+
```
|
|
457
294
|
|
|
458
|
-
|
|
459
|
-
- **Efficient $ref resolution** with caching and circular detection
|
|
460
|
-
- **Lazy example generation** — only generates examples when needed
|
|
461
|
-
- **Zero runtime dependencies** — minimal bundle size (~130KB minified)
|
|
462
|
-
- **Tree-shakeable** — ESM build supports tree-shaking
|
|
295
|
+
---
|
|
463
296
|
|
|
464
|
-
##
|
|
297
|
+
## Core Types
|
|
465
298
|
|
|
466
|
-
|
|
299
|
+
```typescript
|
|
300
|
+
type ParameterLocation = "path" | "query" | "querystring" | "header" | "cookie";
|
|
301
|
+
|
|
302
|
+
interface Parameter {
|
|
303
|
+
name: string;
|
|
304
|
+
in: ParameterLocation;
|
|
305
|
+
value: unknown;
|
|
306
|
+
style?: string;
|
|
307
|
+
explode?: boolean;
|
|
308
|
+
allowReserved?: boolean;
|
|
309
|
+
}
|
|
467
310
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
311
|
+
interface Body {
|
|
312
|
+
mediaType: string;
|
|
313
|
+
value: unknown;
|
|
314
|
+
encoding?: Record<string, unknown>;
|
|
315
|
+
}
|
|
473
316
|
|
|
474
|
-
|
|
317
|
+
interface Security {
|
|
318
|
+
name: string;
|
|
319
|
+
type: string;
|
|
320
|
+
scheme?: string;
|
|
321
|
+
in?: string;
|
|
322
|
+
paramName?: string;
|
|
323
|
+
value: string;
|
|
324
|
+
}
|
|
475
325
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
326
|
+
interface RequestIR {
|
|
327
|
+
method: string;
|
|
328
|
+
baseUrl: string;
|
|
329
|
+
path: string;
|
|
330
|
+
parameters: Parameter[];
|
|
331
|
+
headers: Parameter[];
|
|
332
|
+
body?: Body;
|
|
333
|
+
security: Security[];
|
|
334
|
+
}
|
|
479
335
|
|
|
480
|
-
|
|
336
|
+
interface Generator {
|
|
337
|
+
language: string;
|
|
338
|
+
client: string;
|
|
339
|
+
generate(request: RequestIR): string;
|
|
340
|
+
}
|
|
481
341
|
|
|
482
|
-
|
|
483
|
-
|
|
342
|
+
interface Plugin {
|
|
343
|
+
name: string;
|
|
344
|
+
register(api: { register(generator: Generator): void }): void;
|
|
345
|
+
}
|
|
484
346
|
```
|
|
485
347
|
|
|
486
|
-
|
|
348
|
+
---
|
|
487
349
|
|
|
488
|
-
|
|
489
|
-
npm run build
|
|
490
|
-
```
|
|
350
|
+
## Error Handling
|
|
491
351
|
|
|
492
|
-
|
|
352
|
+
`generate()` throws for missing input or unsupported generators. Wrap calls when processing untrusted documents:
|
|
493
353
|
|
|
494
|
-
```
|
|
495
|
-
|
|
354
|
+
```typescript
|
|
355
|
+
try {
|
|
356
|
+
const code = generate({
|
|
357
|
+
document,
|
|
358
|
+
path: "/pets/{id}",
|
|
359
|
+
method: "get",
|
|
360
|
+
language: "javascript",
|
|
361
|
+
client: "fetch",
|
|
362
|
+
});
|
|
363
|
+
console.log(code);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
console.error("Generation failed:", error instanceof Error ? error.message : error);
|
|
366
|
+
}
|
|
496
367
|
```
|
|
497
368
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
```bash
|
|
501
|
-
npm run check
|
|
502
|
-
```
|
|
369
|
+
---
|
|
503
370
|
|
|
504
|
-
|
|
371
|
+
## Development
|
|
505
372
|
|
|
506
373
|
```bash
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
## Testing
|
|
511
|
-
|
|
512
|
-
The project uses:
|
|
374
|
+
# Install dependencies
|
|
375
|
+
npm install
|
|
513
376
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
- Full branch coverage for core logic
|
|
377
|
+
# Type check
|
|
378
|
+
npm run typecheck
|
|
517
379
|
|
|
518
|
-
|
|
380
|
+
# Build (ESM + CJS + type declarations)
|
|
381
|
+
npm run build
|
|
519
382
|
|
|
520
|
-
|
|
383
|
+
# Run tests
|
|
521
384
|
npm test
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
## Project Structure
|
|
525
385
|
|
|
386
|
+
# Watch mode
|
|
387
|
+
npx vitest watch
|
|
526
388
|
```
|
|
527
|
-
src/
|
|
528
|
-
├── index.ts # Main entry point
|
|
529
|
-
├── types.ts # TypeScript type definitions
|
|
530
|
-
├── core/
|
|
531
|
-
│ ├── generator.ts # Generator factory
|
|
532
|
-
│ ├── helpers.ts # Utility functions (escaping, indentation, etc.)
|
|
533
|
-
│ ├── normalize.ts # OpenAPI document → RequestIR normalization
|
|
534
|
-
│ ├── refs.ts # JSON Pointer $ref resolver
|
|
535
|
-
│ ├── registry.ts # Generator registry (Map-based)
|
|
536
|
-
│ ├── request.ts # RequestIR → compiled request
|
|
537
|
-
│ ├── serialize.ts # Parameter serialization (path/query/header/cookie)
|
|
538
|
-
│ ├── example.ts # JSON Schema → example value generation
|
|
539
|
-
│ └── plugin.ts # Plugin system
|
|
540
|
-
└── emitters/
|
|
541
|
-
├── index.ts # Unified emitter registry (41 generators)
|
|
542
|
-
├── c/ # C (libcurl)
|
|
543
|
-
├── csharp/ # C# (httpclient, restsharp)
|
|
544
|
-
├── javascript/ # JavaScript (fetch, axios, ofetch, jquery, xhr)
|
|
545
|
-
├── python/ # Python (requests, aiohttp, httpx, http-client)
|
|
546
|
-
└── ... # 17 more languages
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
## Security
|
|
550
|
-
|
|
551
|
-
Generated source code can contain request URLs, headers, parameter values, and credentials supplied to the generator.
|
|
552
389
|
|
|
553
|
-
|
|
390
|
+
---
|
|
554
391
|
|
|
555
|
-
|
|
556
|
-
- Logging secrets in CI output
|
|
557
|
-
- Running unreviewed generated commands in production
|
|
558
|
-
- Passing untrusted file paths directly to generated upload code
|
|
392
|
+
## Related Packages
|
|
559
393
|
|
|
560
|
-
|
|
394
|
+
- [`@powerduck/openapi-parser`](https://www.npmjs.com/package/@powerduck/openapi-parser) — OpenAPI 3.2 parser, validator, and upgrader
|
|
395
|
+
- [`@powerduck/openapi-request`](https://www.npmjs.com/package/@powerduck/openapi-request) — Execute OpenAPI operations with full parameter serialization
|
|
396
|
+
- [`@powerduck/openapi-cli`](https://www.npmjs.com/package/@powerduck/openapi-cli) — CI-ready batch testing for OpenAPI documents
|
|
397
|
+
- [`@powerduck/x-to-openapi`](https://www.npmjs.com/package/@powerduck/x-to-openapi) — Convert curl commands and Postman Collections to OpenAPI 3.2
|
|
561
398
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
Contributions are welcome.
|
|
565
|
-
|
|
566
|
-
1. Fork the repository.
|
|
567
|
-
2. Create a feature branch.
|
|
568
|
-
3. Add or update tests.
|
|
569
|
-
4. Run the full validation suite.
|
|
570
|
-
5. Commit the changes.
|
|
571
|
-
6. Open a pull request.
|
|
572
|
-
|
|
573
|
-
```bash
|
|
574
|
-
git checkout -b feature/my-change
|
|
575
|
-
npm install
|
|
576
|
-
npm run check
|
|
577
|
-
git add .
|
|
578
|
-
git commit -m "feat: describe the change"
|
|
579
|
-
git push -u origin feature/my-change
|
|
580
|
-
```
|
|
399
|
+
---
|
|
581
400
|
|
|
582
401
|
## License
|
|
583
402
|
|
|
584
|
-
|
|
403
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerduck/openapi-codegen",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Generate runnable HTTP request examples from OpenAPI documents. 21 languages, 41 clients, browser-compatible, zero runtime dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -63,13 +63,13 @@
|
|
|
63
63
|
},
|
|
64
64
|
"homepage": "https://github.com/PowerDuckie/openapi-codegen#readme",
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
|
|
67
|
-
"@vitest/coverage-v8": "^3.2.7",
|
|
66
|
+
"@types/node": "^20.19.43",
|
|
68
67
|
"fast-check": "^4.0.0",
|
|
69
68
|
"terser": "^5.51.2",
|
|
70
69
|
"tsup": "^8.5.0",
|
|
71
70
|
"tsx": "^4.23.13",
|
|
72
71
|
"typescript": "^5.9.3",
|
|
72
|
+
"@vitest/coverage-v8": "^3.2.7",
|
|
73
73
|
"vitest": "^3.2.7"
|
|
74
74
|
}
|
|
75
75
|
}
|