Skip to content

Commit 4248695

Browse files
committed
Merge branch 'oa3'
2 parents 7f54761 + e0c83af commit 4248695

File tree

101 files changed

+6779
-5551
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+6779
-5551
lines changed

.github/workflows/node.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
strategy:
1717
matrix:
18-
node-version: [16.x, 18.x, 20.x]
18+
node-version: [18.x, 20.x, 21.x, 22.x]
1919

2020
steps:
2121
- uses: actions/checkout@v4
@@ -27,3 +27,8 @@ jobs:
2727
- run: yarn build
2828
- run: yarn test
2929
- run: node dist/cli.js -c test/ci-test.config.json
30+
- run: yarn coverage
31+
32+
- name: Update Coverage Badge
33+
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
34+
uses: we-cli/coverage-badge-action@main

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,4 @@ dist/
6161
coverage/
6262
test/api*.json
6363
.tmp/
64+
.nyc_output/

.mocharc.json

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
{
2-
"extension": ["js", "ts"],
3-
"require": ["sucrase/register"],
4-
"spec": ["src/**/*.spec.ts", "test/**/*.spec.ts"]
2+
"extension": [
3+
"js",
4+
"ts"
5+
],
6+
"require": [
7+
"sucrase/register",
8+
"./test/test-setup.ts"
9+
],
10+
"spec": [
11+
"src/**/*.spec.ts",
12+
"test/*.spec.ts"
13+
]
514
}

.vscode/launch.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
"name": "Swaggie",
1111
"program": "${workspaceFolder}/src/cli.ts",
1212
"cwd": "${workspaceFolder}",
13-
"runtimeArgs": ["-r", "sucrase/register"],
14-
"protocol": "inspector",
13+
"runtimeArgs": ["-r", "@swc/register"],
1514
"args": ["-c", "./test/sample-config.json"]
1615
}
1716
]

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@
44

55
"files.associations": {
66
"templates/**/*.ejs": "plaintext"
7+
},
8+
"[html]": {
9+
"editor.formatOnSave": false
710
}
811
}

README.md

