Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

openapi-diff

Package Overview
Dependencies
Maintainers
2
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openapi-diff - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

test/e2e/fixtures/openapi-3-new.json

10

CHANGELOG.md

@@ -0,1 +1,11 @@

<a name="0.3.0"></a>
# [0.3.0](https://bitbucket.org/atlassian/openapi-diff/compare/0.2.0...v0.3.0) (2017-07-26)
### Features
* support for editions to the openapi / swagger property ([a8c2fc7](https://bitbucket.org/atlassian/openapi-diff/commits/a8c2fc7))
<a name="0.2.0"></a>

@@ -2,0 +12,0 @@ # [0.2.0](https://bitbucket.org/atlassian/openapi-diff/compare/0.1.0...v0.2.0) (2017-07-19)

8

dist/openapi-diff.js

@@ -12,6 +12,6 @@ "use strict";

run: (oldSpecPath, newSpecPath) => {
const whenOldSpecPath = json_loader_1.default.load(oldSpecPath, file_system_1.default, http_client_1.default);
const whenParsedOldSpec = whenOldSpecPath.then(spec_parser_1.default.parse);
const whenNewSpecPath = json_loader_1.default.load(newSpecPath, file_system_1.default, http_client_1.default);
const whenParsedNewSpec = whenNewSpecPath.then(spec_parser_1.default.parse);
const whenOldSpec = json_loader_1.default.load(oldSpecPath, file_system_1.default, http_client_1.default);
const whenParsedOldSpec = whenOldSpec.then(spec_parser_1.default.parse);
const whenNewSpec = json_loader_1.default.load(newSpecPath, file_system_1.default, http_client_1.default);
const whenParsedNewSpec = whenNewSpec.then(spec_parser_1.default.parse);
const whenDiff = q.all([whenParsedOldSpec, whenParsedNewSpec]).spread(spec_differ_1.default.diff);

@@ -18,0 +18,0 @@ const whenResults = whenDiff.then(result_reporter_1.default.build);

@@ -13,3 +13,3 @@ "use strict";

for (const entry of result.nonBreakingChanges) {
changeList.push(`Non-breaking: the path [${entry.path.join('/')}] `
changeList.push(`Non-breaking: the path [${entry.printablePath.join('/')}] `
+ `was modified from \'${entry.lhs}\' to \'${entry.rhs}\'`);

@@ -19,3 +19,3 @@ }

for (const entry of result.unclassifiedChanges) {
changeList.push(`Unclassified: the path [${entry.path.join('/')}] `
changeList.push(`Unclassified: the path [${entry.printablePath.join('/')}] `
+ `was modified from \'${entry.lhs}\' to \'${entry.rhs}\'`);

@@ -22,0 +22,0 @@ }

@@ -6,6 +6,7 @@ "use strict";

const utils_1 = require("./utils");
const processDiff = (rawDiff) => {
const processDiff = (parsedSpec, rawDiff) => {
const processedDiff = [];
if (hasChanges(rawDiff)) {
if (rawDiff) {
for (const entry of rawDiff) {
const taxonomy = findChangeTaxonomy(entry);
const processedEntry = {

@@ -17,5 +18,6 @@ index: getChangeNullableProperties(entry.index),

path: entry.path,
printablePath: utils_1.default.findOriginalPath(parsedSpec, entry.path),
rhs: entry.rhs,
taxonomy: findChangeTaxonomy(entry),
type: findChangeType(entry)
taxonomy,
type: findChangeType(taxonomy)
};

@@ -33,13 +35,25 @@ processedDiff.push(processedEntry);

};
const isOpenapiProperty = (entry) => {
return entry.path[0] === 'openapi';
};
const isInfoChange = (entry) => {
return isEdit(entry) && isInfoObject(entry) && !utils_1.default.isXProperty(entry.path[1]);
};
const hasChanges = (rawDiff) => {
return !_.isUndefined(rawDiff);
const isOpenapiChange = (entry) => {
return isEdit(entry) && isOpenapiProperty(entry);
};
const findChangeTaxonomy = (change) => {
return isInfoChange(change) ? 'info.object.edit' : 'zzz.unclassified.change';
if (isInfoChange(change)) {
return 'info.object.edit';
}
else if (isOpenapiChange(change)) {
return 'openapi.property.edit';
}
else {
return 'unclassified.change';
}
};
const findChangeType = (change) => {
return isInfoChange(change) ? 'non-breaking' : 'unclassified';
const findChangeType = (taxonomy) => {
const isNonBreakingChange = taxonomy === 'info.object.edit' || taxonomy === 'openapi.property.edit';
return isNonBreakingChange ? 'non-breaking' : 'unclassified';
};

@@ -58,5 +72,5 @@ const getChangeNullableProperties = (changeProperty) => {

exports.default = {
diff: (oldSpec, newSpec) => {
const rawDiff = deepDiff.diff(oldSpec, newSpec);
const processedDiff = processDiff(rawDiff);
diff: (oldParsedSpec, newParsedSpec) => {
const rawDiff = deepDiff.diff(oldParsedSpec, newParsedSpec);
const processedDiff = processDiff(oldParsedSpec, rawDiff);
const resultingDiff = sortProcessedDiff(processedDiff);

@@ -63,0 +77,0 @@ return resultingDiff;

@@ -8,2 +8,9 @@ "use strict";

};
const parseOpenApiProperty = (spec) => {
const parsedOpenApiProperty = {
originalPath: spec.swagger ? ['swagger'] : ['openapi'],
parsedValue: spec.swagger ? spec.swagger : spec.openapi
};
return parsedOpenApiProperty;
};
const parseTopLevelXProperties = (spec) => {

@@ -21,3 +28,4 @@ const xPropertiesArray = [];

const parsedSpec = {
info: parseInfoObject(spec)
info: parseInfoObject(spec),
openapi: parseOpenApiProperty(spec)
};

@@ -24,0 +32,0 @@ for (const entry of parseTopLevelXProperties(spec)) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
exports.default = {
findOriginalPath: (parsedSpec, parsedPath) => {
const parsedPathCopy = _.cloneDeep(parsedPath);
if (_.last(parsedPathCopy) === 'parsedValue') {
parsedPathCopy.pop();
}
const parsedPathString = parsedPathCopy.join('.');
return _.has(parsedSpec, [parsedPathString, 'originalPath']) ?
parsedSpec[parsedPathString].originalPath :
parsedPath;
},
isXProperty: (propertyPath) => {

@@ -5,0 +16,0 @@ return propertyPath.startsWith('x-');

@@ -111,3 +111,3 @@ 'use strict';

gulp.task('lint-commits', (callback) => {
return exec('./node_modules/.bin/conventional-changelog-lint --from \"b462f37\"', (err, stdout, stderr) => {
return exec('./node_modules/.bin/conventional-changelog-lint --from \"5f39d3e\"', (err, stdout, stderr) => {
console.log(stdout);

@@ -114,0 +114,0 @@ console.log(stderr);

@@ -1,4 +0,2 @@

import {
OpenAPIDiff
} from './openapi-diff/types';
import { OpenAPIDiff } from './openapi-diff/types';

@@ -16,7 +14,7 @@ import * as q from 'q';

run: (oldSpecPath, newSpecPath) => {
const whenOldSpecPath = jsonLoader.load(oldSpecPath, fileSystem, httpClient);
const whenParsedOldSpec = whenOldSpecPath.then(specParser.parse);
const whenOldSpec = jsonLoader.load(oldSpecPath, fileSystem, httpClient);
const whenParsedOldSpec = whenOldSpec.then(specParser.parse);
const whenNewSpecPath = jsonLoader.load(newSpecPath, fileSystem, httpClient);
const whenParsedNewSpec = whenNewSpecPath.then(specParser.parse);
const whenNewSpec = jsonLoader.load(newSpecPath, fileSystem, httpClient);
const whenParsedNewSpec = whenNewSpec.then(specParser.parse);

@@ -23,0 +21,0 @@ const whenDiff = q.all([whenParsedOldSpec, whenParsedNewSpec]).spread(specDiffer.diff);

@@ -9,3 +9,4 @@ import * as q from 'q';

JsonLoaderFunction,
OpenAPISpec
OpenAPI3Spec,
Swagger2Spec
} from './types';

@@ -18,7 +19,7 @@

const parseAsJson = (location: string, content: string): q.Promise<OpenAPISpec> => {
const parseAsJson = (location: string, content: string): q.Promise<Swagger2Spec | OpenAPI3Spec> => {
try {
return q(JSON.parse(content));
} catch (error) {
return q.reject<OpenAPISpec>(new VError(error, `ERROR: unable to parse ${location} as a JSON file`));
return q.reject<OpenAPI3Spec>(new VError(error, `ERROR: unable to parse ${location} as a JSON file`));
}

@@ -25,0 +26,0 @@ };

@@ -15,3 +15,3 @@ import * as _ from 'lodash';

for (const entry of result.nonBreakingChanges) {
changeList.push(`Non-breaking: the path [${entry.path.join('/')}] `
changeList.push(`Non-breaking: the path [${entry.printablePath.join('/')}] `
+ `was modified from \'${entry.lhs}\' to \'${entry.rhs}\'`);

@@ -22,3 +22,3 @@ }

for (const entry of result.unclassifiedChanges) {
changeList.push(`Unclassified: the path [${entry.path.join('/')}] `
changeList.push(`Unclassified: the path [${entry.printablePath.join('/')}] `
+ `was modified from \'${entry.lhs}\' to \'${entry.rhs}\'`);

@@ -25,0 +25,0 @@ }

@@ -9,15 +9,18 @@ import * as deepDiff from 'deep-diff';

Diff,
DiffChange, DiffChangeTaxonomy,
DiffChange,
DiffChangeTaxonomy,
DiffChangeType,
OpenAPISpec,
ParsedSpec,
ResultDiff
} from './types';
const processDiff = (rawDiff: IDiff[]): DiffChange[] => {
const processDiff = (parsedSpec: ParsedSpec, rawDiff: IDiff[] | undefined): DiffChange[] => {
const processedDiff: DiffChange[] = [];
if (hasChanges(rawDiff)) {
if (rawDiff) {
for (const entry of rawDiff) {
const taxonomy = findChangeTaxonomy(entry);
const processedEntry: DiffChange = {

@@ -29,5 +32,6 @@ index: getChangeNullableProperties(entry.index),

path: entry.path,
printablePath: utils.findOriginalPath(parsedSpec, entry.path),
rhs: entry.rhs,
taxonomy: findChangeTaxonomy(entry),
type: findChangeType(entry)
taxonomy,
type: findChangeType(taxonomy)
};

@@ -50,2 +54,6 @@

const isOpenapiProperty = (entry: IDiff): boolean => {
return entry.path[0] === 'openapi';
};
const isInfoChange = (entry: IDiff): boolean => {

@@ -55,12 +63,19 @@ return isEdit(entry) && isInfoObject(entry) && !utils.isXProperty(entry.path[1]);

const hasChanges = (rawDiff: IDiff[]): boolean => {
return !_.isUndefined(rawDiff);
const isOpenapiChange = (entry: IDiff): boolean => {
return isEdit(entry) && isOpenapiProperty(entry);
};
const findChangeTaxonomy = (change: IDiff): DiffChangeTaxonomy => {
return isInfoChange(change) ? 'info.object.edit' : 'zzz.unclassified.change';
if (isInfoChange(change)) {
return 'info.object.edit';
} else if (isOpenapiChange (change)) {
return 'openapi.property.edit';
} else {
return 'unclassified.change';
}
};
const findChangeType = (change: IDiff): DiffChangeType => {
return isInfoChange(change) ? 'non-breaking' : 'unclassified';
const findChangeType = (taxonomy: DiffChangeTaxonomy): DiffChangeType => {
const isNonBreakingChange = taxonomy === 'info.object.edit' || taxonomy === 'openapi.property.edit';
return isNonBreakingChange ? 'non-breaking' : 'unclassified';
};

@@ -82,5 +97,6 @@

export default {
diff: (oldSpec: OpenAPISpec, newSpec: OpenAPISpec): Diff => {
const rawDiff: IDiff[] = deepDiff.diff(oldSpec, newSpec);
const processedDiff: DiffChange[] = processDiff(rawDiff);
diff: (oldParsedSpec: ParsedSpec,
newParsedSpec: ParsedSpec): Diff => {
const rawDiff: IDiff[] = deepDiff.diff(oldParsedSpec, newParsedSpec);
const processedDiff: DiffChange[] = processDiff(oldParsedSpec, rawDiff);
const resultingDiff = sortProcessedDiff(processedDiff);

@@ -87,0 +103,0 @@ return resultingDiff;

@@ -6,13 +6,23 @@ import * as _ from 'lodash';

import {
OpenAPISpec,
OpenAPI3Spec,
ParsedInfoObject,
ParsedOpenApiProperty,
ParsedSpec,
Swagger2Spec,
XProperty
} from './types';
const parseInfoObject = (spec: OpenAPISpec): ParsedInfoObject => {
const parseInfoObject = (spec: Swagger2Spec | OpenAPI3Spec): ParsedInfoObject => {
return spec.info;
};
const parseTopLevelXProperties = (spec: OpenAPISpec): XProperty[] => {
const parseOpenApiProperty = (spec: Swagger2Spec | OpenAPI3Spec): ParsedOpenApiProperty => {
const parsedOpenApiProperty: ParsedOpenApiProperty = {
originalPath: spec.swagger ? ['swagger'] : ['openapi'],
parsedValue: spec.swagger ? spec.swagger : spec.openapi
};
return parsedOpenApiProperty;
};
const parseTopLevelXProperties = (spec: Swagger2Spec | OpenAPI3Spec): XProperty[] => {
const xPropertiesArray: XProperty[] = [];

@@ -28,11 +38,14 @@ _.forIn(spec, (value, key) => {

export default {
parse: (spec: OpenAPISpec): ParsedSpec => {
parse: (spec: Swagger2Spec | OpenAPI3Spec): ParsedSpec => {
const parsedSpec: ParsedSpec = {
info: parseInfoObject(spec)
info: parseInfoObject(spec),
openapi: parseOpenApiProperty(spec)
};
for (const entry of parseTopLevelXProperties(spec)) {
_.set(parsedSpec, entry.key, entry.value);
}
return parsedSpec;
}
};

@@ -13,2 +13,3 @@ // Diff types

export interface DiffChange extends IDiff {
printablePath: string[];
taxonomy: DiffChangeTaxonomy;

@@ -20,3 +21,4 @@ type: DiffChangeType;

'info.object.edit' |
'zzz.unclassified.change';
'openapi.property.edit' |
'unclassified.change';

@@ -40,7 +42,14 @@ export type DiffChangeType =

export interface OpenAPISpec {
export interface Swagger2Spec {
info: OpenAPISpecInfo;
[xProperty: string]: any;
swagger: string;
}
export interface OpenAPI3Spec {
info: OpenAPISpecInfo;
[xProperty: string]: any;
openapi: string;
}
// Parsed Spec types

@@ -69,4 +78,10 @@

export interface ParsedOpenApiProperty {
originalPath: string[];
parsedValue: string;
}
export interface ParsedSpec {
info: ParsedInfoObject;
openapi: ParsedOpenApiProperty;
[xProperty: string]: any;

@@ -73,0 +88,0 @@ }

@@ -0,2 +1,19 @@

import * as _ from 'lodash';
import {ParsedSpec} from './types';
export default {
findOriginalPath: (parsedSpec: ParsedSpec, parsedPath: string[]): string[] => {
const parsedPathCopy = _.cloneDeep(parsedPath);
if (_.last(parsedPathCopy) === 'parsedValue') {
parsedPathCopy.pop();
}
const parsedPathString: string = parsedPathCopy.join('.');
return _.has(parsedSpec, [parsedPathString, 'originalPath']) ?
parsedSpec[parsedPathString].originalPath :
parsedPath;
},
isXProperty: (propertyPath: string): boolean => {

@@ -3,0 +20,0 @@ return propertyPath.startsWith('x-');

{
"name": "openapi-diff",
"version": "0.2.0",
"version": "0.3.0",
"description": "A CLI tool to identify differences between Swagger/OpenAPI specs.",

@@ -5,0 +5,0 @@ "bin": {

@@ -28,6 +28,7 @@ # OpenAPI Diff

- Specs in the local filesystem or as URLs
- Editions to the Info object and ^x- properties at the top level of the spec.
- Detects editions to the `swagger` / `openapi` object.
- Detects editions to the `info` object and `^x- properties` at the top level of the spec.
### Beta support
- Additions and deletions to the Info object and ^x- properties at the top level of the spec.
- Additions and deletions to the `info` object and `^x- properties` at the top level of the spec.

@@ -34,0 +35,0 @@ ### Not supported

@@ -16,3 +16,4 @@ {

"version": "1.0.0"
}
},
"swagger": "2.0"
}

@@ -16,3 +16,4 @@ {

"version": "1.0.0"
}
},
"swagger": "2.0"
}

@@ -18,3 +18,4 @@ {

},
"x-generic-property": "some new content"
"x-generic-property": "some new content",
"swagger": "2.1"
}

@@ -18,3 +18,4 @@ {

},
"x-generic-property": "some content"
"x-generic-property": "some content",
"swagger": "2.0"
}

@@ -1,1 +0,1035 @@

{"swagger":"2.0","info":{"description":"This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.","version":"1.0.1","title":"Swagger Petstore","termsOfService":"http://swagger.io/terms/","contact":{"email":"apiteam@swagger.io"},"license":{"name":"Apache 2.1","url":"http://www.apache.org/licenses/LICENSE-2.0.html"}},"host":"petstore.swagger.io","basePath":"/v2","tags":[{"name":"pet","description":"Everything about your Pets","externalDocs":{"description":"Find out more","url":"http://swagger.io"}},{"name":"store","description":"Access to Petstore orders"},{"name":"user","description":"Operations about user","externalDocs":{"description":"Find out more about our store","url":"http://swagger.io"}}],"schemes":["http"],"paths":{"/pet":{"post":{"tags":["pet"],"summary":"Add a new pet to the store","description":"","operationId":"addPet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"put":{"tags":["pet"],"summary":"Update an existing pet","description":"","operationId":"updatePet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"},"405":{"description":"Validation exception"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByStatus":{"get":{"tags":["pet"],"summary":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","operationId":"findPetsByStatus","produces":["application/xml","application/json"],"parameters":[{"name":"status","in":"query","description":"Status values that need to be considered for filter","required":true,"type":"array","items":{"type":"string","enum":["available","pending","sold"],"default":"available"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid status value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByTags":{"get":{"tags":["pet"],"summary":"Finds Pets by tags","description":"Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","operationId":"findPetsByTags","produces":["application/xml","application/json"],"parameters":[{"name":"tags","in":"query","description":"Tags to filter by","required":true,"type":"array","items":{"type":"string"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid tag value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}],"deprecated":true}},"/pet/{petId}":{"get":{"tags":["pet"],"summary":"Find pet by ID","description":"Returns a single pet","operationId":"getPetById","produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to return","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Pet"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"api_key":[]}]},"post":{"tags":["pet"],"summary":"Updates a pet in the store with form data","description":"","operationId":"updatePetWithForm","consumes":["application/x-www-form-urlencoded"],"produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet that needs to be updated","required":true,"type":"integer","format":"int64"},{"name":"name","in":"formData","description":"Updated name of the pet","required":false,"type":"string"},{"name":"status","in":"formData","description":"Updated status of the pet","required":false,"type":"string"}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"delete":{"tags":["pet"],"summary":"Deletes a pet","description":"","operationId":"deletePet","produces":["application/xml","application/json"],"parameters":[{"name":"api_key","in":"header","required":false,"type":"string"},{"name":"petId","in":"path","description":"Pet id to delete","required":true,"type":"integer","format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}/uploadImage":{"post":{"tags":["pet"],"summary":"uploads an image","description":"","operationId":"uploadFile","consumes":["multipart/form-data"],"produces":["application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to update","required":true,"type":"integer","format":"int64"},{"name":"additionalMetadata","in":"formData","description":"Additional data to pass to server","required":false,"type":"string"},{"name":"file","in":"formData","description":"file to upload","required":false,"type":"file"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/ApiResponse"}}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/store/inventory":{"get":{"tags":["store"],"summary":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","operationId":"getInventory","produces":["application/json"],"parameters":[],"responses":{"200":{"description":"successful operation","schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"security":[{"api_key":[]}]}},"/store/order":{"post":{"tags":["store"],"summary":"Place an order for a pet","description":"","operationId":"placeOrder","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"order placed for purchasing the pet","required":true,"schema":{"$ref":"#/definitions/Order"}}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid Order"}}}},"/store/order/{orderId}":{"get":{"tags":["store"],"summary":"Find purchase order by ID","description":"For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions","operationId":"getOrderById","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of pet that needs to be fetched","required":true,"type":"integer","maximum":10.0,"minimum":1.0,"format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}},"delete":{"tags":["store"],"summary":"Delete purchase order by ID","description":"For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors","operationId":"deleteOrder","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of the order that needs to be deleted","required":true,"type":"integer","minimum":1.0,"format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}}},"/user":{"post":{"tags":["user"],"summary":"Create user","description":"This can only be done by the logged in user.","operationId":"createUser","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Created user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithArray":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithArrayInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithList":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithListInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/login":{"get":{"tags":["user"],"summary":"Logs user into the system","description":"","operationId":"loginUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"query","description":"The user name for login","required":true,"type":"string"},{"name":"password","in":"query","description":"The password for login in clear text","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"type":"string"},"headers":{"X-Rate-Limit":{"type":"integer","format":"int32","description":"calls per hour allowed by the user"},"X-Expires-After":{"type":"string","format":"date-time","description":"date in UTC when token expires"}}},"400":{"description":"Invalid username/password supplied"}}}},"/user/logout":{"get":{"tags":["user"],"summary":"Logs out current logged in user session","description":"","operationId":"logoutUser","produces":["application/xml","application/json"],"parameters":[],"responses":{"default":{"description":"successful operation"}}}},"/user/{username}":{"get":{"tags":["user"],"summary":"Get user by user name","description":"","operationId":"getUserByName","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be fetched. Use user1 for testing. ","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/User"}},"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}},"put":{"tags":["user"],"summary":"Updated user","description":"This can only be done by the logged in user.","operationId":"updateUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"name that need to be updated","required":true,"type":"string"},{"in":"body","name":"body","description":"Updated user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"400":{"description":"Invalid user supplied"},"404":{"description":"User not found"}}},"delete":{"tags":["user"],"summary":"Delete user","description":"This can only be done by the logged in user.","operationId":"deleteUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be deleted","required":true,"type":"string"}],"responses":{"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}}}},"securityDefinitions":{"petstore_auth":{"type":"oauth2","authorizationUrl":"http://petstore.swagger.io/oauth/dialog","flow":"implicit","scopes":{"write:pets":"modify pets in your account","read:pets":"read your pets"}},"api_key":{"type":"apiKey","name":"api_key","in":"header"}},"definitions":{"Order":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"petId":{"type":"integer","format":"int64"},"quantity":{"type":"integer","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean","default":false}},"xml":{"name":"Order"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Category"}},"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"integer","format":"int32","description":"User Status"}},"xml":{"name":"User"}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Tag"}},"Pet":{"type":"object","required":["name","photoUrls"],"properties":{"id":{"type":"integer","format":"int64"},"category":{"$ref":"#/definitions/Category"},"name":{"type":"string","example":"doggie"},"photoUrls":{"type":"array","xml":{"name":"photoUrl","wrapped":true},"items":{"type":"string"}},"tags":{"type":"array","xml":{"name":"tag","wrapped":true},"items":{"$ref":"#/definitions/Tag"}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"xml":{"name":"Pet"}},"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"type":{"type":"string"},"message":{"type":"string"}}}},"externalDocs":{"description":"Find out more about Swagger","url":"http://swagger.io"}}
{
"swagger": "2.1",
"info": {
"description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
"version": "1.0.1",
"title": "Swagger Petstore",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": "apiteam@swagger.io"
},
"license": {
"name": "Apache 2.1",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"host": "petstore.swagger.io",
"basePath": "/v2",
"tags": [
{
"name": "pet",
"description": "Everything about your Pets",
"externalDocs": {
"description": "Find out more",
"url": "http://swagger.io"
}
},
{
"name": "store",
"description": "Access to Petstore orders"
},
{
"name": "user",
"description": "Operations about user",
"externalDocs": {
"description": "Find out more about our store",
"url": "http://swagger.io"
}
}
],
"schemes": [
"http"
],
"paths": {
"/pet": {
"post": {
"tags": [
"pet"
],
"summary": "Add a new pet to the store",
"description": "",
"operationId": "addPet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
"put": {
"tags": [
"pet"
],
"summary": "Update an existing pet",
"description": "",
"operationId": "updatePet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
},
"405": {
"description": "Validation exception"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/findByStatus": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by status",
"description": "Multiple status values can be provided with comma separated strings",
"operationId": "findPetsByStatus",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "status",
"in": "query",
"description": "Status values that need to be considered for filter",
"required": true,
"type": "array",
"items": {
"type": "string",
"enum": [
"available",
"pending",
"sold"
],
"default": "available"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid status value"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/findByTags": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by tags",
"description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
"operationId": "findPetsByTags",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "tags",
"in": "query",
"description": "Tags to filter by",
"required": true,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid tag value"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
],
"deprecated": true
}
},
"/pet/{petId}": {
"get": {
"tags": [
"pet"
],
"summary": "Find pet by ID",
"description": "Returns a single pet",
"operationId": "getPetById",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet to return",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
}
},
"security": [
{
"api_key": []
}
]
},
"post": {
"tags": [
"pet"
],
"summary": "Updates a pet in the store with form data",
"description": "",
"operationId": "updatePetWithForm",
"consumes": [
"application/x-www-form-urlencoded"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet that needs to be updated",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "name",
"in": "formData",
"description": "Updated name of the pet",
"required": false,
"type": "string"
},
{
"name": "status",
"in": "formData",
"description": "Updated status of the pet",
"required": false,
"type": "string"
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
"delete": {
"tags": [
"pet"
],
"summary": "Deletes a pet",
"description": "",
"operationId": "deletePet",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "api_key",
"in": "header",
"required": false,
"type": "string"
},
{
"name": "petId",
"in": "path",
"description": "Pet id to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/{petId}/uploadImage": {
"post": {
"tags": [
"pet"
],
"summary": "uploads an image",
"description": "",
"operationId": "uploadFile",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet to update",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "additionalMetadata",
"in": "formData",
"description": "Additional data to pass to server",
"required": false,
"type": "string"
},
{
"name": "file",
"in": "formData",
"description": "file to upload",
"required": false,
"type": "file"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/ApiResponse"
}
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/store/inventory": {
"get": {
"tags": [
"store"
],
"summary": "Returns pet inventories by status",
"description": "Returns a map of status codes to quantities",
"operationId": "getInventory",
"produces": [
"application/json"
],
"parameters": [],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "object",
"additionalProperties": {
"type": "integer",
"format": "int32"
}
}
}
},
"security": [
{
"api_key": []
}
]
}
},
"/store/order": {
"post": {
"tags": [
"store"
],
"summary": "Place an order for a pet",
"description": "",
"operationId": "placeOrder",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "order placed for purchasing the pet",
"required": true,
"schema": {
"$ref": "#/definitions/Order"
}
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Order"
}
},
"400": {
"description": "Invalid Order"
}
}
}
},
"/store/order/{orderId}": {
"get": {
"tags": [
"store"
],
"summary": "Find purchase order by ID",
"description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions",
"operationId": "getOrderById",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "orderId",
"in": "path",
"description": "ID of pet that needs to be fetched",
"required": true,
"type": "integer",
"maximum": 10.0,
"minimum": 1.0,
"format": "int64"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Order"
}
},
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Order not found"
}
}
},
"delete": {
"tags": [
"store"
],
"summary": "Delete purchase order by ID",
"description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors",
"operationId": "deleteOrder",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "orderId",
"in": "path",
"description": "ID of the order that needs to be deleted",
"required": true,
"type": "integer",
"minimum": 1.0,
"format": "int64"
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Order not found"
}
}
}
},
"/user": {
"post": {
"tags": [
"user"
],
"summary": "Create user",
"description": "This can only be done by the logged in user.",
"operationId": "createUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Created user object",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/createWithArray": {
"post": {
"tags": [
"user"
],
"summary": "Creates list of users with given input array",
"description": "",
"operationId": "createUsersWithArrayInput",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "List of user object",
"required": true,
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/createWithList": {
"post": {
"tags": [
"user"
],
"summary": "Creates list of users with given input array",
"description": "",
"operationId": "createUsersWithListInput",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "List of user object",
"required": true,
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/login": {
"get": {
"tags": [
"user"
],
"summary": "Logs user into the system",
"description": "",
"operationId": "loginUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "query",
"description": "The user name for login",
"required": true,
"type": "string"
},
{
"name": "password",
"in": "query",
"description": "The password for login in clear text",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "string"
},
"headers": {
"X-Rate-Limit": {
"type": "integer",
"format": "int32",
"description": "calls per hour allowed by the user"
},
"X-Expires-After": {
"type": "string",
"format": "date-time",
"description": "date in UTC when token expires"
}
}
},
"400": {
"description": "Invalid username/password supplied"
}
}
}
},
"/user/logout": {
"get": {
"tags": [
"user"
],
"summary": "Logs out current logged in user session",
"description": "",
"operationId": "logoutUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/{username}": {
"get": {
"tags": [
"user"
],
"summary": "Get user by user name",
"description": "",
"operationId": "getUserByName",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "path",
"description": "The name that needs to be fetched. Use user1 for testing. ",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/User"
}
},
"400": {
"description": "Invalid username supplied"
},
"404": {
"description": "User not found"
}
}
},
"put": {
"tags": [
"user"
],
"summary": "Updated user",
"description": "This can only be done by the logged in user.",
"operationId": "updateUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "path",
"description": "name that need to be updated",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "body",
"description": "Updated user object",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"400": {
"description": "Invalid user supplied"
},
"404": {
"description": "User not found"
}
}
},
"delete": {
"tags": [
"user"
],
"summary": "Delete user",
"description": "This can only be done by the logged in user.",
"operationId": "deleteUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "path",
"description": "The name that needs to be deleted",
"required": true,
"type": "string"
}
],
"responses": {
"400": {
"description": "Invalid username supplied"
},
"404": {
"description": "User not found"
}
}
}
}
},
"securityDefinitions": {
"petstore_auth": {
"type": "oauth2",
"authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
"flow": "implicit",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
},
"api_key": {
"type": "apiKey",
"name": "api_key",
"in": "header"
}
},
"definitions": {
"Order": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"petId": {
"type": "integer",
"format": "int64"
},
"quantity": {
"type": "integer",
"format": "int32"
},
"shipDate": {
"type": "string",
"format": "date-time"
},
"status": {
"type": "string",
"description": "Order Status",
"enum": [
"placed",
"approved",
"delivered"
]
},
"complete": {
"type": "boolean",
"default": false
}
},
"xml": {
"name": "Order"
}
},
"Category": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
},
"xml": {
"name": "Category"
}
},
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"username": {
"type": "string"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"phone": {
"type": "string"
},
"userStatus": {
"type": "integer",
"format": "int32",
"description": "User Status"
}
},
"xml": {
"name": "User"
}
},
"Tag": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
},
"xml": {
"name": "Tag"
}
},
"Pet": {
"type": "object",
"required": [
"name",
"photoUrls"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"category": {
"$ref": "#/definitions/Category"
},
"name": {
"type": "string",
"example": "doggie"
},
"photoUrls": {
"type": "array",
"xml": {
"name": "photoUrl",
"wrapped": true
},
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"xml": {
"name": "tag",
"wrapped": true
},
"items": {
"$ref": "#/definitions/Tag"
}
},
"status": {
"type": "string",
"description": "pet status in the store",
"enum": [
"available",
"pending",
"sold"
]
}
},
"xml": {
"name": "Pet"
}
},
"ApiResponse": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"type": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
},
"externalDocs": {
"description": "Find out more about Swagger",
"url": "http://swagger.io"
}
}

@@ -1,1 +0,1035 @@

{"swagger":"2.0","info":{"description":"This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.","version":"1.0.0","title":"Swagger Petstore","termsOfService":"http://swagger.io/terms/","contact":{"email":"apiteam@swagger.io"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"}},"host":"petstore.swagger.io","basePath":"/v2","tags":[{"name":"pet","description":"Everything about your Pets","externalDocs":{"description":"Find out more","url":"http://swagger.io"}},{"name":"store","description":"Access to Petstore orders"},{"name":"user","description":"Operations about user","externalDocs":{"description":"Find out more about our store","url":"http://swagger.io"}}],"schemes":["http"],"paths":{"/pet":{"post":{"tags":["pet"],"summary":"Add a new pet to the store","description":"","operationId":"addPet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"put":{"tags":["pet"],"summary":"Update an existing pet","description":"","operationId":"updatePet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"},"405":{"description":"Validation exception"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByStatus":{"get":{"tags":["pet"],"summary":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","operationId":"findPetsByStatus","produces":["application/xml","application/json"],"parameters":[{"name":"status","in":"query","description":"Status values that need to be considered for filter","required":true,"type":"array","items":{"type":"string","enum":["available","pending","sold"],"default":"available"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid status value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByTags":{"get":{"tags":["pet"],"summary":"Finds Pets by tags","description":"Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","operationId":"findPetsByTags","produces":["application/xml","application/json"],"parameters":[{"name":"tags","in":"query","description":"Tags to filter by","required":true,"type":"array","items":{"type":"string"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid tag value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}],"deprecated":true}},"/pet/{petId}":{"get":{"tags":["pet"],"summary":"Find pet by ID","description":"Returns a single pet","operationId":"getPetById","produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to return","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Pet"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"api_key":[]}]},"post":{"tags":["pet"],"summary":"Updates a pet in the store with form data","description":"","operationId":"updatePetWithForm","consumes":["application/x-www-form-urlencoded"],"produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet that needs to be updated","required":true,"type":"integer","format":"int64"},{"name":"name","in":"formData","description":"Updated name of the pet","required":false,"type":"string"},{"name":"status","in":"formData","description":"Updated status of the pet","required":false,"type":"string"}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"delete":{"tags":["pet"],"summary":"Deletes a pet","description":"","operationId":"deletePet","produces":["application/xml","application/json"],"parameters":[{"name":"api_key","in":"header","required":false,"type":"string"},{"name":"petId","in":"path","description":"Pet id to delete","required":true,"type":"integer","format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}/uploadImage":{"post":{"tags":["pet"],"summary":"uploads an image","description":"","operationId":"uploadFile","consumes":["multipart/form-data"],"produces":["application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to update","required":true,"type":"integer","format":"int64"},{"name":"additionalMetadata","in":"formData","description":"Additional data to pass to server","required":false,"type":"string"},{"name":"file","in":"formData","description":"file to upload","required":false,"type":"file"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/ApiResponse"}}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/store/inventory":{"get":{"tags":["store"],"summary":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","operationId":"getInventory","produces":["application/json"],"parameters":[],"responses":{"200":{"description":"successful operation","schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"security":[{"api_key":[]}]}},"/store/order":{"post":{"tags":["store"],"summary":"Place an order for a pet","description":"","operationId":"placeOrder","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"order placed for purchasing the pet","required":true,"schema":{"$ref":"#/definitions/Order"}}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid Order"}}}},"/store/order/{orderId}":{"get":{"tags":["store"],"summary":"Find purchase order by ID","description":"For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions","operationId":"getOrderById","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of pet that needs to be fetched","required":true,"type":"integer","maximum":10.0,"minimum":1.0,"format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}},"delete":{"tags":["store"],"summary":"Delete purchase order by ID","description":"For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors","operationId":"deleteOrder","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of the order that needs to be deleted","required":true,"type":"integer","minimum":1.0,"format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}}},"/user":{"post":{"tags":["user"],"summary":"Create user","description":"This can only be done by the logged in user.","operationId":"createUser","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Created user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithArray":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithArrayInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithList":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithListInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/login":{"get":{"tags":["user"],"summary":"Logs user into the system","description":"","operationId":"loginUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"query","description":"The user name for login","required":true,"type":"string"},{"name":"password","in":"query","description":"The password for login in clear text","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"type":"string"},"headers":{"X-Rate-Limit":{"type":"integer","format":"int32","description":"calls per hour allowed by the user"},"X-Expires-After":{"type":"string","format":"date-time","description":"date in UTC when token expires"}}},"400":{"description":"Invalid username/password supplied"}}}},"/user/logout":{"get":{"tags":["user"],"summary":"Logs out current logged in user session","description":"","operationId":"logoutUser","produces":["application/xml","application/json"],"parameters":[],"responses":{"default":{"description":"successful operation"}}}},"/user/{username}":{"get":{"tags":["user"],"summary":"Get user by user name","description":"","operationId":"getUserByName","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be fetched. Use user1 for testing. ","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/User"}},"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}},"put":{"tags":["user"],"summary":"Updated user","description":"This can only be done by the logged in user.","operationId":"updateUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"name that need to be updated","required":true,"type":"string"},{"in":"body","name":"body","description":"Updated user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"400":{"description":"Invalid user supplied"},"404":{"description":"User not found"}}},"delete":{"tags":["user"],"summary":"Delete user","description":"This can only be done by the logged in user.","operationId":"deleteUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be deleted","required":true,"type":"string"}],"responses":{"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}}}},"securityDefinitions":{"petstore_auth":{"type":"oauth2","authorizationUrl":"http://petstore.swagger.io/oauth/dialog","flow":"implicit","scopes":{"write:pets":"modify pets in your account","read:pets":"read your pets"}},"api_key":{"type":"apiKey","name":"api_key","in":"header"}},"definitions":{"Order":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"petId":{"type":"integer","format":"int64"},"quantity":{"type":"integer","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean","default":false}},"xml":{"name":"Order"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Category"}},"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"integer","format":"int32","description":"User Status"}},"xml":{"name":"User"}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Tag"}},"Pet":{"type":"object","required":["name","photoUrls"],"properties":{"id":{"type":"integer","format":"int64"},"category":{"$ref":"#/definitions/Category"},"name":{"type":"string","example":"doggie"},"photoUrls":{"type":"array","xml":{"name":"photoUrl","wrapped":true},"items":{"type":"string"}},"tags":{"type":"array","xml":{"name":"tag","wrapped":true},"items":{"$ref":"#/definitions/Tag"}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"xml":{"name":"Pet"}},"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"type":{"type":"string"},"message":{"type":"string"}}}},"externalDocs":{"description":"Find out more about Swagger","url":"http://swagger.io"}}
{
"swagger": "2.0",
"info": {
"description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
"version": "1.0.0",
"title": "Swagger Petstore",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": "apiteam@swagger.io"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"host": "petstore.swagger.io",
"basePath": "/v2",
"tags": [
{
"name": "pet",
"description": "Everything about your Pets",
"externalDocs": {
"description": "Find out more",
"url": "http://swagger.io"
}
},
{
"name": "store",
"description": "Access to Petstore orders"
},
{
"name": "user",
"description": "Operations about user",
"externalDocs": {
"description": "Find out more about our store",
"url": "http://swagger.io"
}
}
],
"schemes": [
"http"
],
"paths": {
"/pet": {
"post": {
"tags": [
"pet"
],
"summary": "Add a new pet to the store",
"description": "",
"operationId": "addPet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
"put": {
"tags": [
"pet"
],
"summary": "Update an existing pet",
"description": "",
"operationId": "updatePet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
},
"405": {
"description": "Validation exception"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/findByStatus": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by status",
"description": "Multiple status values can be provided with comma separated strings",
"operationId": "findPetsByStatus",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "status",
"in": "query",
"description": "Status values that need to be considered for filter",
"required": true,
"type": "array",
"items": {
"type": "string",
"enum": [
"available",
"pending",
"sold"
],
"default": "available"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid status value"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/findByTags": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by tags",
"description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
"operationId": "findPetsByTags",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "tags",
"in": "query",
"description": "Tags to filter by",
"required": true,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid tag value"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
],
"deprecated": true
}
},
"/pet/{petId}": {
"get": {
"tags": [
"pet"
],
"summary": "Find pet by ID",
"description": "Returns a single pet",
"operationId": "getPetById",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet to return",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
}
},
"security": [
{
"api_key": []
}
]
},
"post": {
"tags": [
"pet"
],
"summary": "Updates a pet in the store with form data",
"description": "",
"operationId": "updatePetWithForm",
"consumes": [
"application/x-www-form-urlencoded"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet that needs to be updated",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "name",
"in": "formData",
"description": "Updated name of the pet",
"required": false,
"type": "string"
},
{
"name": "status",
"in": "formData",
"description": "Updated status of the pet",
"required": false,
"type": "string"
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
"delete": {
"tags": [
"pet"
],
"summary": "Deletes a pet",
"description": "",
"operationId": "deletePet",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "api_key",
"in": "header",
"required": false,
"type": "string"
},
{
"name": "petId",
"in": "path",
"description": "Pet id to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/{petId}/uploadImage": {
"post": {
"tags": [
"pet"
],
"summary": "uploads an image",
"description": "",
"operationId": "uploadFile",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet to update",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "additionalMetadata",
"in": "formData",
"description": "Additional data to pass to server",
"required": false,
"type": "string"
},
{
"name": "file",
"in": "formData",
"description": "file to upload",
"required": false,
"type": "file"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/ApiResponse"
}
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/store/inventory": {
"get": {
"tags": [
"store"
],
"summary": "Returns pet inventories by status",
"description": "Returns a map of status codes to quantities",
"operationId": "getInventory",
"produces": [
"application/json"
],
"parameters": [],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "object",
"additionalProperties": {
"type": "integer",
"format": "int32"
}
}
}
},
"security": [
{
"api_key": []
}
]
}
},
"/store/order": {
"post": {
"tags": [
"store"
],
"summary": "Place an order for a pet",
"description": "",
"operationId": "placeOrder",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "order placed for purchasing the pet",
"required": true,
"schema": {
"$ref": "#/definitions/Order"
}
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Order"
}
},
"400": {
"description": "Invalid Order"
}
}
}
},
"/store/order/{orderId}": {
"get": {
"tags": [
"store"
],
"summary": "Find purchase order by ID",
"description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions",
"operationId": "getOrderById",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "orderId",
"in": "path",
"description": "ID of pet that needs to be fetched",
"required": true,
"type": "integer",
"maximum": 10.0,
"minimum": 1.0,
"format": "int64"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Order"
}
},
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Order not found"
}
}
},
"delete": {
"tags": [
"store"
],
"summary": "Delete purchase order by ID",
"description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors",
"operationId": "deleteOrder",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "orderId",
"in": "path",
"description": "ID of the order that needs to be deleted",
"required": true,
"type": "integer",
"minimum": 1.0,
"format": "int64"
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Order not found"
}
}
}
},
"/user": {
"post": {
"tags": [
"user"
],
"summary": "Create user",
"description": "This can only be done by the logged in user.",
"operationId": "createUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Created user object",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/createWithArray": {
"post": {
"tags": [
"user"
],
"summary": "Creates list of users with given input array",
"description": "",
"operationId": "createUsersWithArrayInput",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "List of user object",
"required": true,
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/createWithList": {
"post": {
"tags": [
"user"
],
"summary": "Creates list of users with given input array",
"description": "",
"operationId": "createUsersWithListInput",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "List of user object",
"required": true,
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/login": {
"get": {
"tags": [
"user"
],
"summary": "Logs user into the system",
"description": "",
"operationId": "loginUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "query",
"description": "The user name for login",
"required": true,
"type": "string"
},
{
"name": "password",
"in": "query",
"description": "The password for login in clear text",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "string"
},
"headers": {
"X-Rate-Limit": {
"type": "integer",
"format": "int32",
"description": "calls per hour allowed by the user"
},
"X-Expires-After": {
"type": "string",
"format": "date-time",
"description": "date in UTC when token expires"
}
}
},
"400": {
"description": "Invalid username/password supplied"
}
}
}
},
"/user/logout": {
"get": {
"tags": [
"user"
],
"summary": "Logs out current logged in user session",
"description": "",
"operationId": "logoutUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [],
"responses": {
"default": {
"description": "successful operation"
}
}
}
},
"/user/{username}": {
"get": {
"tags": [
"user"
],
"summary": "Get user by user name",
"description": "",
"operationId": "getUserByName",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "path",
"description": "The name that needs to be fetched. Use user1 for testing. ",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/User"
}
},
"400": {
"description": "Invalid username supplied"
},
"404": {
"description": "User not found"
}
}
},
"put": {
"tags": [
"user"
],
"summary": "Updated user",
"description": "This can only be done by the logged in user.",
"operationId": "updateUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "path",
"description": "name that need to be updated",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "body",
"description": "Updated user object",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"400": {
"description": "Invalid user supplied"
},
"404": {
"description": "User not found"
}
}
},
"delete": {
"tags": [
"user"
],
"summary": "Delete user",
"description": "This can only be done by the logged in user.",
"operationId": "deleteUser",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "username",
"in": "path",
"description": "The name that needs to be deleted",
"required": true,
"type": "string"
}
],
"responses": {
"400": {
"description": "Invalid username supplied"
},
"404": {
"description": "User not found"
}
}
}
}
},
"securityDefinitions": {
"petstore_auth": {
"type": "oauth2",
"authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
"flow": "implicit",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
},
"api_key": {
"type": "apiKey",
"name": "api_key",
"in": "header"
}
},
"definitions": {
"Order": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"petId": {
"type": "integer",
"format": "int64"
},
"quantity": {
"type": "integer",
"format": "int32"
},
"shipDate": {
"type": "string",
"format": "date-time"
},
"status": {
"type": "string",
"description": "Order Status",
"enum": [
"placed",
"approved",
"delivered"
]
},
"complete": {
"type": "boolean",
"default": false
}
},
"xml": {
"name": "Order"
}
},
"Category": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
},
"xml": {
"name": "Category"
}
},
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"username": {
"type": "string"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"phone": {
"type": "string"
},
"userStatus": {
"type": "integer",
"format": "int32",
"description": "User Status"
}
},
"xml": {
"name": "User"
}
},
"Tag": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
},
"xml": {
"name": "Tag"
}
},
"Pet": {
"type": "object",
"required": [
"name",
"photoUrls"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"category": {
"$ref": "#/definitions/Category"
},
"name": {
"type": "string",
"example": "doggie"
},
"photoUrls": {
"type": "array",
"xml": {
"name": "photoUrl",
"wrapped": true
},
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"xml": {
"name": "tag",
"wrapped": true
},
"items": {
"$ref": "#/definitions/Tag"
}
},
"status": {
"type": "string",
"description": "pet status in the store",
"enum": [
"available",
"pending",
"sold"
]
}
},
"xml": {
"name": "Pet"
}
},
"ApiResponse": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"type": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
},
"externalDocs": {
"description": "Find out more about Swagger",
"url": "http://swagger.io"
}
}

@@ -164,3 +164,3 @@ import {exec} from 'child_process';

expect(result).toEqual(jasmine.stringMatching('0 breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('3 non-breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('4 non-breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('2 unclassified changes found.'));

@@ -177,2 +177,5 @@

expect(result).toContain('Non-breaking: the path [swagger] was modified ' +
'from \'2.0\' to \'2.1\'');
expect(result).toContain('Unclassified: the path [info/x-info-property] was modified ' +

@@ -193,5 +196,8 @@ 'from \'some content\' to \'some new content\'');

expect(result).toEqual(jasmine.stringMatching('0 breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('2 non-breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('3 non-breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('0 unclassified changes found.'));
expect(result).toContain('Non-breaking: the path [swagger] was modified ' +
'from \'2.0\' to \'2.1\'');
expect(result).toContain('Non-breaking: the path [info/version] was modified ' +

@@ -204,2 +210,28 @@ 'from \'1.0.0\' to \'1.0.1\'');

});
it('should be able to process real OpenApi 3.0.0 files', (done) => {
invokeCommand({
newSpecLocation: 'test/e2e/fixtures/openapi-3-new.json',
oldSpecLocation: 'test/e2e/fixtures/openapi-3-old.json'
}).then((result) => {
expect(result).toEqual(jasmine.stringMatching('0 breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('3 non-breaking changes found.'));
expect(result).toEqual(jasmine.stringMatching('2 unclassified changes found.'));
expect(result).toContain('Non-breaking: the path [openapi] was modified ' +
'from \'3.0.0\' to \'3.0.0-RC1\'');
expect(result).toContain('Non-breaking: the path [info/version] was modified ' +
'from \'Test version\' to \'New test version\'');
expect(result).toContain('Non-breaking: the path [info/title] was modified ' +
'from \'Test API\' to \'New test API\'');
expect(result).toContain('Unclassified: the path [info/x-info-property] was modified ' +
'from \'Some content\' to \'Some new content\'');
expect(result).toContain('Unclassified: the path [x-generic-property] was modified ' +
'from \'Some content\' to \'Some new content\'');
}).then(done, done.fail);
});
});
import specDiffer from '../../../lib/openapi-diff/spec-differ';
import {

@@ -7,87 +8,44 @@ Diff,

let result: Diff;
describe('specDiffer', () => {
const buildParsedSpecWithFullInfoObject = (): ParsedSpec => {
const spec = {
info: {
contact: {
email: 'contact email',
name: 'contact name',
url: 'contact url'
},
description: 'spec description',
licence: {
name: 'licence name',
url: 'licence url'
},
termsOfService: 'terms of service',
title: 'spec title',
version: 'version'
},
openapi: {
originalPath: ['openapi'],
parsedValue: '3.0.0'
}
};
return spec;
};
describe('when there is a single change in the info object', () => {
beforeEach(() => {
const oldParsedSpec = buildParsedSpecWithFullInfoObject();
const newParsedSpec = buildParsedSpecWithFullInfoObject();
newParsedSpec.info.title = 'NEW spec title';
result = specDiffer.diff(oldParsedSpec, newParsedSpec);
});
it('should classify a single change in the info object as non-breaking', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.breakingChanges.length).toEqual(0);
expect(result.unclassifiedChanges.length).toEqual(0);
expect(result.nonBreakingChanges.length).toBe(1);
});
it('should populate the type of a single change in the info object as non-breaking', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.nonBreakingChanges[0].type).toEqual('non-breaking');

@@ -97,124 +55,15 @@ });

it('should populate the taxonomy of a single change in the info object as an edition in it', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.nonBreakingChanges[0].taxonomy).toEqual('info.object.edit');
});
it('should populate the path of a single change in the info object correctly', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
it('should populate the paths of a single change in the info object correctly', () => {
expect(result.nonBreakingChanges[0].path[0]).toEqual('info');
expect(result.nonBreakingChanges[0].path[1]).toEqual('title');
expect(result.nonBreakingChanges[0].printablePath[0]).toEqual('info');
expect(result.nonBreakingChanges[0].printablePath[1]).toEqual('title');
});
it('should copy the rest of the individual diff attributes across', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.nonBreakingChanges[0].lhs).toEqual('old spec title');
expect(result.nonBreakingChanges[0].rhs).toEqual('new spec title');
expect(result.nonBreakingChanges[0].lhs).toEqual('spec title');
expect(result.nonBreakingChanges[0].rhs).toEqual('NEW spec title');
expect(result.nonBreakingChanges[0].index).toBeNull();

@@ -227,83 +76,19 @@ expect(result.nonBreakingChanges[0].item).toBeNull();

it('should classify multiple changes in the info object as non-breaking', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
beforeEach(() => {
const oldParsedSpec = buildParsedSpecWithFullInfoObject();
const newParsedSpec = buildParsedSpecWithFullInfoObject();
newParsedSpec.info.title = 'NEW spec title';
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'new contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
if (newParsedSpec.info.contact) {
newParsedSpec.info.contact.name = 'NEW contact name';
} else {
fail('Unexpected mock spec attributes missing');
}
result = specDiffer.diff(oldParsedSpec, newParsedSpec);
});
const result: Diff = specDiffer.diff(oldSpec, newSpec);
it('should classify multiple changes in the info object as non-breaking', () => {
expect(result.breakingChanges.length).toEqual(0);
expect(result.unclassifiedChanges.length).toEqual(0);
expect(result.nonBreakingChanges.length).toEqual(2);
});
it('should populate the types of multiple changes in the info object as non-breaking', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'new contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.nonBreakingChanges[0].type).toEqual('non-breaking');

@@ -314,39 +99,2 @@ expect(result.nonBreakingChanges[1].type).toEqual('non-breaking');

it('should populate the taxonomy of multiple changes in the info object as an edition to it', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'new contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.nonBreakingChanges[0].taxonomy).toEqual('info.object.edit');

@@ -356,89 +104,16 @@ expect(result.nonBreakingChanges[1].taxonomy).toEqual('info.object.edit');

it('should populate the path of the multiple changes in the info object correctly', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
it('should populate the paths of the multiple changes in the info object correctly', () => {
expect(result.nonBreakingChanges[0].path[0]).toEqual('info');
expect(result.nonBreakingChanges[0].path[1]).toEqual('contact');
expect(result.nonBreakingChanges[0].path[2]).toEqual('name');
expect(result.nonBreakingChanges[0].printablePath[0]).toEqual('info');
expect(result.nonBreakingChanges[0].printablePath[1]).toEqual('contact');
expect(result.nonBreakingChanges[0].printablePath[2]).toEqual('name');
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'new spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.nonBreakingChanges[0].path[0]).toEqual('info');
expect(result.nonBreakingChanges[0].path[1]).toEqual('title');
expect(result.nonBreakingChanges[1].path[0]).toEqual('info');
expect(result.nonBreakingChanges[1].path[1]).toEqual('title');
expect(result.nonBreakingChanges[1].printablePath[0]).toEqual('info');
expect(result.nonBreakingChanges[1].printablePath[1]).toEqual('title');
});
});
it('should populate the path of the multiple changes in the info object correctly when nested', () => {
const oldSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'old contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const newSpec: ParsedSpec = {
info: {
contact: {
email: 'old contact email',
name: 'new contact name',
url: 'old contact url'
},
description: 'old spec description',
licence: {
name: 'old licence name',
url: 'old licence url'
},
termsOfService: 'old terms of service',
title: 'old spec title',
version: 'old version'
}
};
const result: Diff = specDiffer.diff(oldSpec, newSpec);
expect(result.nonBreakingChanges[0].path[0]).toEqual('info');
expect(result.nonBreakingChanges[0].path[1]).toEqual('contact');
expect(result.nonBreakingChanges[0].path[2]).toEqual('name');
});
});
import specParser from '../../../lib/openapi-diff/spec-parser';
import {OpenAPISpec, ParsedSpec} from '../../../lib/openapi-diff/types';
import {OpenAPI3Spec, ParsedSpec} from '../../../lib/openapi-diff/types';
let resultingSpec: ParsedSpec;
describe('specParser, with regards to the info object,', () => {
const buildSimpleOpenApi3Spec = (): OpenAPI3Spec => {
const spec = {
info: {
title: 'spec title',
version: 'spec version'
},
openapi: '3.0.0'
};
return spec;
};
const buildOpenApi3SpecWithCompleteInfoObject = (): OpenAPI3Spec => {
const spec = {
info: {
contact: {
email: 'contact email',
name: 'contact name',
url: 'contact url'
},
description: 'spec description',
licence: {
name: 'licence name',
url: 'licence url'
},
termsOfService: 'terms of service',
title: 'spec title',
version: 'version'
},
openapi: '3.0.0'
};
return spec;
};
describe('when the original spec has all the default fields populated', () => {
beforeEach(() => {
const originalSpec = buildOpenApi3SpecWithCompleteInfoObject();
resultingSpec = specParser.parse(originalSpec);
});
it('should generate a parsed spec with an info object', () => {
const originalSpec: OpenAPISpec = {
info: {
contact: {
email: 'contact email',
name: 'contact name',
url: 'contact url'
},
description: 'spec description',
licence: {
name: 'licence name',
url: 'licence url'
},
termsOfService: 'terms of service',
title: 'spec title',
version: 'version'
}
};
const resultingSpec: OpenAPISpec = specParser.parse(originalSpec);
expect(resultingSpec.info).toBeDefined();

@@ -33,21 +53,2 @@ });

it('should generate a parsed spec copying across all the default fields to the info object', () => {
const originalSpec: OpenAPISpec = {
info: {
contact: {
email: 'contact email',
name: 'contact name',
url: 'contact url'
},
description: 'spec description',
licence: {
name: 'licence name',
url: 'licence url'
},
termsOfService: 'terms of service',
title: 'spec title',
version: 'version'
}
};
const resultingSpec: OpenAPISpec = specParser.parse(originalSpec);
expect(resultingSpec.info.title).toBe('spec title');

@@ -77,12 +78,8 @@ expect(resultingSpec.info.description).toBe('spec description');

beforeEach(() => {
const originalSpec = buildSimpleOpenApi3Spec();
resultingSpec = specParser.parse(originalSpec);
});
it('should generate a parsed spec with an info object', () => {
const originalSpec: OpenAPISpec = {
info: {
title: 'spec title',
version: 'version'
}
};
const resultingSpec: ParsedSpec = specParser.parse(originalSpec);
expect(resultingSpec.info).toBeDefined();

@@ -92,12 +89,4 @@ });

it('should generate a parsed spec copying across only the required fields to the info object', () => {
const originalSpec: OpenAPISpec = {
info: {
title: 'spec title',
version: 'version'
}
};
const resultingSpec: ParsedSpec = specParser.parse(originalSpec);
expect(resultingSpec.info.title).toBe('spec title');
expect(resultingSpec.info.version).toBe('version');
expect(resultingSpec.info.version).toBe('spec version');
});

@@ -108,13 +97,9 @@ });

beforeEach(() => {
const originalSpec = buildSimpleOpenApi3Spec();
originalSpec.info['x-external-id'] = 'some id';
resultingSpec = specParser.parse(originalSpec);
});
it('should generate a parsed spec with an info object', () => {
const originalSpec: OpenAPISpec = {
info: {
title: 'spec title',
version: 'version',
'x-external-id': 'some id'
}
};
const resultingSpec: ParsedSpec = specParser.parse(originalSpec);
expect(resultingSpec.info).toBeDefined();

@@ -124,31 +109,5 @@ });

it('should generate a parsed spec copying across the x-property and its value', () => {
const originalSpec: OpenAPISpec = {
info: {
title: 'spec title',
version: 'version',
'x-external-id': 'some id'
}
};
const resultingSpec: ParsedSpec = specParser.parse(originalSpec);
expect(resultingSpec.info['x-external-id']).toBe('some id');
});
});
describe('when the original spec has an x-property at the top level', () => {
it('should generate a parsed spec copying across the x-property and its value', () => {
const originalSpec: OpenAPISpec = {
info: {
title: 'spec title',
version: 'version'
},
'x-external-id': 'some id'
};
const resultingSpec: ParsedSpec = specParser.parse(originalSpec);
expect(resultingSpec['x-external-id']).toBe('some id');
});
});
});
import specParser from '../../../lib/openapi-diff/spec-parser';
import {OpenAPISpec, ParsedSpec} from '../../../lib/openapi-diff/types';
import {OpenAPI3Spec, ParsedSpec} from '../../../lib/openapi-diff/types';

@@ -10,3 +10,3 @@ describe('specParser, with regards to the top level object,', () => {

const originalSpec: OpenAPISpec = {
const originalSpec: OpenAPI3Spec = {
info: {

@@ -16,2 +16,3 @@ title: 'spec title',

},
openapi: '3.0.0',
'x-external-id': 'some id',

@@ -18,0 +19,0 @@ 'x-internal-id': 'some other id'

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc