Skip to content

Commit d5754f0

Browse files
feat: add openapi schema diff function (#1)
1 parent 51c740f commit d5754f0

19 files changed

+3611
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Set default behavior to automatically convert line endings
2+
* text=auto eol=lf

.github/workflows/test.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Run Tests
2+
3+
on: [push, pull_request]
4+
5+
permissions:
6+
contents: read
7+
8+
jobs:
9+
test:
10+
name: Test
11+
runs-on: ${{ matrix.os }}
12+
13+
strategy:
14+
matrix:
15+
node-version: [18.x, 20.x]
16+
os: [ubuntu-latest, windows-latest, macOS-latest]
17+
18+
steps:
19+
- uses: actions/checkout@v3
20+
21+
- name: Use Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v3
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
26+
- name: Install
27+
run: |
28+
npm install
29+
30+
- name: Test
31+
run: |
32+
npm run test

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,9 @@ dist
128128
.yarn/build-state.yml
129129
.yarn/install-state.gz
130130
.pnp.*
131+
132+
# lock files
133+
bun.lockb
134+
package-lock.json
135+
pnpm-lock.yaml
136+
yarn.lock

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

README.md

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# openapi-schema-diff
2+
3+
__openapi-schema-diff__ is a javascript library that compares two OpenAPI schemas and finds breaking changes.
4+
5+
- [Installation](#installation)
6+
- [Usage](#usage)
7+
- [API](#api)
8+
- [compare(sourceSchema, targetSchema)](#comparesourceSchema-targetSchema)
9+
- [License](#license)
10+
11+
<a name="installation"></a>
12+
13+
## Installation
14+
15+
```bash
16+
npm install openapi-schema-diff
17+
```
18+
19+
<a name="usage"></a>
20+
21+
## Usage
22+
23+
```javascript
24+
const compareOpenApiSchemas = require('openapi-schema-diff')
25+
26+
const sourceSchema = {
27+
openapi: '3.0.0',
28+
info: {
29+
title: 'My API',
30+
version: '1.0.0'
31+
},
32+
paths: {
33+
'/pets': {
34+
get: {
35+
summary: 'Returns all pets',
36+
responses: {
37+
200: {
38+
description: 'A list of pets.',
39+
content: {
40+
'application/json': {
41+
schema: {
42+
type: 'array',
43+
items: {
44+
type: 'object',
45+
properties: {
46+
name: {
47+
type: 'string'
48+
},
49+
age: {
50+
type: 'integer'
51+
}
52+
}
53+
}
54+
}
55+
}
56+
}
57+
}
58+
}
59+
}
60+
}
61+
}
62+
}
63+
64+
const targetSchema = {
65+
openapi: '3.0.0',
66+
info: {
67+
title: 'My API',
68+
version: '1.0.0'
69+
},
70+
paths: {
71+
'/pets': {
72+
get: {
73+
summary: 'Returns all pets',
74+
responses: {
75+
200: {
76+
description: 'A list of pets.',
77+
content: {
78+
'application/json': {
79+
schema: {
80+
type: 'array',
81+
items: {
82+
type: 'object',
83+
properties: {
84+
name: {
85+
type: 'string'
86+
},
87+
age: {
88+
type: 'integer'
89+
},
90+
breed: {
91+
type: 'string'
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}
98+
}
99+
}
100+
}
101+
}
102+
}
103+
}
104+
105+
const differences = compareOpenApiSchemas(sourceSchema, targetSchema)
106+
assert.deepEqual(differences, {
107+
isEqual: false,
108+
sameRoutes: [],
109+
addedRoutes: [],
110+
deletedRoutes: [],
111+
changedRoutes: [
112+
{
113+
method: 'get',
114+
path: '/pets',
115+
sourceSchema: sourceSchema.paths['/pets'].get,
116+
targetSchema: targetSchema.paths['/pets'].get,
117+
changes: [
118+
{
119+
type: 'responseBody',
120+
statusCode: '200',
121+
mediaType: 'application/json',
122+
action: 'changed',
123+
sourceSchema: sourceSchema.paths['/pets'].get.responses['200'].content['application/json'],
124+
targetSchema: targetSchema.paths['/pets'].get.responses['200'].content['application/json'],
125+
changes: [
126+
{
127+
keyword: 'schema',
128+
changes: [
129+
{
130+
jsonPath: '#/items/properties/breed',
131+
source: undefined,
132+
target: {
133+
type: 'string'
134+
}
135+
}
136+
],
137+
comment: 'response header schema has been changed'
138+
}
139+
],
140+
comment: 'response body for "200" status code and "application/json" media type has been changed in GET "/pets" route'
141+
}
142+
]
143+
}
144+
]
145+
})
146+
```
147+
148+
<a name="api"></a>
149+
150+
## API
151+
152+
<a name="compare-openapi-schemas"></a>
153+
154+
#### compare(sourceSchema, targetSchema)
155+
156+
Compares two OpenAPI schemas and returns and finds breaking changes. Source and target schemas must have the same OpenAPI major version.
157+
158+
- `sourceSchema` __\<object\>__ - source OpenAPI schema.
159+
- `targetSchema` __\<object\>__ - target OpenAPI schema.
160+
- __Returns__ - an object with schema differences.
161+
- `isEqual` __\<boolean\>__ - `true` if target schema does not have breaking changes, `false` otherwise.
162+
- `sameRoutes` __\<array\>__ - an array of routes that are present in both schemas and do not have breaking changes. See [same route](#same-route-object).
163+
- `addedRoutes` __\<array\>__ - an array of routes that are present in target schema but not in source schema. See [added route](#added-route-object).
164+
- `deletedRoutes` __\<array\>__ - an array of routes that are present in source schema but not in target schema. See [deleted route](#deleted-route-object).
165+
- `changedRoutes` __\<array\>__ - an array of routes that are present in both schemas and have breaking changes. See [changed route](#changed-route-object).
166+
167+
##### Same route object
168+
169+
- `method` __\<string\>__ - HTTP method name of the route.
170+
- `path` __\<string\>__ - path of the route.
171+
- `sourceSchema` __\<object\>__ - source OpenAPI schema of the route.
172+
- `targetSchema` __\<object\>__ - target OpenAPI schema of the route.
173+
174+
##### Added route object
175+
176+
- `method` __\<string\>__ - HTTP method name of the route.
177+
- `path` __\<string\>__ - path of the route.
178+
- `targetSchema` __\<object\>__ - target OpenAPI schema of the route.
179+
180+
##### Deleted route object
181+
182+
- `method` __\<string\>__ - HTTP method name of the route.
183+
- `path` __\<string\>__ - path of the route.
184+
- `sourceSchema` __\<object\>__ - source OpenAPI schema of the route.
185+
186+
##### Changed route object
187+
188+
- `method` __\<string\>__ - HTTP method name of the route.
189+
- `path` __\<string\>__ - path of the route.
190+
- `sourceSchema` __\<object\>__ - source OpenAPI schema of the route.
191+
- `targetSchema` __\<object\>__ - target OpenAPI schema of the route.
192+
- `changes` __\<array\>__ - a list of route components (header, querystring, body, ...) that have breaking changes. See [change object](#route-change-object)
193+
194+
##### Route change object
195+
196+
- `type` __\<string\>__ - type of the component. One of `parameter`, `requestBody`, `responseBody`, `responseHeader`.
197+
- `action` __\<string\>__ - action that was performed on the component. One of `added`, `deleted`, `changed`.
198+
- `sourceSchema` __\<object\>__ - source OpenAPI schema of the component.
199+
- `targetSchema` __\<object\>__ - target OpenAPI schema of the component.
200+
- `comment` __\<string\>__ - a comment describing the change.
201+
- `changes` __\<array\>__ - a list of changes in a component json schema. Exist only if `action` equals to `changed`. Each schema keyword has it's own change object. See [list of change objects](#list-schema-keywords-and-their-change-objects).
202+
203+
Each of the route components has it's own unique properties that identify it. For more details look at the component change object: [parameter](#parameter-change-object), [request body](#request-body-change-object), [response body](#response-body-change-object), [response header](#response-header-change-object).
204+
205+
##### Parameter change object
206+
207+
- `type` __\<string\>__ - type of the component. Equals to `parameter`.
208+
- `name` __\<string\>__ - name of the parameter.
209+
- `in` __\<string\>__ - location of the parameter. One of `query`, `header`, `path`, `cookie`.
210+
- `schemaChanges` - a list of changes in a component json schema. See [schema change object](#schema-change-object).
211+
- `comment` __\<string\>__ - a comment describing the change.
212+
213+
##### Request body change object
214+
215+
- `type` __\<string\>__ - type of the component. Equals to `requestBody`.
216+
- `mediaType` __\<string\>__ - media type of the component.
217+
- `schemaChanges` - a list of changes in a component json schema. See [schema change object](#schema-change-object).
218+
- `comment` __\<string\>__ - a comment describing the change.
219+
220+
##### Response body change object
221+
222+
- `type` __\<string\>__ - type of the component. Equals to `responseBody`.
223+
- `statusCode` __\<string\>__ - HTTP status code of the component.
224+
- `mediaType` __\<string\>__ - media type of the component.
225+
- `schemaChanges` - a list of changes in a component json schema. See [schema change object](#schema-change-object).
226+
- `comment` __\<string\>__ - a comment describing the change.
227+
228+
##### Response header change object
229+
230+
- `type` __\<string\>__ - type of the component. Equals to `responseHeader`.
231+
- `header` __\<string\>__ - name of the header.
232+
- `statusCode` __\<string\>__ - HTTP status code of the component.
233+
- `schemaChanges` - a list of changes in a component json schema. See [schema change object](#schema-change-object).
234+
- `comment` __\<string\>__ - a comment describing the change.
235+
236+
#### List schema keywords and their change objects
237+
238+
- [schema change object](#schema-keyword-change-object)
239+
- [required keyword change object](#required-keyword-change-object)
240+
241+
##### schema keyword change object
242+
243+
- `keyword` __\<string\>__ - keyword name. Equals to `schema`.
244+
- `comment` __\<string\>__ - a comment describing the change.
245+
- `changes` __\<array\>__ - a list of changes in a component json schema.
246+
- `jsonPath` __\<string\>__ - JSON path of the changed schema.
247+
- `source` __\<object\>__ - source subschema placed at the `jsonPath`.
248+
- `target` __\<object\>__ - target subschema placed at the `jsonPath`.
249+
250+
##### required keyword change object
251+
252+
- `keyword` __\<string\>__ - keyword name. Equals to `required`.
253+
- `source` __\<boolean\>__ - source value of the keyword.
254+
- `target` __\<boolean\>__ - target value of the keyword.
255+
- `comment` __\<string\>__ - a comment describing the change.
256+
257+
<a name="license"></a>
258+
259+
## License
260+
261+
MIT

0 commit comments

Comments
 (0)