openapi-diff
Advanced tools
Comparing version 0.23.0 to 0.23.1
@@ -0,1 +1,6 @@ | ||
<a name="0.23.1"></a> | ||
## [0.23.1](https://bitbucket.org/atlassian/openapi-diff/compare/0.23.0...0.23.1) (2020-01-28) | ||
<a name="0.23.0"></a> | ||
@@ -2,0 +7,0 @@ # [0.23.0](https://bitbucket.org/atlassian/openapi-diff/compare/0.22.0...0.23.0) (2019-08-02) |
#! /usr/bin/env node | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -27,3 +28,3 @@ }); | ||
The <source> spec and <destination> spec arguments should be paths to where the specs live in your filesystem.`) | ||
.action((sourceSpecPath, destinationSpecPath) => __awaiter(this, void 0, void 0, function* () { | ||
.action((sourceSpecPath, destinationSpecPath) => __awaiter(void 0, void 0, void 0, function* () { | ||
try { | ||
@@ -30,0 +31,0 @@ yield openApiDiff.diffPaths({ |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -8,0 +9,0 @@ }); |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -8,0 +9,0 @@ }); |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -8,0 +9,0 @@ }); |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -8,0 +9,0 @@ }); |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -43,5 +44,5 @@ }); | ||
}; | ||
const findDifferencesInMatchingMethods = (sourceOperations, destinationOperations) => __awaiter(this, void 0, void 0, function* () { | ||
const findDifferencesInMatchingMethods = (sourceOperations, destinationOperations) => __awaiter(void 0, void 0, void 0, function* () { | ||
const whenDifferencesForAllMatchingMethods = get_common_keys_from_objects_1.getCommonKeysFromObjects(sourceOperations, destinationOperations) | ||
.map((matchingMethod) => __awaiter(this, void 0, void 0, function* () { | ||
.map((matchingMethod) => __awaiter(void 0, void 0, void 0, function* () { | ||
const matchingSourceOperation = sourceOperations[matchingMethod]; | ||
@@ -60,3 +61,3 @@ const matchingDestinationOperation = destinationOperations[matchingMethod]; | ||
}); | ||
exports.findDifferencesInOperations = (sourceOperations, destinationOperations) => __awaiter(this, void 0, void 0, function* () { | ||
exports.findDifferencesInOperations = (sourceOperations, destinationOperations) => __awaiter(void 0, void 0, void 0, function* () { | ||
const matchingMethodsDifferences = yield findDifferencesInMatchingMethods(sourceOperations, destinationOperations); | ||
@@ -63,0 +64,0 @@ return [ |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -43,3 +44,3 @@ }); | ||
}; | ||
const findDifferencesInMatchingPaths = (sourcePathItems, destinationPathItems) => __awaiter(this, void 0, void 0, function* () { | ||
const findDifferencesInMatchingPaths = (sourcePathItems, destinationPathItems) => __awaiter(void 0, void 0, void 0, function* () { | ||
const matchingPaths = get_common_keys_from_objects_1.getCommonKeysFromObjects(sourcePathItems, destinationPathItems); | ||
@@ -57,3 +58,3 @@ const whenFindDifferencesInAllOperations = matchingPaths.map((matchingPathItem) => find_diffs_in_operations_1.findDifferencesInOperations(sourcePathItems[matchingPathItem].operations, destinationPathItems[matchingPathItem].operations)); | ||
}, {}); | ||
exports.findDiffsInPaths = (sourcePathItems, destinationPathItems) => __awaiter(this, void 0, void 0, function* () { | ||
exports.findDiffsInPaths = (sourcePathItems, destinationPathItems) => __awaiter(void 0, void 0, void 0, function* () { | ||
const normalizedSourcePathItems = normalizePathItems(sourcePathItems); | ||
@@ -60,0 +61,0 @@ const normalizedDestinationPathItems = normalizePathItems(destinationPathItems); |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -13,3 +14,3 @@ }); | ||
const json_schema_diff_1 = require("./json-schema-diff"); | ||
exports.findDifferencesInRequestBodies = (sourceRequestBody, destinationRequestBody) => __awaiter(this, void 0, void 0, function* () { | ||
exports.findDifferencesInRequestBodies = (sourceRequestBody, destinationRequestBody) => __awaiter(void 0, void 0, void 0, function* () { | ||
const diffResults = yield json_schema_diff_1.getSchemaDifferences(sourceRequestBody, destinationRequestBody); | ||
@@ -16,0 +17,0 @@ const requestBodyScopeOptions = { |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -13,3 +14,3 @@ }); | ||
const json_schema_diff_1 = require("./json-schema-diff"); | ||
exports.findDifferencesInResponseBodies = (sourceResponseBody, destinationResponseBody) => __awaiter(this, void 0, void 0, function* () { | ||
exports.findDifferencesInResponseBodies = (sourceResponseBody, destinationResponseBody) => __awaiter(void 0, void 0, void 0, function* () { | ||
const diffResults = yield json_schema_diff_1.getSchemaDifferences(sourceResponseBody, destinationResponseBody); | ||
@@ -16,0 +17,0 @@ const responseBodyScopeOptions = { |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -43,5 +44,5 @@ }); | ||
}; | ||
const findDifferencesInMatchingResponses = (sourceResponses, destinationResponses) => __awaiter(this, void 0, void 0, function* () { | ||
const findDifferencesInMatchingResponses = (sourceResponses, destinationResponses) => __awaiter(void 0, void 0, void 0, function* () { | ||
const whenDifferencesForAllMatchingResponses = get_common_keys_from_objects_1.getCommonKeysFromObjects(sourceResponses, destinationResponses) | ||
.map((matchingResponse) => __awaiter(this, void 0, void 0, function* () { | ||
.map((matchingResponse) => __awaiter(void 0, void 0, void 0, function* () { | ||
const matchingSourceResponse = sourceResponses[matchingResponse]; | ||
@@ -57,3 +58,3 @@ const matchingDestinationResponse = destinationResponses[matchingResponse]; | ||
}); | ||
exports.findDifferencesInResponses = (sourceResponses, destinationResponses) => __awaiter(this, void 0, void 0, function* () { | ||
exports.findDifferencesInResponses = (sourceResponses, destinationResponses) => __awaiter(void 0, void 0, void 0, function* () { | ||
const matchingResponsesDifferences = yield findDifferencesInMatchingResponses(sourceResponses, destinationResponses); | ||
@@ -60,0 +61,0 @@ return [ |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -18,3 +19,3 @@ }); | ||
}; | ||
exports.getSchemaDifferences = (sourceParsedScope, destinationParsedScope) => __awaiter(this, void 0, void 0, function* () { | ||
exports.getSchemaDifferences = (sourceParsedScope, destinationParsedScope) => __awaiter(void 0, void 0, void 0, function* () { | ||
try { | ||
@@ -21,0 +22,0 @@ return yield JsonSchemaDiff.diffSchemas({ |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -8,0 +9,0 @@ }); |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -13,3 +14,3 @@ }); | ||
const open_api_diff_error_impl_1 = require("../../../common/open-api-diff-error-impl"); | ||
exports.validateAndDereferenceSpec = (spec, location) => __awaiter(this, void 0, void 0, function* () { | ||
exports.validateAndDereferenceSpec = (spec, location) => __awaiter(void 0, void 0, void 0, function* () { | ||
try { | ||
@@ -16,0 +17,0 @@ const options = { |
@@ -12,3 +12,3 @@ "use strict"; | ||
const compatibleSchema = to_diff_compatible_json_schema_1.toDiffCompatibleJsonSchema(schema); | ||
return Object.assign({}, compatibleSchema, { components: { schemas: compatibleReferenceSources } }); | ||
return Object.assign(Object.assign({}, compatibleSchema), { components: { schemas: compatibleReferenceSources } }); | ||
}; |
@@ -8,3 +8,3 @@ "use strict"; | ||
const compatibleSchema = to_diff_compatible_json_schema_1.toDiffCompatibleJsonSchema(schema); | ||
return Object.assign({}, compatibleSchema, { definitions: compatibleReferenceSources }); | ||
return Object.assign(Object.assign({}, compatibleSchema), { definitions: compatibleReferenceSources }); | ||
}; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -19,5 +20,5 @@ }); | ||
}; | ||
exports.validateAndDereferenceOpenapi3Spec = (content, location) => __awaiter(this, void 0, void 0, function* () { | ||
exports.validateAndDereferenceOpenapi3Spec = (content, location) => __awaiter(void 0, void 0, void 0, function* () { | ||
validateSpecFormat(content, location); | ||
return validate_and_dereference_spec_1.validateAndDereferenceSpec(content, location); | ||
}); |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -19,5 +20,5 @@ }); | ||
}; | ||
exports.validateAndDereferenceSwagger2Spec = (content, location) => __awaiter(this, void 0, void 0, function* () { | ||
exports.validateAndDereferenceSwagger2Spec = (content, location) => __awaiter(void 0, void 0, void 0, function* () { | ||
validateSpecFormat(content, location); | ||
return validate_and_dereference_spec_1.validateAndDereferenceSpec(content, location); | ||
}); |
{ | ||
"name": "openapi-diff", | ||
"version": "0.23.0", | ||
"version": "0.23.1", | ||
"description": "A CLI tool to identify differences between Swagger/OpenAPI specs.", | ||
@@ -37,2 +37,4 @@ "bin": { | ||
"devDependencies": { | ||
"@commitlint/cli": "^8.3.5", | ||
"@commitlint/config-conventional": "^8.3.4", | ||
"@types/express": "^4.17.0", | ||
@@ -42,6 +44,7 @@ "@types/jasmine": "^3.3.16", | ||
"@types/lodash": "^4.14.136", | ||
"@types/node": "^10.17.13", | ||
"@types/request": "^2.48.2", | ||
"@types/swagger-schema-official": "^2.0.18", | ||
"@types/verror": "^1.10.1", | ||
"conventional-changelog-lint": "1.1.9", | ||
"ansi-colors": "^4.1.1", | ||
"del": "^5.0.0", | ||
@@ -60,9 +63,9 @@ "express": "^4.17.1", | ||
"minimist": "^1.2.0", | ||
"tslint": "^5.18.0", | ||
"typescript": "^3.5.3" | ||
"tslint": "6.0.0", | ||
"typescript": "3.7.5" | ||
}, | ||
"dependencies": { | ||
"commander": "^2.20.0", | ||
"commander": "^4.1.0", | ||
"js-yaml": "^3.13.1", | ||
"json-schema-diff": "^0.12.0", | ||
"json-schema-diff": "^0.15.0", | ||
"jsonpointer": "^4.0.1", | ||
@@ -69,0 +72,0 @@ "lodash": "^4.17.15", |
264
README.md
# OpenAPI Diff | ||
> A CLI tool to identify differences between Swagger/OpenAPI specs. | ||
> A CLI tool to identify differences between Swagger or OpenApi specifications. | ||
## Requirements | ||
- nodejs 8.x or higher (tested using 8.x, 10.x and 12.x) | ||
- npm 3.x or higher (tested using 3.x and 6.x) | ||
- nodejs 8.x or higher (tested using 8.x, 10.x, 12.x and 13.x) | ||
- npm 6.x or higher (tested using 6.x) | ||
- Swagger 2 or OpenApi 3 specifications | ||
@@ -15,30 +16,249 @@ ## Installation | ||
Avoid installing the tool globally as this will lead to problems when multiple codebases try to use different versions | ||
of the tool on the same machine. | ||
## Description | ||
This took identifies what has changed between two Swagger or OpenApi specification files. These changes are classified into three groups, breaking, non-breaking and unclassified. Using an approach based on set theory this tool is able to calculate these differences to a high level of accuracy. | ||
### Supported Keywords | ||
[SPEC_SUPPORT.md](SPEC_SUPPORT.md) contains the details of what Swagger and OpenApi keywords are supported. | ||
### Change Classifications | ||
Changes detected by this tool are classified into three groups. | ||
#### Breaking | ||
Changes that would make existing consumers incompatible with the API, for example: | ||
- removing a path | ||
- removing a method | ||
- changing a property from optional to required in a request body | ||
- changing a property from required to optional in a response body | ||
#### Non Breaking | ||
Changes that would **not** make existing consumers incompatible with the API, for example: | ||
- adding a path | ||
- adding a method | ||
- changing a property from required to optional in a request body | ||
- changing a property from optional to required in a response body | ||
#### Unclassified | ||
Changes that have been detected by the tool but can't be classified, for example: | ||
- modifications to X-Properties | ||
## Usage | ||
Invoke the tool with two paths to Swagger/OpenAPI files in order to find differences between them, these paths can | ||
either be paths to the specs in the local filesystem or URLs to the specs, both JSON and YAML are supported. | ||
### Usage as a cli tool | ||
Invoke the tool with a file path to the source specification file and the destination specification file. These files should be in JSON or YAML format and be valid Swagger 2 or OpenApi 3 specificaitons. | ||
The tool will output a list of breaking, non breaking and unclassified differences found between the source and desitnation files. | ||
If any breaking changes are found the tool will return a non-zero exit code. | ||
##### Example | ||
*/path/to/source-specification.yaml* | ||
```yaml | ||
openapi: 3.0.1 | ||
info: | ||
title: User Service | ||
version: 1.0.0 | ||
paths: | ||
/users: | ||
post: | ||
requestBody: | ||
content: | ||
application/json: | ||
schema: | ||
properties: | ||
name: | ||
type: string | ||
required: | ||
- name | ||
type: object | ||
required: true | ||
responses: | ||
201: | ||
description: Created | ||
content: | ||
application/json: | ||
schema: | ||
properties: | ||
id: | ||
type: string | ||
required: | ||
- id | ||
type: object | ||
/users/{userId}: | ||
get: | ||
parameters: | ||
- name: userId | ||
in: path | ||
required: true | ||
schema: | ||
type: string | ||
responses: | ||
200: | ||
description: The user | ||
content: | ||
application/json: | ||
schema: | ||
properties: | ||
name: | ||
type: string | ||
required: | ||
- name | ||
type: object | ||
``` | ||
./node_modules/.bin/openapi-diff /path/to/source/openapi.json /path/to/destination/openapi.json | ||
./node_modules/.bin/openapi-diff /path/to/source/openapi.yml /path/to/destination/openapi.yml | ||
*/path/to/destination-specification.yaml* | ||
```yaml | ||
openapi: 3.0.1 | ||
info: | ||
title: User Service | ||
version: 1.0.0 | ||
paths: | ||
/users: | ||
post: | ||
requestBody: | ||
content: | ||
application/json: | ||
schema: | ||
properties: | ||
name: | ||
type: string | ||
required: | ||
- name | ||
type: object | ||
required: true | ||
responses: | ||
201: | ||
description: Created | ||
content: | ||
application/json: | ||
schema: | ||
properties: | ||
id: | ||
type: string | ||
required: | ||
- id | ||
type: object | ||
``` | ||
The tool's output will display the amount and type of changes, and then list the changes with the relevant info. | ||
Changes are classified as follows: | ||
*Invoking the tool* | ||
* Breaking: changes that would make existing consumers incompatible with the API (deletion of paths, adding required | ||
properties...) | ||
* Non-breaking: changes that would **not** make existing consumers incompatible with the API (addition of paths, | ||
turning a required property into optional...) | ||
* Unclassified: changes that have been detected by the tool but can't be classified (modifications to X-Properties and | ||
other unforeseen changes) | ||
``` | ||
openapi-diff /path/to/source-specification.yaml /path/to/destination-specification.yaml | ||
``` | ||
The command will exit with an exit code 1 if any breaking changes were found, so that you can fail builds in CI when | ||
this happens. | ||
*Output* | ||
## Feature support | ||
See [SPEC_SUPPORT.md](SPEC_SUPPORT.md) for details on which Swagger/OpenApi keywords the tool currently supports | ||
detecting differences within. | ||
``` | ||
Breaking changes found between the two specifications: | ||
{ | ||
"breakingDifferences": [ | ||
{ | ||
"type": "breaking", | ||
"action": "remove", | ||
"code": "path.remove", | ||
"destinationSpecEntityDetails": [], | ||
"entity": "path", | ||
"source": "openapi-diff", | ||
"sourceSpecEntityDetails": [ | ||
{ | ||
"location": "paths./users/{userId}", | ||
"value": { | ||
"get": { | ||
"parameters": [ | ||
{ | ||
"name": "userId", | ||
"in": "path", | ||
"required": true, | ||
"schema": { | ||
"type": "string" | ||
} | ||
} | ||
], | ||
"responses": { | ||
"200": { | ||
"description": "The user", | ||
"content": { | ||
"application/json": { | ||
"schema": { | ||
"properties": { | ||
"name": { | ||
"type": "string" | ||
} | ||
}, | ||
"required": [ | ||
"name" | ||
], | ||
"type": "object" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
] | ||
} | ||
], | ||
"breakingDifferencesFound": true, | ||
"nonBreakingDifferences": [], | ||
"unclassifiedDifferences": [] | ||
} | ||
``` | ||
### Usage as a nodejs api | ||
Invoke the library with a `SpecOption` for the source specification and the desitnation specification. A `SpecOption` has 3 properties: | ||
| Name | Type | Required | Description | | ||
| ---------: | :------: | :------: | ------------------------------------------------------------ | | ||
| `content` | `string` | Yes | A string containing the serialised json or yaml content of the specification. | | ||
| `location` | `string` | Yes | A label for the specification, typically a file path or file name but can be any value. This is used when reporting errors parsing the specification content. | | ||
| `format` | `string` | Yes | The format of the specification. Must be either `swagger2` or `openapi3` | | ||
For full details of the nodejs api please refer to [api-types.d.ts](lib/api-types.d.ts) | ||
#### Example | ||
```javascript | ||
const openapiDiff = require('openapi-diff'); | ||
const source = { | ||
// openapi3... | ||
}; | ||
const destination = { | ||
// openapi3... | ||
}; | ||
const result = await openapiDiff.diffSpecs({ | ||
sourceSpec: { | ||
content: JSON.stringify(source), | ||
location: 'source.json', | ||
format: 'openapi3' | ||
}, | ||
destinationSpec: { | ||
content: JSON.stringify(destination), | ||
location: 'destination.json', | ||
format: 'openapi3' | ||
} | ||
}); | ||
if (result.breakingDifferencesFound) { | ||
console.log('Breaking change found!') | ||
} | ||
``` | ||
## Changelog | ||
@@ -45,0 +265,0 @@ See [CHANGELOG.md](CHANGELOG.md) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
107813
67
1733
271
26
+ Addedcommander@4.1.1(transitive)
+ Addedjson-schema-diff@0.15.0(transitive)
- Removedformat-util@1.0.5(transitive)
- Removedjson-schema-diff@0.12.1(transitive)
- Removedjson-schema-ref-parser@6.1.0(transitive)
- Removedono@4.0.11(transitive)
Updatedcommander@^4.1.0
Updatedjson-schema-diff@^0.15.0