Lines changed: 138 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
![npm latest version](https://img.shields.io/npm/v/swaggie)
88
![NodeCI](https://github.com/yhnavein/swaggie/workflows/NodeCI/badge.svg)
9-
![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/yhnavein/swaggie.svg)
9+
![Test Coverage](https://img.shields.io/badge/test_coverage-98%25-brightgreen)
1010
![npm downloads](https://img.shields.io/npm/dw/swaggie.svg)
1111
![npm bundle size](https://img.shields.io/bundlephobia/minzip/swaggie.svg)
1212
![npm install size](https://packagephobia.now.sh/badge?p=swaggie)
1313

1414
<!-- ![Dependencies](https://img.shields.io/david/yhnavein/swaggie.svg) -->
1515

16-
Generate ES6 or Typescript code from an OpenAPI 2.0 spec, so that accessing REST API resources from the client code is less error-prone, static-typed and just easier to use long-term.
16+
Generate ES6 or Typescript code from an OpenAPI 3.0 spec, so that accessing REST API resources from the client code is less error-prone, static-typed and just easier to use long-term.
1717

1818
You can take a look at the [Examples section](#example) down below.
1919

@@ -29,29 +29,43 @@ Or globally to run CLI from anywhere
2929

3030
npm install swaggie -g
3131

32+
## OpenAPI versions
33+
34+
Swaggie from version 1.0 supports OpenAPI 3.0 (and some features of 3.1). Swagger or OpenAPI v2 documents are not supported anymore, but you have few options how to deal with it:
35+
36+
- **(preferred)** From your backend server generate OpenAPI 3.0 spec instead of version 2 (samples are updated to use OpenAPI 3.0)
37+
- Convert your OpenAPI 2.0 spec to 3.0 using [swagger2openapi](https://www.npmjs.com/package/swagger2openapi) tool (or something similar)
38+
- If you can't do that for any reason, you can stick to `Swaggie v0.x`. But upgrade is suggested
39+
40+
Please note that OpenAPI 3.0 is a major spec upgrade and it's possible that there will be some breaking changes in the generated code.
41+
I have tried my best to minimize the impact, but it was not possible to avoid it completely.
42+
43+
More info about breaking changes can be found in the [Releases](https://github.com/yhnavein/swaggie/releases).
44+
3245
### CLI
3346

3447
```
3548
Usage: swaggie [options]
3649
3750
Options:
3851
39-
-h, --help output usage information
40-
-V, --version output the version number
41-
-c, --config <path> The path to the configuration JSON file. You can do all the set up there instead of parameters in the CLI
42-
-s, --src <url|path> The url or path to the Open API spec file
43-
-t, --template <string> Template used forgenerating API client. Default: "axios"
44-
-o, --out <path> The path to the file where the API would be generated
45-
-b, --baseUrl <string> Base URL that will be used as a default value in the clients. Default: ""
46-
--preferAny Use "any" type instead of "unknown". Default: false
47-
--servicePrefix <string> Prefix for service names. Useful when you have multiple APIs and you want to avoid name collisions. Default: ''
48-
--queryModels <bool> Generate models for query string instead list of parameters. Default: false
52+
-V, --version output the version number
53+
-c, --config <path> The path to the configuration JSON file. You can do all the set up there instead of parameters in the CLI
54+
-s, --src <url|path> The url or path to the Open API spec file
55+
-o, --out <filePath> The path to the file where the API would be generated. Use stdout if left empty
56+
-b, --baseUrl <string> Base URL that will be used as a default value in the clients (default: "")
57+
-t, --template <string> Template used forgenerating API client. Default: "axios"
58+
--preferAny Use "any" type instead of "unknown" (default: false)
59+
--servicePrefix <string> Prefix for service names. Useful when you have multiple APIs and you want to avoid name collisions (default: "")
60+
--allowDots <bool> Determines if dots should be used for serialization object properties
61+
--arrayFormat <format> Determines how arrays should be serialized (choices: "indices", "repeat", "brackets")
62+
-h, --help display help for command
4963
```
5064

5165
Sample CLI usage using Swagger's Pet Store:
5266

5367
```bash
54-
swaggie -s https://petstore.swagger.io/v2/swagger.json -o ./client/petstore/
68+
swaggie -s https://petstore3.swagger.io/api/v3/openapi.json -o ./client/petstore/
5569
```
5670

5771
`swaggie` outputs TypeScript that is somehow formatted, but it's far from perfect. You can adjust the generated code by prettifying output using your preferred beautify tool using your repo's styling guidelines. For example involving `prettier` looks like this:
@@ -72,13 +86,16 @@ Sample configuration looks like this:
7286
{
7387
"$schema": "https://raw.githubusercontent.com/yhnavein/swaggie/master/schema.json",
7488
"out": "./src/client/petstore.ts",
75-
"src": "https://petstore.swagger.io/v2/swagger.json",
89+
"src": "https://petstore3.swagger.io/api/v3/openapi.json",
7690
"template": "axios",
7791
"baseUrl": "/api",
7892
"preferAny": true,
7993
"servicePrefix": "",
80-
"queryModels": true,
81-
"dateFormat": "Date" // "string" | "Date"
94+
"dateFormat": "Date", // "string" | "Date"
95+
"queryParamsSerialization": {
96+
"arrayFormat": "repeat", // "repeat" | "brackets" | "indices"
97+
"allowDots": true
98+
}
8299
}
83100
```
84101

@@ -98,39 +115,47 @@ ng2 Template for Angular 2+ (uses HttpClient, InjectionTokens, etc)
98115
If you want to use your own template, you can use the path to your template for the `-t` parameter:
99116
100117
```
101-
swaggie -s https://petstore.swagger.io/v2/swagger.json -o ./client/petstore --template ./my-swaggie-template/
118+
swaggie -s https://petstore3.swagger.io/api/v3/openapi.json -o ./client/petstore --template ./my-swaggie-template/
102119
```
103120
104-
### Code
121+
## Usage – Integrating into your project
105122
106-
```javascript
107-
const swaggie = require('swaggie');
108-
swaggie
109-
.genCode({
110-
src: 'http://petstore.swagger.io/v2/swagger.json',
111-
out: './api/petstore.ts',
112-
})
113-
.then(complete, error);
123+
Let's assume that you have a [PetStore API](http://petstore.swagger.io/) as your REST API and you are developing a client app written in TypeScript that will consume this API.
114124
115-
function complete(spec) {
116-
console.info('Service generation complete');
117-
}
125+
Instead of writing any code by hand for fetching particular resources, we will let Swaggie do it for us.
118126
119-
function error(e) {
120-
console.error(e.toString());
121-
}
122-
```
127+
### Query Parameters Serialization
123128
124-
## Usage – Integrating into your project
129+
When it comes to use of query parameters then you might need to adjust the way these parameters will be serialized, as backend server you are using expects them to be in a specific format. Thankfully in Swaggie you can specify how they should be handled. If you won't provide any configuration, then Swaggie will use the defaults values expected in the ASP.NET Core world.
125130
126-
Let's assume that you have a [PetStore API](http://petstore.swagger.io/) as your REST API and you are developing a client app written in TypeScript that will consume this API.
131+
For your convenience there are few config examples to achieve different serialization formats for an object `{ "a": { "b": 1 }, "c": [2, 3] }`:
127132
128-
Instead of writing any code by hand for fetching particular resources, we will let Swaggie do it for us.
133+
| Expected Format | allowDots | arrayFormat |
134+
| ----------------------- | --------- | ----------- |
135+
| `?a.b=1&c=2&c=3` | `true` | `repeat` |
136+
| `?a.b=1&c[]=2&c[]=3` | `true` | `brackets` |
137+
| `?a.b=1&c[0]=2&c[1]=3` | `true` | `indices` |
138+
| `?a[b]=1&c=2&c=3` | `false` | `repeat` |
139+
| `?a[b]=1&c[]=2&c[]=3` | `false` | `brackets` |
140+
| `?a[b]=1&c[0]=2&c[1]=3` | `false` | `indices` |
141+
142+
Once you know what your backend expects, you can adjust the configuration file accordingly: (below are default values)
143+
144+
```json
145+
{
146+
"queryParamsSerialization": {
147+
"arrayFormat": "repeat",
148+
"allowDots": true
149+
}
150+
}
151+
```
152+
153+
### Code Quality
129154

130155
> Please note that it's **recommended** to pipe Swaggie command to some prettifier like `prettier`, `biome` or `dprint` to make the generated code look not only nice, but also persistent.
131156
> Because Swaggie relies on a templating engine, whitespaces are generally a mess, so they may change between versions.
132157
133-
### Suggested prettiers
158+
**Suggested prettiers**
134159

135160
[prettier](https://prettier.io/) - the most popular one
136161

@@ -151,7 +176,7 @@ You are not limited to any of these, but in our examples we will use Prettier. P
151176
Let's run `swaggie` against PetStore API and see what will happen:
152177

153178
```bash
154-
swaggie -s https://petstore.swagger.io/v2/swagger.json -o ./api/petstore.ts && prettier ./api/petstore.ts --write
179+
swaggie -s https://petstore3.swagger.io/api/v3/openapi.json -o ./api/petstore.ts && prettier ./api/petstore.ts --write
155180
```
156181

157182
```typescript
@@ -160,19 +185,21 @@ swaggie -s https://petstore.swagger.io/v2/swagger.json -o ./api/petstore.ts && p
160185
import Axios, { AxiosPromise } from 'axios';
161186
const axios = Axios.create({
162187
baseURL: '/api',
188+
paramsSerializer: (params) =>
189+
encodeParams(params, null, {
190+
allowDots: true,
191+
arrayFormat: 'repeat',
192+
}),
163193
});
164194

165195
/** [...] **/
166196

167197
export const petClient = {
168198
/**
169199
* @param petId
170-
* @return Success
171200
*/
172201
getPetById(petId: number): AxiosPromise<Pet> {
173-
let url = '/pet/{petId}';
174-
175-
url = url.replace('{petId}', encodeURIComponent('' + petId));
202+
let url = `/pet/${encodeURIComponent(`${petId}`)}`;
176203

177204
return axios.request<Pet>({
178205
url: url,
@@ -208,17 +235,75 @@ You might wonder how to set up server to fully utilize Swaggie's features. For t
208235

209236
Server is not necessary to use Swaggie. Swaggie cares only about the JSON/yaml file with the Open API spec, but for your development purpose you might want to have a server that can serve this file automatically from the actual endpoints.
210237

211-
## Notes
238+
## Competitors
239+
240+
If you are familiar with the client-code generators for the Swagger / OpenAPI standards then you might wonder why `swaggie` is better than existing tools. I compiled a quick comparison with other tools below:
241+
242+
### Swaggie
243+
244+
- Fast and small ![swaggie size](https://packagephobia.now.sh/badge?p=swaggie)
245+
- Lightweight and easy to start
246+
- Easy to contribute to, custom templates
247+
- Flexible, suits well in the existing apps
248+
- Generates REST clients and all models
249+
- Supports different templates (like `axios`, `fetch`, `xior`, `swr-axios`, `ng1`, `ng2`)
250+
- Written in TypeScript
251+
- Generates only one file with everything you need inside
252+
253+
### [NSwag](https://github.com/RicoSuter/NSwag)
254+
255+
- Slow and big ![nswag size](https://packagephobia.now.sh/badge?p=nswag)
256+
- Complicated templates, not easy to contribute to
257+
- Enforces usage of other tools and architecture
258+
- Generates more boilerplate code
259+
- Written in .NET, require .NET to execute, although published to npm as well
260+
- Many more features (but mostly for .NET apps), client generation is just a part of it
261+
262+
### [Hey API](https://heyapi.vercel.app)
263+
264+
- Fast and small ![nswag size](https://packagephobia.now.sh/badge?p=%40hey-api%2Fopenapi-ts)
265+
- No flexibility, other clients are discouraged from use
266+
- Generates a lot of code and multiple files
267+
- Written in TypeScript
268+
269+
### [Kiota](https://learn.microsoft.com/en-us/openapi/kiota/)
270+
271+
- A lot of boilerplate code and many files
272+
- Written in .NET, requires .NET to execute, published to NuGet
273+
- Not flexible at all - you need to use their architecture in your code
274+
- Looks like an enterprise solution with many configuration options
275+
276+
## Using Swaggie programmatically
277+
278+
```javascript
279+
const swaggie = require('swaggie');
280+
swaggie
281+
.genCode({
282+
src: 'https://petstore3.swagger.io/api/v3/openapi.json',
283+
out: './api/petstore.ts',
284+
})
285+
.then(complete, error);
212286

213-
If you are familiar with the client-code generators for the Swagger / OpenAPI standards then you might wonder why `swaggie` is better than existing tools. Currently the most popular alternative is an open-source `NSwag`.
287+
function complete(spec) {
288+
console.info('Service generation complete');
289+
}
214290

215-
Quick comparison table:
291+
function error(e) {
292+
console.error(e.toString());
293+
}
294+
```
295+
296+
## Notes
216297

217-
| swaggie | NSwag |
218-
| --------------------------------------------------------------- | ----------------------------------------------------------- |
219-
| - Written in node.js + TypeScript | - Written in .NET |
220-
| - Fast | - Slow |
221-
| - ![swaggie size](https://packagephobia.now.sh/badge?p=swaggie) | - ![nswag size](https://packagephobia.now.sh/badge?p=nswag) |
222-
| - Easy to contribute to | - Contributing hard |
223-
| - Lightweight | - Complicated templates |
224-
| - Only features generating API clients for TS/JS | - Many more features (but mostly for .NET apps) |
298+
| Supported | Not supported |
299+
| ------------------------------------------------------------------------------ | ------------------------------------------ |
300+
| OpenAPI 3 | Swagger 2 |
301+
| `allOf`, `oneOf`, `anyOf`, `$ref` to schemas | `not` |
302+
| Spec formats: `JSON`, `YAML` | Very complex query params |
303+
| Extensions: `x-position`, `x-name`, `x-enumNames`, `x-enum-varnames` | Multiple response types (one will be used) |
304+
| Content types: `JSON`, `text`, `multipart/form-data` | Multiple request types (one will be used) |
305+
| Content types: `application/x-www-form-urlencoded`, `application/octet-stream` | References to other spec files |
306+
| Different types of enum definitions (+ OpenAPI 3.1 support for enums) | |
307+
| Paths inheritance, comments (descriptions) | |
308+
| Getting documents from remote locations or as path reference (local file) | |
309+
| Grouping endpoints by tags + handle gracefully duplicate operation ids | |

api.config.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
{
2-
"$schema": "https://raw.githubusercontent.com/yhnavein/swaggie/master/schema.json",
3-
"out": "./.tmp/swagger-test/petstore.ts",
4-
"src": "https://petstore.swagger.io/v2/swagger.json",
5-
"template": "ng2",
2+
"$schema": "./schema.json",
3+
"out": "./.tmp/fetch-petstore.ts",
4+
"src": "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json",
5+
"template": "fetch",
66
"preferAny": true,
7-
"queryModels": true,
8-
"dateFormat": "string"
7+
"dateFormat": "string",
8+
"queryParamsSerialization": {
9+
"arrayFormat": "indices",
10+
"allowDots": false
11+
}
912
}

0 commit comments

Comments
 (0)