diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a036fc15..22991625 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,8 +27,14 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- - name: Install deps and run tests
- run: npm cit
+ - name: Install deps
+ run: npm ci
+
+ - name: Run tests
+ run: npm test
+
+ - name: Run benchmarks
+ run: npm run bench
lint:
runs-on: ubuntu-latest
diff --git a/package-lock.json b/package-lock.json
index c8375012..6a0f84ce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,6 +4,7 @@
"requires": true,
"packages": {
"": {
+ "name": "oas",
"workspaces": [
"./packages/*"
],
@@ -13897,9 +13898,9 @@
}
},
"node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"dev": true,
"funding": [
{
@@ -20621,7 +20622,6 @@
"jsonpath-plus": "^10.0.0",
"jsonpointer": "^5.0.0",
"memoizee": "^0.4.16",
- "oas-normalize": "file:../oas-normalize",
"openapi-types": "^12.1.1",
"path-to-regexp": "^8.1.0",
"remove-undefined-objects": "^5.0.0"
diff --git a/package.json b/package.json
index 0df6e734..779d7e8f 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,7 @@
"scripts": {
"alex": "alex .",
"attw": "npx lerna run attw --stream",
+ "bench": "vitest bench",
"build": "npx lerna run build --stream",
"clean": "npx lerna clean",
"lint": "npm run lint:types && npm run lint:js && npm run prettier",
diff --git a/packages/oas-normalize/README.md b/packages/oas-normalize/README.md
index 30c33b0a..6b5f7678 100644
--- a/packages/oas-normalize/README.md
+++ b/packages/oas-normalize/README.md
@@ -5,7 +5,7 @@
- Tooling for converting, validating, and parsing OpenAPI, Swagger, and Postman API definitions
+ Tooling for converting, validating, and parsing OpenAPI, Swagger, and Postman API definitions.
@@ -27,126 +27,154 @@ npm install oas-normalize
## Usage
-```javascript
+```ts
import OASNormalize from 'oas-normalize';
-// const { default: OASNormalize } = require('oas-normalize'); // If you're using CJS.
const oas = new OASNormalize(
'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore-expanded.yaml',
- // ...or a string, path, JSON blob, whatever you've got.
+ // ...or a JSON object, YAML, a file path, stringified JSON, whatever you have.
);
-oas
+await oas
.validate()
- .then(definition => {
- // Definition will always be JSON, and valid.
- console.log(definition);
+ .then(() => {
+ // The API definition is valid!
})
.catch(err => {
- console.log(err);
+ console.error(err);
});
```
-### `#bundle()`
+> [!WARNING]
+> Support for Postman collections is experimental. If you've supplied a Postman collection to the library, it will **always** be converted to OpenAPI, using [`@readme/postman-to-openapi`](https://npm.im/@readme/postman-to-openapi) before doing any bundling, validating, etc.
-> **Note**
->
-> Because Postman collections don't support `$ref` pointers, this method will automatically upconvert a Postman collection to OpenAPI if supplied one.
+### `.load()`
+
+Load and retrive the API definition that `oas-normalize` was initialized with. Every method of `oas-normalize` utilizes this internally however if you would like to retrieve the original API _definition_ supplied (for example if all you had was a URL, a file path, or a buffer), you can use `.load()` to automatically resolve and return its contents.
+
+```ts
+const file = await oas.load();
+console.log(file);
+```
+
+### `.bundle()`
Bundle up the given API definition, resolving any external `$ref` pointers in the process.
-```js
-await oas.bundle().then(definition => {
- console.log(definition);
-});
+```ts
+const definition = await oas.bundle();
+console.log(definition);
```
-### `#deref()`
+### `.convert()`
-> **Note**
->
-> Because Postman collections don't support `$ref` pointers, this method will automatically upconvert a Postman collection to OpenAPI if supplied one.
+Convert a given API definition into an OpenAPI definition JSON object.
+
+```ts
+await oas
+ .convert()
+ .then(definition => {
+ // Definition will always be an OpenAPI JSON object, regardless if a
+ // Swagger definition, Postman collection, or even YAML was supplied.
+ console.log(definition);
+ })
+ .catch(err => {
+ console.error(err);
+ });
+```
+
+### `.deref()`
Dereference the given API definition, resolving all `$ref` pointers in the process.
-```js
-await oas.deref().then(definition => {
- console.log(definition);
-});
+```ts
+const definition = await oas.bundle();
+console.log(definition);
```
-### `#validate({ convertToLatest?: boolean })`
+### `.validate()`
-Validate and optionally convert to OpenAPI, a given API definition. This supports Swagger 2.0, OpenAPI 3.x API definitions as well as Postman 2.x collections.
+Validate a given API definition. This supports Swagger 2.0 and OpenAPI 3.x API definitions, as well as Postman 2.x collections.
-Please note that if you've supplied a Postman collection to the library it will **always** be converted to OpenAPI, using [@readme/postman-to-openapi](https://npm.im/@readme/postman-to-openapi), and we will only validate resulting OpenAPI definition.
-
-```js
-await oas.validate().then(definition => {
- console.log(definition);
-});
+```ts
+try {
+ await oas.validate();
+ // The API definition is valid!
+} catch (err) {
+ console.error(err);
+}
```
-#### Options
+#### Error Handling
-
-| Option | Type | Description |
-| :--- | :--- | :--- |
-| `convertToLatest` | Boolean | By default `#validate` will not upconvert Swagger API definitions to OpenAPI so if you wish for this to happen, supply `true`. |
-
+All thrown validation error messages that direct the user to the line(s) where their errors are present:
-#### Error Handling
+```
+OpenAPI schema validation failed.
-For validation errors, when available, you'll get back an object:
-
-```js
-{
- "details": [
- // Ajv pathing errors. For example:
- /* {
- "instancePath": "/components/securitySchemes/tlsAuth",
- "schemaPath": "#/properties/securitySchemes/patternProperties/%5E%5Ba-zA-Z0-9%5C.%5C-_%5D%2B%24/oneOf",
- "keyword": "oneOf",
- "params": { "passingSchemas": null },
- "message": "must match exactly one schema in oneOf"
- }, */
- ]
-}
+REQUIRED must have required property 'url'
+
+ 7 | },
+ 8 | "servers": [
+> 9 | {
+ | ^ ☹️ url is missing here!
+ 10 | "urll": "http://petstore.swagger.io/v2"
+ 11 | }
+ 12 | ],
```
-`message` is almost always there, but `path` is less dependable.
+However if you would like to programatically access this information the `SyntaxError` error that is thrown contains a `details` array of [AJV](https://npm.im/ajv) errors:
+
+```json
+[
+ {
+ "instancePath": "/servers/0",
+ "schemaPath": "#/required",
+ "keyword": "required",
+ "params": { "missingProperty": "url" },
+ "message": "must have required property 'url'",
+ },
+ {
+ "instancePath": "/servers/0",
+ "schemaPath": "#/additionalProperties",
+ "keyword": "additionalProperties",
+ "params": { "additionalProperty": "urll" },
+ "message": "must NOT have additional properties",
+ },
+];
+```
-### `#version()`
+### `.version()`
Load and retrieve version information about a supplied API definition.
-```js
-await oas.version().then(({ specification, version }) => {
- console.log(specification); // openapi
- console.log(version); // 3.1.0
-});
+```ts
+const { specification, version } = await oas.version();
+
+console.log(specification); // openapi
+console.log(version); // 3.1.0
```
### Options
##### Enable local paths
-For security reasons, you need to opt into allowing fetching by a local path. To enable it supply the `enablePaths` option to the class instance:
+For security reasons, you need to opt into allowing fetching by a local path. To enable this supply the `enablePaths` option to the class instance:
-```js
+```ts
const oas = new OASNormalize('./petstore.json', { enablePaths: true });
```
##### Colorized errors
-If you wish errors from `.validate()` to be styled and colorized, supply `colorizeErrors: true` to your instance of `OASNormalize`:
+If you wish errors from `.validate()` to be styled and colorized, supply `colorizeErrors: true` to the class instance:
-```js
+```ts
const oas = new OASNormalize('https://example.com/petstore.json', {
colorizeErrors: true,
});
```
-Error messages will look like such:
+When enabled thrown validation error messages will now resemble the following:
diff --git a/packages/oas-normalize/package.json b/packages/oas-normalize/package.json
index f939daf8..88403456 100644
--- a/packages/oas-normalize/package.json
+++ b/packages/oas-normalize/package.json
@@ -53,6 +53,7 @@
},
"scripts": {
"attw": "attw --pack --format table-flipped",
+ "bench": "echo 'Please run benchmarks from the root!' && exit 1",
"build": "tsup",
"lint": "npm run lint:types && npm run lint:js",
"lint:js": "eslint . --ext .js,.ts --ignore-path ../../.gitignore",
diff --git a/packages/oas-normalize/src/index.ts b/packages/oas-normalize/src/index.ts
index df958a92..b95ba34d 100644
--- a/packages/oas-normalize/src/index.ts
+++ b/packages/oas-normalize/src/index.ts
@@ -12,6 +12,7 @@ import * as utils from './lib/utils.js';
export default class OASNormalize {
cache: {
bundle?: OpenAPI.Document | false;
+ convert?: OpenAPI.Document | false;
deref?: OpenAPI.Document | false;
load?: Record | false;
};
@@ -40,15 +41,16 @@ export default class OASNormalize {
}
/**
- * @private
+ * Load and return the API definition that `oas-normalize` was initialized with.
+ *
*/
async load(): Promise> {
- if (this.cache.load) return Promise.resolve(this.cache.load);
+ if (this.cache.load) return this.cache.load;
const resolve = (obj: Parameters[0]) => {
const ret = utils.stringToJSON(obj);
this.cache.load = ret;
- return Promise.resolve(ret);
+ return ret;
};
switch (this.type) {
@@ -67,24 +69,21 @@ export default class OASNormalize {
case 'path':
// Load a local file
if (!this.opts.enablePaths) {
- return Promise.reject(new Error('Use `opts.enablePaths` to enable accessing local files.'));
+ throw new Error('Use `opts.enablePaths` to enable accessing local files.');
}
const contents = fs.readFileSync(this.file).toString();
if (!contents.trim()) {
- return Promise.reject(new Error('No file contents found.'));
+ throw new Error('No file contents found.');
}
return resolve(contents);
default:
- return Promise.reject(new Error('Could not load this file.'));
+ throw new Error('Could not load this file.');
}
}
- /**
- * @private
- */
- static async convertPostmanToOpenAPI(schema: any) {
+ private static async convertPostmanToOpenAPI(schema: any) {
return postmanToOpenAPI(JSON.stringify(schema), undefined, { outputFormat: 'json', replaceVars: true }).then(
JSON.parse,
);
@@ -95,7 +94,7 @@ export default class OASNormalize {
*
*/
async bundle() {
- if (this.cache.bundle) return Promise.resolve(this.cache.bundle);
+ if (this.cache.bundle) return this.cache.bundle;
return this.load()
.then(schema => {
@@ -120,7 +119,7 @@ export default class OASNormalize {
*
*/
async deref() {
- if (this.cache.deref) return Promise.resolve(this.cache.deref);
+ if (this.cache.deref) return this.cache.deref;
return this.load()
.then(schema => {
@@ -141,19 +140,47 @@ export default class OASNormalize {
}
/**
- * Validate, and potentially convert to OpenAPI, a given API definition.
+ * Convert a given API definition to OpenAPI if it is not already.
+ *
+ */
+ async convert(): Promise {
+ if (this.cache.convert) return this.cache.convert;
+
+ return this.load()
+ .then(async schema => {
+ // If we have a Postman collection we need to convert it to OpenAPI.
+ return utils.isPostman(schema) ? OASNormalize.convertPostmanToOpenAPI(schema) : schema;
+ })
+ .then(async schema => {
+ if (!utils.isSwagger(schema) && !utils.isOpenAPI(schema)) {
+ throw new Error('The supplied API definition is unsupported.');
+ } else if (utils.isOpenAPI(schema)) {
+ return schema;
+ }
+
+ const baseVersion = parseInt(schema.swagger, 10);
+ if (baseVersion === 1) {
+ throw new Error('Swagger v1.2 is unsupported.');
+ }
+
+ return converter
+ .convertObj(schema, { anchors: true })
+ .then((options: { openapi: OpenAPI.Document }) => options.openapi);
+ });
+ }
+
+ /**
+ * Validate a given API definition.
+ *
+ * If supplied a Postman collection it will be converted to OpenAPI first and then run through
+ * standard OpenAPI validation.
*
*/
async validate(
opts: {
- /**
- * Automatically convert the supplied API definition to the latest version of OpenAPI.
- */
- convertToLatest?: boolean;
parser?: openapiParser.Options;
- } = { convertToLatest: false },
- ): Promise {
- const convertToLatest = opts.convertToLatest;
+ } = {},
+ ): Promise {
const parserOptions = opts.parser || {};
if (!parserOptions.validate) {
parserOptions.validate = {};
@@ -163,44 +190,34 @@ export default class OASNormalize {
return this.load()
.then(async schema => {
- if (!utils.isPostman(schema)) {
- return schema;
- }
-
- return OASNormalize.convertPostmanToOpenAPI(schema);
+ // Because we don't have something akin to `openapi-parser` for Postman collections we just
+ // always convert them to OpenAPI.
+ return utils.isPostman(schema) ? OASNormalize.convertPostmanToOpenAPI(schema) : schema;
})
.then(async schema => {
if (!utils.isSwagger(schema) && !utils.isOpenAPI(schema)) {
- return Promise.reject(new Error('The supplied API definition is unsupported.'));
+ throw new Error('The supplied API definition is unsupported.');
} else if (utils.isSwagger(schema)) {
const baseVersion = parseInt(schema.swagger, 10);
if (baseVersion === 1) {
- return Promise.reject(new Error('Swagger v1.2 is unsupported.'));
+ throw new Error('Swagger v1.2 is unsupported.');
}
}
/**
- * `openapiParser.validate()` dereferences schemas at the same time as validation and does
- * not give us an option to disable this. Since all we already have a dereferencing method
- * on this library and our `validate()` method here just needs to tell us if the definition
- * is valid or not we need to clone it before passing it over to `openapi-parser` so as to
- * not run into pass-by-reference problems.
+ * `openapiParser.validate()` dereferences schemas at the same time as validation, mutating
+ * the supplied parameter in the process, and does not give us an option to disable this.
+ * As we already have a dereferencing method on this library, and this method just needs to
+ * tell us if the API definition is valid or not, we need to clone the schema before
+ * supplying it to `openapi-parser`.
*/
// eslint-disable-next-line try-catch-failsafe/json-parse
const clonedSchema = JSON.parse(JSON.stringify(schema));
- return openapiParser
- .validate(clonedSchema, parserOptions)
- .then(() => {
- if (!convertToLatest || utils.isOpenAPI(schema)) {
- return schema;
- }
-
- return converter
- .convertObj(schema, { anchors: true })
- .then((options: { openapi: OpenAPI.Document }) => options.openapi);
- })
- .catch(err => Promise.reject(err));
+ return openapiParser.validate(clonedSchema, parserOptions).then(() => {
+ // The API definition, whatever its format or specification, is valid.
+ return true;
+ });
});
}
diff --git a/packages/oas-normalize/test/__fixtures__/postman/petstore.collection.yaml b/packages/oas-normalize/test/__fixtures__/postman/petstore.collection.yaml
new file mode 100644
index 00000000..05bf5a90
--- /dev/null
+++ b/packages/oas-normalize/test/__fixtures__/postman/petstore.collection.yaml
@@ -0,0 +1,1793 @@
+info:
+ _postman_id: 0b2e8577-2899-4229-bb1c-4cb031108c2f
+ name: Swagger Petstore
+ 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.
+
+ Contact Support:
+ Email: apiteam@swagger.io
+ schema: https://schema.getpostman.com/json/collection/v2.1.0/collection.json
+item:
+ - name: pet
+ item:
+ - name: '{pet Id}'
+ item:
+ - name: Find pet by ID
+ request:
+ auth:
+ type: apikey
+ apikey:
+ - key: key
+ value: api_key
+ type: string
+ - key: value
+ value: ''
+ type: string
+ - key: in
+ value: header
+ type: string
+ method: GET
+ header:
+ - key: Accept
+ value: application/xml
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet to return'
+ description: Returns a single pet
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: apikey'
+ key: api_key
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet to return'
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ {
+ "name": "doggie",
+ "photoUrls": [
+ "https://example.com/photo.png",
+ "https://example.com/photo.png"
+ ],
+ "id": 25,
+ "category": {
+ "id": -66648423,
+ "name": "sint proident voluptate nostrud"
+ },
+ "tags": [
+ {
+ "id": -36713801,
+ "name": "cupidatat laboris"
+ },
+ {
+ "id": 88956444,
+ "name": "sed"
+ }
+ ],
+ "status": "available"
+ }
+ - name: Invalid ID supplied
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: apikey'
+ key: api_key
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet to return'
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Pet not found
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: apikey'
+ key: api_key
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet to return'
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: successful response
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: apikey'
+ key: api_key
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet to return'
+ status: Internal Server Error
+ code: 500
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Updates a pet in the store with form data
+ request:
+ auth:
+ type: oauth2
+ oauth2:
+ - key: scope
+ value: write:pets read:pets
+ type: string
+ - key: authUrl
+ value: http://petstore.swagger.io/oauth/dialog
+ type: string
+ - key: grant_type
+ value: implicit
+ type: string
+ method: POST
+ header:
+ - key: Content-Type
+ value: application/x-www-form-urlencoded
+ body:
+ mode: urlencoded
+ urlencoded:
+ - key: name
+ value: dolore magna
+ description: Updated name of the pet
+ - key: status
+ value: et incididunt
+ description: Updated status of the pet
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet that needs to be updated'
+ response:
+ - name: Invalid input
+ originalRequest:
+ method: POST
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ body:
+ mode: urlencoded
+ urlencoded:
+ - key: name
+ value: dolore magna
+ description: Updated name of the pet
+ - key: status
+ value: et incididunt
+ description: Updated status of the pet
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet that needs to be updated'
+ status: Method Not Allowed
+ code: 405
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Deletes a pet
+ request:
+ auth:
+ type: oauth2
+ oauth2:
+ - key: scope
+ value: write:pets read:pets
+ type: string
+ - key: authUrl
+ value: http://petstore.swagger.io/oauth/dialog
+ type: string
+ - key: grant_type
+ value: implicit
+ type: string
+ method: DELETE
+ header:
+ - key: api_key
+ value: dolore est
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) Pet id to delete'
+ response:
+ - name: Invalid ID supplied
+ originalRequest:
+ method: DELETE
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ - key: api_key
+ value: dolore est
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) Pet id to delete'
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Pet not found
+ originalRequest:
+ method: DELETE
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ - key: api_key
+ value: dolore est
+ url:
+ raw: '{{baseUrl}}/pet/:petId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) Pet id to delete'
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Uploads an image
+ request:
+ auth:
+ type: oauth2
+ oauth2:
+ - key: scope
+ value: write:pets read:pets
+ type: string
+ - key: authUrl
+ value: http://petstore.swagger.io/oauth/dialog
+ type: string
+ - key: grant_type
+ value: implicit
+ type: string
+ method: POST
+ header:
+ - key: Content-Type
+ value: multipart/form-data
+ - key: Accept
+ value: application/json
+ body:
+ mode: formdata
+ formdata:
+ - key: additionalMetadata
+ value: voluptate cillum
+ description: Additional data to pass to server
+ type: text
+ - key: file
+ description: file to upload
+ type: file
+ src: []
+ url:
+ raw: '{{baseUrl}}/pet/:petId/uploadImage'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ - uploadImage
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet to update'
+ response:
+ - name: successful operation
+ originalRequest:
+ method: POST
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ body:
+ mode: formdata
+ formdata:
+ - key: additionalMetadata
+ value: voluptate cillum
+ description: Additional data to pass to server
+ type: text
+ - key: file
+ description: file to upload
+ type: file
+ src: []
+ url:
+ raw: '{{baseUrl}}/pet/:petId/uploadImage'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - ':petId'
+ - uploadImage
+ variable:
+ - key: petId
+ value: '-53776022'
+ description: '(Required) ID of pet to update'
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ {
+ "code": -15164975,
+ "type": "Excepteur",
+ "message": "ut Lorem dolor officia incididunt"
+ }
+ - name: Add a new pet to the store
+ request:
+ auth:
+ type: oauth2
+ oauth2:
+ - key: scope
+ value: write:pets read:pets
+ type: string
+ - key: authUrl
+ value: http://petstore.swagger.io/oauth/dialog
+ type: string
+ - key: grant_type
+ value: implicit
+ type: string
+ method: POST
+ header:
+ - key: Content-Type
+ value: application/json
+ body:
+ mode: raw
+ raw: |-
+ {
+ "name": "doggie",
+ "photoUrls": [
+ "https://example.com/photo.png",
+ "https://example.com/photo.png"
+ ],
+ "category": {
+ "id": -98206889,
+ "name": "ut"
+ },
+ "tags": [
+ {
+ "id": -66696067,
+ "name": "laboris dolore pariatur qui"
+ },
+ {
+ "id": -22260355,
+ "name": "qui reprehenderit aliqua sint velit"
+ }
+ ],
+ "status": "available"
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/pet'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ response:
+ - name: Invalid input
+ originalRequest:
+ method: POST
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ status: Method Not Allowed
+ code: 405
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Update an existing pet
+ request:
+ auth:
+ type: oauth2
+ oauth2:
+ - key: scope
+ value: write:pets read:pets
+ type: string
+ - key: authUrl
+ value: http://petstore.swagger.io/oauth/dialog
+ type: string
+ - key: grant_type
+ value: implicit
+ type: string
+ method: PUT
+ header:
+ - key: Content-Type
+ value: application/json
+ body:
+ mode: raw
+ raw: |-
+ {
+ "name": "doggie",
+ "photoUrls": [
+ "https://example.com/photo.png",
+ "https://example.com/photo.png"
+ ],
+ "category": {
+ "id": 45108667,
+ "name": "elit"
+ },
+ "tags": [
+ {
+ "id": -90871361,
+ "name": "tempor ullamco"
+ },
+ {
+ "id": 41541088,
+ "name": "commodo irure in dolor fugiat"
+ }
+ ],
+ "status": "sold"
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/pet'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ response:
+ - name: Invalid ID supplied
+ originalRequest:
+ method: PUT
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Pet not found
+ originalRequest:
+ method: PUT
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Validation exception
+ originalRequest:
+ method: PUT
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ status: Method Not Allowed
+ code: 405
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Finds Pets by status
+ request:
+ auth:
+ type: oauth2
+ oauth2:
+ - key: scope
+ value: write:pets read:pets
+ type: string
+ - key: authUrl
+ value: http://petstore.swagger.io/oauth/dialog
+ type: string
+ - key: grant_type
+ value: implicit
+ type: string
+ method: GET
+ header:
+ - key: Accept
+ value: application/xml
+ url:
+ raw: '{{baseUrl}}/pet/findByStatus?status=available&status=available'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - findByStatus
+ query:
+ - key: status
+ value: available
+ description: '(Required) Status values that need to be considered for filter'
+ - key: status
+ value: available
+ description: '(Required) Status values that need to be considered for filter'
+ description: Multiple status values can be provided with comma separated strings
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/findByStatus?status=available&status=available'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - findByStatus
+ query:
+ - key: status
+ value: available
+ - key: status
+ value: available
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ [
+ {
+ "name": "doggie",
+ "photoUrls": [
+ "https://example.com/photo.png",
+ "https://example.com/photo.png"
+ ],
+ "id": 25,
+ "category": {
+ "id": -10731015,
+ "name": "consectetur proident"
+ },
+ "tags": [
+ {
+ "id": -87509155,
+ "name": "dolor nulla Ut"
+ },
+ {
+ "id": -19458248,
+ "name": "elit"
+ }
+ ],
+ "status": "pending"
+ },
+ {
+ "name": "doggie",
+ "photoUrls": [
+ "https://example.com/photo.png",
+ "https://example.com/photo.png"
+ ],
+ "id": 25,
+ "category": {
+ "id": 38511362,
+ "name": "a"
+ },
+ "tags": [
+ {
+ "id": 26246913,
+ "name": "pariatur"
+ },
+ {
+ "id": 65442833,
+ "name": "dolor irure consectetur"
+ }
+ ],
+ "status": "pending"
+ }
+ ]
+ - name: Invalid status value
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/findByStatus?status=available&status=available'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - findByStatus
+ query:
+ - key: status
+ value: available
+ - key: status
+ value: available
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Finds Pets by tags
+ request:
+ auth:
+ type: oauth2
+ oauth2:
+ - key: scope
+ value: write:pets read:pets
+ type: string
+ - key: authUrl
+ value: http://petstore.swagger.io/oauth/dialog
+ type: string
+ - key: grant_type
+ value: implicit
+ type: string
+ method: GET
+ header:
+ - key: Accept
+ value: application/xml
+ url:
+ raw: '{{baseUrl}}/pet/findByTags?tags=enim nostrud consequat&tags=culpa quis
+ dolor laboris'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - findByTags
+ query:
+ - key: tags
+ value: enim nostrud consequat
+ description: '(Required) Tags to filter by'
+ - key: tags
+ value: culpa quis dolor laboris
+ description: '(Required) Tags to filter by'
+ description: Muliple tags can be provided with comma separated strings. Use
+ tag1, tag2, tag3 for testing.
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/findByTags?tags=sed occaecat anim veniam ex&tags=anim
+ reprehenderit magna'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - findByTags
+ query:
+ - key: tags
+ value: sed occaecat anim veniam ex
+ - key: tags
+ value: anim reprehenderit magna
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ [
+ {
+ "name": "doggie",
+ "photoUrls": [
+ "https://example.com/photo.png",
+ "https://example.com/photo.png"
+ ],
+ "id": 25,
+ "category": {
+ "id": -10731015,
+ "name": "consectetur proident"
+ },
+ "tags": [
+ {
+ "id": -87509155,
+ "name": "dolor nulla Ut"
+ },
+ {
+ "id": -19458248,
+ "name": "elit"
+ }
+ ],
+ "status": "pending"
+ },
+ {
+ "name": "doggie",
+ "photoUrls": [
+ "https://example.com/photo.png",
+ "https://example.com/photo.png"
+ ],
+ "id": 25,
+ "category": {
+ "id": 38511362,
+ "name": "a"
+ },
+ "tags": [
+ {
+ "id": 26246913,
+ "name": "pariatur"
+ },
+ {
+ "id": 65442833,
+ "name": "dolor irure consectetur"
+ }
+ ],
+ "status": "pending"
+ }
+ ]
+ - name: Invalid tag value
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: oauth2'
+ key: Authorization
+ value: ''
+ url:
+ raw: '{{baseUrl}}/pet/findByTags?tags=sed occaecat anim veniam ex&tags=anim
+ reprehenderit magna'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - pet
+ - findByTags
+ query:
+ - key: tags
+ value: sed occaecat anim veniam ex
+ - key: tags
+ value: anim reprehenderit magna
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: store
+ item:
+ - name: order
+ item:
+ - name: '{order Id}'
+ item:
+ - name: Find purchase order by ID
+ request:
+ method: GET
+ header:
+ - key: Accept
+ value: application/xml
+ url:
+ raw: '{{baseUrl}}/store/order/:orderId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ - ':orderId'
+ variable:
+ - key: orderId
+ value: '7'
+ description: '(Required) ID of pet that needs to be fetched'
+ description: For valid response try integer IDs with value >= 1 and <= 10.
+ Other values will generated exceptions
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/store/order/:orderId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ - ':orderId'
+ variable:
+ - key: orderId
+ value: '7'
+ description: '(Required) ID of pet that needs to be fetched'
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ {
+ "id": -15329310,
+ "petId": -50620843,
+ "quantity": 78361352,
+ "shipDate": "2018-08-08T02:36:45.934Z",
+ "status": "delivered",
+ "complete": false
+ }
+ - name: Invalid ID supplied
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/store/order/:orderId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ - ':orderId'
+ variable:
+ - key: orderId
+ value: '7'
+ description: '(Required) ID of pet that needs to be fetched'
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Order not found
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/store/order/:orderId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ - ':orderId'
+ variable:
+ - key: orderId
+ value: '7'
+ description: '(Required) ID of pet that needs to be fetched'
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Delete purchase order by ID
+ request:
+ method: DELETE
+ header: []
+ url:
+ raw: '{{baseUrl}}/store/order/:orderId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ - ':orderId'
+ variable:
+ - key: orderId
+ value: '32526146'
+ description: '(Required) ID of the order that needs to be deleted'
+ description: For valid response try integer IDs with positive integer value.
+ Negative or non-integer values will generate API errors
+ response:
+ - name: Invalid ID supplied
+ originalRequest:
+ method: DELETE
+ header: []
+ url:
+ raw: '{{baseUrl}}/store/order/:orderId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ - ':orderId'
+ variable:
+ - key: orderId
+ value: '32526146'
+ description: '(Required) ID of the order that needs to be deleted'
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Order not found
+ originalRequest:
+ method: DELETE
+ header: []
+ url:
+ raw: '{{baseUrl}}/store/order/:orderId'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ - ':orderId'
+ variable:
+ - key: orderId
+ value: '32526146'
+ description: '(Required) ID of the order that needs to be deleted'
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Place an order for a pet
+ request:
+ method: POST
+ header:
+ - key: Content-Type
+ value: application/json
+ - key: Accept
+ value: application/xml
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -15329310,
+ "petId": -50620843,
+ "quantity": 78361352,
+ "shipDate": "2018-08-08T02:36:45.934Z",
+ "status": "delivered",
+ "complete": false
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/store/order'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ response:
+ - name: successful operation
+ originalRequest:
+ method: POST
+ header: []
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -15329310,
+ "petId": -50620843,
+ "quantity": 78361352,
+ "shipDate": "2018-08-08T02:36:45.934Z",
+ "status": "delivered",
+ "complete": false
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/store/order'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ {
+ "id": -15329310,
+ "petId": -50620843,
+ "quantity": 78361352,
+ "shipDate": "2018-08-08T02:36:45.934Z",
+ "status": "delivered",
+ "complete": false
+ }
+ - name: Invalid Order
+ originalRequest:
+ method: POST
+ header: []
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -15329310,
+ "petId": -50620843,
+ "quantity": 78361352,
+ "shipDate": "2018-08-08T02:36:45.934Z",
+ "status": "delivered",
+ "complete": false
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/store/order'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - order
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Returns pet inventories by status
+ request:
+ auth:
+ type: apikey
+ apikey:
+ - key: key
+ value: api_key
+ type: string
+ - key: value
+ value: ''
+ type: string
+ - key: in
+ value: header
+ type: string
+ method: GET
+ header:
+ - key: Accept
+ value: application/json
+ url:
+ raw: '{{baseUrl}}/store/inventory'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - inventory
+ description: Returns a map of status codes to quantities
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header:
+ - description: 'Added as a part of security scheme: apikey'
+ key: api_key
+ value: ''
+ url:
+ raw: '{{baseUrl}}/store/inventory'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - store
+ - inventory
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ {
+ "dolor_4": -59651882,
+ "dolor__10": 76938793
+ }
+ - name: user
+ item:
+ - name: '{username}'
+ item:
+ - name: Get user by user name
+ request:
+ method: GET
+ header:
+ - key: Accept
+ value: application/xml
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) The name that needs to be fetched. Use user1
+ for testing. '
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) The name that needs to be fetched. Use user1
+ for testing. '
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: |-
+ {
+ "id": -70409270,
+ "username": "do ea nisi",
+ "firstName": "occaecat dolor in dolore",
+ "lastName": "laborum sit ullamco",
+ "email": "nostrud Ut",
+ "password": "officia occaecat enim l",
+ "phone": "in elit officia sint",
+ "userStatus": 86291576
+ }
+ - name: Invalid username supplied
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) The name that needs to be fetched. Use user1
+ for testing. '
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: User not found
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) The name that needs to be fetched. Use user1
+ for testing. '
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Updated user
+ request:
+ method: PUT
+ header:
+ - key: Content-Type
+ value: application/json
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -70409270,
+ "username": "do ea nisi",
+ "firstName": "occaecat dolor in dolore",
+ "lastName": "laborum sit ullamco",
+ "email": "nostrud Ut",
+ "password": "officia occaecat enim l",
+ "phone": "in elit officia sint",
+ "userStatus": 86291576
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) name that need to be updated'
+ description: This can only be done by the logged in user.
+ response:
+ - name: Invalid user supplied
+ originalRequest:
+ method: PUT
+ header: []
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -70409270,
+ "username": "do ea nisi",
+ "firstName": "occaecat dolor in dolore",
+ "lastName": "laborum sit ullamco",
+ "email": "nostrud Ut",
+ "password": "officia occaecat enim l",
+ "phone": "in elit officia sint",
+ "userStatus": 86291576
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) name that need to be updated'
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: User not found
+ originalRequest:
+ method: PUT
+ header: []
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -70409270,
+ "username": "do ea nisi",
+ "firstName": "occaecat dolor in dolore",
+ "lastName": "laborum sit ullamco",
+ "email": "nostrud Ut",
+ "password": "officia occaecat enim l",
+ "phone": "in elit officia sint",
+ "userStatus": 86291576
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) name that need to be updated'
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Delete user
+ request:
+ method: DELETE
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) The name that needs to be deleted'
+ description: This can only be done by the logged in user.
+ response:
+ - name: Invalid username supplied
+ originalRequest:
+ method: DELETE
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) The name that needs to be deleted'
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: User not found
+ originalRequest:
+ method: DELETE
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/:username'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - ':username'
+ variable:
+ - key: username
+ value: dolore est
+ description: '(Required) The name that needs to be deleted'
+ status: Not Found
+ code: 404
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Create user
+ request:
+ method: POST
+ header:
+ - key: Content-Type
+ value: application/json
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -70409270,
+ "username": "do ea nisi",
+ "firstName": "occaecat dolor in dolore",
+ "lastName": "laborum sit ullamco",
+ "email": "nostrud Ut",
+ "password": "officia occaecat enim l",
+ "phone": "in elit officia sint",
+ "userStatus": 86291576
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/user'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ description: This can only be done by the logged in user.
+ response:
+ - name: successful operation
+ originalRequest:
+ method: POST
+ header: []
+ body:
+ mode: raw
+ raw: |-
+ {
+ "id": -70409270,
+ "username": "do ea nisi",
+ "firstName": "occaecat dolor in dolore",
+ "lastName": "laborum sit ullamco",
+ "email": "nostrud Ut",
+ "password": "officia occaecat enim l",
+ "phone": "in elit officia sint",
+ "userStatus": 86291576
+ }
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/user'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ status: Internal Server Error
+ code: 500
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Creates list of users with given input array
+ request:
+ method: POST
+ header:
+ - key: Content-Type
+ value: application/json
+ body:
+ mode: raw
+ raw: |-
+ [
+ {
+ "id": -95496632,
+ "username": "reprehenderit Duis",
+ "firstName": "ipsum enim",
+ "lastName": "sit incididunt quis su",
+ "email": "esse in nostrud",
+ "password": "dolore",
+ "phone": "ea tempor sed eiusmod",
+ "userStatus": 23456761
+ },
+ {
+ "id": -17610454,
+ "username": "occaecat in laboris voluptate",
+ "firstName": "consectetur fugiat",
+ "lastName": "est consectet",
+ "email": "ea qui",
+ "password": "dolor aliquip",
+ "phone": "nulla eu veniam",
+ "userStatus": -56036685
+ }
+ ]
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/user/createWithArray'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - createWithArray
+ response:
+ - name: successful operation
+ originalRequest:
+ method: POST
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/createWithArray'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - createWithArray
+ status: Internal Server Error
+ code: 500
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Creates list of users with given input array
+ request:
+ method: POST
+ header:
+ - key: Content-Type
+ value: application/json
+ body:
+ mode: raw
+ raw: |-
+ [
+ {
+ "id": -17453134,
+ "username": "est veniam proident",
+ "firstName": "adipisic",
+ "lastName": "ea nisi ut anim",
+ "email": "culpa voluptate laborum ut",
+ "password": "veniam id enim voluptate",
+ "phone": "enim sed",
+ "userStatus": 31329378
+ },
+ {
+ "id": -97425969,
+ "username": "velit sint ea ad reprehend",
+ "firstName": "reprehenderit do aliquip",
+ "lastName": "anim mollit",
+ "email": "minim qui laborum in",
+ "password": "exercitation quis",
+ "phone": "irure",
+ "userStatus": -62781043
+ }
+ ]
+ options:
+ raw:
+ language: json
+ url:
+ raw: '{{baseUrl}}/user/createWithList'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - createWithList
+ response:
+ - name: successful operation
+ originalRequest:
+ method: POST
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/createWithList'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - createWithList
+ status: Internal Server Error
+ code: 500
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Logs user into the system
+ request:
+ method: GET
+ header:
+ - key: Accept
+ value: application/xml
+ url:
+ raw: '{{baseUrl}}/user/login?username=dolore est&password=dolore est'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - login
+ query:
+ - key: username
+ value: dolore est
+ description: '(Required) The user name for login'
+ - key: password
+ value: dolore est
+ description: '(Required) The password for login in clear text'
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/login?username=dolore est&password=dolore est'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - login
+ query:
+ - key: username
+ value: dolore est
+ - key: password
+ value: dolore est
+ status: OK
+ code: 200
+ _postman_previewlanguage: json
+ header:
+ - key: X-Rate-Limit
+ value: '-71676539'
+ description: calls per hour allowed by the user
+ - key: X-Expires-After
+ value: '1966-01-28T06:32:02.771Z'
+ description: date in UTC when token expires
+ - key: Content-Type
+ value: application/json
+ cookie: []
+ body: '"dolore est"'
+ - name: Invalid username/password supplied
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/login?username=dolore est&password=dolore est'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - login
+ query:
+ - key: username
+ value: dolore est
+ - key: password
+ value: dolore est
+ status: Bad Request
+ code: 400
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+ - name: Logs out current logged in user session
+ request:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/logout'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - logout
+ response:
+ - name: successful operation
+ originalRequest:
+ method: GET
+ header: []
+ url:
+ raw: '{{baseUrl}}/user/logout'
+ host:
+ - '{{baseUrl}}'
+ path:
+ - user
+ - logout
+ status: Internal Server Error
+ code: 500
+ _postman_previewlanguage: text
+ header:
+ - key: Content-Type
+ value: text/plain
+ cookie: []
+ body: ''
+variable:
+ - key: baseUrl
+ value: http://petstore.swagger.io/v2
+ type: string
diff --git a/packages/oas-normalize/test/__snapshots__/index.test.ts.snap b/packages/oas-normalize/test/__snapshots__/index.test.ts.snap
index 8075a6d6..2e2e3dc1 100644
--- a/packages/oas-normalize/test/__snapshots__/index.test.ts.snap
+++ b/packages/oas-normalize/test/__snapshots__/index.test.ts.snap
@@ -1,6 +1,6 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`#validate > OpenAPI 3.0 support > should validate a JSON path as expected 1`] = `
+exports[`#convert > OpenAPI 3.0 support > should validate a JSON path as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -1072,7 +1072,7 @@ exports[`#validate > OpenAPI 3.0 support > should validate a JSON path as expect
}
`;
-exports[`#validate > OpenAPI 3.0 support > should validate a URL hosting JSON as expected 1`] = `
+exports[`#convert > OpenAPI 3.0 support > should validate a URL hosting JSON as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -2144,7 +2144,7 @@ exports[`#validate > OpenAPI 3.0 support > should validate a URL hosting JSON as
}
`;
-exports[`#validate > OpenAPI 3.0 support > should validate a URL hosting YAML as expected 1`] = `
+exports[`#convert > OpenAPI 3.0 support > should validate a URL hosting YAML as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -3216,7 +3216,7 @@ exports[`#validate > OpenAPI 3.0 support > should validate a URL hosting YAML as
}
`;
-exports[`#validate > OpenAPI 3.0 support > should validate a YAML path as expected 1`] = `
+exports[`#convert > OpenAPI 3.0 support > should validate a YAML path as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -4288,7 +4288,7 @@ exports[`#validate > OpenAPI 3.0 support > should validate a YAML path as expect
}
`;
-exports[`#validate > OpenAPI 3.1 support > should validate a JSON path as expected 1`] = `
+exports[`#convert > OpenAPI 3.1 support > should validate a JSON path as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -5355,7 +5355,7 @@ exports[`#validate > OpenAPI 3.1 support > should validate a JSON path as expect
}
`;
-exports[`#validate > OpenAPI 3.1 support > should validate a URL hosting JSON as expected 1`] = `
+exports[`#convert > OpenAPI 3.1 support > should validate a URL hosting JSON as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -6422,7 +6422,7 @@ exports[`#validate > OpenAPI 3.1 support > should validate a URL hosting JSON as
}
`;
-exports[`#validate > OpenAPI 3.1 support > should validate a URL hosting YAML as expected 1`] = `
+exports[`#convert > OpenAPI 3.1 support > should validate a URL hosting YAML as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -7489,7 +7489,7 @@ exports[`#validate > OpenAPI 3.1 support > should validate a URL hosting YAML as
}
`;
-exports[`#validate > OpenAPI 3.1 support > should validate a YAML path as expected 1`] = `
+exports[`#convert > OpenAPI 3.1 support > should validate a YAML path as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -8556,7 +8556,7 @@ exports[`#validate > OpenAPI 3.1 support > should validate a YAML path as expect
}
`;
-exports[`#validate > Postman support > should support converting a Postman collection to OpenAPI (validating it in the process) 1`] = `
+exports[`#convert > Postman support > should support converting a Postman collection to OpenAPI (validating it in the process) 1`] = `
{
"components": {
"securitySchemes": {
@@ -10252,7 +10252,7 @@ Contact Support:
}
`;
-exports[`#validate > Swagger 2.0 support > should validate a JSON path as expected 1`] = `
+exports[`#convert > Swagger 2.0 support > should validate a JSON path as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -11317,7 +11317,7 @@ exports[`#validate > Swagger 2.0 support > should validate a JSON path as expect
}
`;
-exports[`#validate > Swagger 2.0 support > should validate a URL hosting JSON as expected 1`] = `
+exports[`#convert > Swagger 2.0 support > should validate a URL hosting JSON as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -12382,7 +12382,7 @@ exports[`#validate > Swagger 2.0 support > should validate a URL hosting JSON as
}
`;
-exports[`#validate > Swagger 2.0 support > should validate a URL hosting YAML as expected 1`] = `
+exports[`#convert > Swagger 2.0 support > should validate a URL hosting YAML as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -13447,7 +13447,7 @@ exports[`#validate > Swagger 2.0 support > should validate a URL hosting YAML as
}
`;
-exports[`#validate > Swagger 2.0 support > should validate a YAML path as expected 1`] = `
+exports[`#convert > Swagger 2.0 support > should validate a YAML path as expected 1`] = `
{
"components": {
"requestBodies": {
@@ -14513,7 +14513,7 @@ exports[`#validate > Swagger 2.0 support > should validate a YAML path as expect
`;
exports[`#validate > should error out, and show all errors, when a definition has lots of problems 1`] = `
-[SyntaxError: OpenAPI schema validation failed.
+"OpenAPI schema validation failed.
REQUIRED must have required property 'url'
@@ -14533,5 +14533,38 @@ ADDITIONAL PROPERTY must NOT have additional properties
| ^^^^^^^ 😲 tagss is not expected to be here!
27 | "pet"
28 | ],
- 29 | "summary": "Finds Pets by status",]
+ 29 | "summary": "Finds Pets by status","
+`;
+
+exports[`#validate > should error out, and show all errors, when a definition has lots of problems 2`] = `
+[
+ {
+ "instancePath": "/servers/0",
+ "keyword": "required",
+ "message": "must have required property 'url'",
+ "params": {
+ "missingProperty": "url",
+ },
+ "schemaPath": "#/required",
+ },
+ {
+ "instancePath": "/servers/0",
+ "keyword": "additionalProperties",
+ "message": "must NOT have additional properties",
+ "params": {
+ "additionalProperty": "urll",
+ },
+ "schemaPath": "#/additionalProperties",
+ },
+ {
+ "instancePath": "/paths/~1pet~1findByStatus/get",
+ "isIdentifierLocation": true,
+ "keyword": "additionalProperties",
+ "message": "must NOT have additional properties",
+ "params": {
+ "additionalProperty": "tagss",
+ },
+ "schemaPath": "#/additionalProperties",
+ },
+]
`;
diff --git a/packages/oas-normalize/test/benchmarks/convert.bench.ts b/packages/oas-normalize/test/benchmarks/convert.bench.ts
new file mode 100644
index 00000000..82f77039
--- /dev/null
+++ b/packages/oas-normalize/test/benchmarks/convert.bench.ts
@@ -0,0 +1,60 @@
+/* eslint-disable unicorn/prefer-module */
+/* eslint-disable vitest/consistent-test-it */
+import fs from 'node:fs/promises';
+
+import swaggerJSON from '@readme/oas-examples/2.0/json/petstore.json';
+import petstore30JSON from '@readme/oas-examples/3.0/json/petstore.json';
+import petstore31JSON from '@readme/oas-examples/3.1/json/petstore.json';
+import { bench, describe } from 'vitest';
+
+import OASNormalize from '../../src/index.js';
+import postmanJSON from '../__fixtures__/postman/petstore.collection.json';
+
+describe('JSON', () => {
+ bench('OpenAPI 3.1', async () => {
+ const normalized = new OASNormalize(JSON.stringify(petstore30JSON));
+ await normalized.convert();
+ });
+
+ bench('OpenAPI 3.0', async () => {
+ const normalized = new OASNormalize(JSON.stringify(petstore31JSON));
+ await normalized.convert();
+ });
+
+ bench('Swagger 2.0', async () => {
+ const normalized = new OASNormalize(JSON.stringify(swaggerJSON));
+ await normalized.convert();
+ });
+
+ bench('Postman', async () => {
+ const normalized = new OASNormalize(JSON.stringify(postmanJSON));
+ await normalized.convert();
+ });
+});
+
+describe('YAML', async () => {
+ const swaggerYAML = await fs.readFile(require.resolve('@readme/oas-examples/2.0/yaml/petstore.yaml'), 'utf8');
+ const petstore30YAML = await fs.readFile(require.resolve('@readme/oas-examples/3.0/yaml/petstore.yaml'), 'utf8');
+ const petstore31YAML = await fs.readFile(require.resolve('@readme/oas-examples/3.1/yaml/petstore.yaml'), 'utf8');
+ const postmanYAML = await fs.readFile(require.resolve('../__fixtures__/postman/petstore.collection.yaml'), 'utf8');
+
+ bench('OpenAPI 3.1', async () => {
+ const normalized = new OASNormalize(petstore31YAML);
+ await normalized.convert();
+ });
+
+ bench('OpenAPI 3.0', async () => {
+ const normalized = new OASNormalize(petstore30YAML);
+ await normalized.convert();
+ });
+
+ bench('Swagger 2.0', async () => {
+ const normalized = new OASNormalize(swaggerYAML);
+ await normalized.convert();
+ });
+
+ bench('Postman', async () => {
+ const normalized = new OASNormalize(postmanYAML);
+ await normalized.convert();
+ });
+});
diff --git a/packages/oas-normalize/test/benchmarks/validate.bench.ts b/packages/oas-normalize/test/benchmarks/validate.bench.ts
new file mode 100644
index 00000000..7c9423d7
--- /dev/null
+++ b/packages/oas-normalize/test/benchmarks/validate.bench.ts
@@ -0,0 +1,60 @@
+/* eslint-disable unicorn/prefer-module */
+/* eslint-disable vitest/consistent-test-it */
+import fs from 'node:fs/promises';
+
+import swaggerJSON from '@readme/oas-examples/2.0/json/petstore.json';
+import petstore30JSON from '@readme/oas-examples/3.0/json/petstore.json';
+import petstore31JSON from '@readme/oas-examples/3.1/json/petstore.json';
+import { bench, describe } from 'vitest';
+
+import OASNormalize from '../../src/index.js';
+import postmanJSON from '../__fixtures__/postman/petstore.collection.json';
+
+describe('JSON', () => {
+ bench('OpenAPI 3.1', async () => {
+ const normalized = new OASNormalize(JSON.stringify(petstore30JSON));
+ await normalized.validate();
+ });
+
+ bench('OpenAPI 3.0', async () => {
+ const normalized = new OASNormalize(JSON.stringify(petstore31JSON));
+ await normalized.validate();
+ });
+
+ bench('Swagger 2.0', async () => {
+ const normalized = new OASNormalize(JSON.stringify(swaggerJSON));
+ await normalized.validate();
+ });
+
+ bench('Postman', async () => {
+ const normalized = new OASNormalize(JSON.stringify(postmanJSON));
+ await normalized.validate();
+ });
+});
+
+describe('YAML', async () => {
+ const swaggerYAML = await fs.readFile(require.resolve('@readme/oas-examples/2.0/yaml/petstore.yaml'), 'utf8');
+ const petstore30YAML = await fs.readFile(require.resolve('@readme/oas-examples/3.0/yaml/petstore.yaml'), 'utf8');
+ const petstore31YAML = await fs.readFile(require.resolve('@readme/oas-examples/3.1/yaml/petstore.yaml'), 'utf8');
+ const postmanYAML = await fs.readFile(require.resolve('../__fixtures__/postman/petstore.collection.yaml'), 'utf8');
+
+ bench('OpenAPI 3.1', async () => {
+ const normalized = new OASNormalize(petstore31YAML);
+ await normalized.validate();
+ });
+
+ bench('OpenAPI 3.0', async () => {
+ const normalized = new OASNormalize(petstore30YAML);
+ await normalized.validate();
+ });
+
+ bench('Swagger 2.0', async () => {
+ const normalized = new OASNormalize(swaggerYAML);
+ await normalized.validate();
+ });
+
+ bench('Postman', async () => {
+ const normalized = new OASNormalize(postmanYAML);
+ await normalized.validate();
+ });
+});
diff --git a/packages/oas-normalize/test/index.test.ts b/packages/oas-normalize/test/index.test.ts
index c9da9c2d..2ad11ec7 100644
--- a/packages/oas-normalize/test/index.test.ts
+++ b/packages/oas-normalize/test/index.test.ts
@@ -5,7 +5,7 @@ import fs from 'node:fs';
import path from 'node:path';
import nock from 'nock';
-import { describe, afterEach, beforeAll, beforeEach, it, expect } from 'vitest';
+import { describe, afterEach, beforeAll, beforeEach, it, expect, assert } from 'vitest';
import OASNormalize from '../src/index.js';
import { getAPIDefinitionType, isAPIDefinition, isOpenAPI, isPostman, isSwagger } from '../src/lib/utils.js';
@@ -174,6 +174,67 @@ describe('#bundle', () => {
});
});
+describe('#convert', () => {
+ describe.each([
+ ['Swagger 2.0', '2.0'],
+ ['OpenAPI 3.0', '3.0'],
+ ['OpenAPI 3.1', '3.1'],
+ ])('%s support', (_, version) => {
+ it.runIf(version === '3.1')(
+ 'should not attempt to upconvert an OpenAPI definition if we dont need to',
+ async () => {
+ const webhooks = await import('@readme/oas-examples/3.1/json/webhooks.json').then(r => r.default);
+ const o = new OASNormalize(structuredClone(webhooks));
+
+ await expect(o.convert()).resolves.toStrictEqual(webhooks);
+ },
+ );
+
+ it('should validate a URL hosting JSON as expected', async () => {
+ const json = await import(`@readme/oas-examples/${version}/json/petstore.json`).then(r => r.default);
+
+ nock('http://example.com').get(`/api-${version}.json`).reply(200, structuredClone(json));
+ const o = new OASNormalize(`http://example.com/api-${version}.json`);
+
+ await expect(o.convert()).resolves.toMatchSnapshot();
+ });
+
+ it('should validate a JSON path as expected', async () => {
+ const o = new OASNormalize(require.resolve(`@readme/oas-examples/${version}/json/petstore.json`), {
+ enablePaths: true,
+ });
+
+ await expect(o.convert()).resolves.toMatchSnapshot();
+ });
+
+ it('should validate a URL hosting YAML as expected', async () => {
+ const yaml = fs.readFileSync(require.resolve(`@readme/oas-examples/${version}/yaml/petstore.yaml`), 'utf8');
+ nock('http://example.com').get(`/api-${version}.yaml`).reply(200, yaml);
+ const o = new OASNormalize(`http://example.com/api-${version}.yaml`);
+
+ await expect(o.convert()).resolves.toMatchSnapshot();
+ });
+
+ it('should validate a YAML path as expected', async () => {
+ const o = new OASNormalize(require.resolve(`@readme/oas-examples/${version}/yaml/petstore.yaml`), {
+ enablePaths: true,
+ });
+
+ await expect(o.convert()).resolves.toMatchSnapshot();
+ });
+ });
+
+ describe('Postman support', () => {
+ it('should support converting a Postman collection to OpenAPI (validating it in the process)', async () => {
+ const o = new OASNormalize(require.resolve('./__fixtures__/postman/petstore.collection.json'), {
+ enablePaths: true,
+ });
+
+ await expect(o.convert()).resolves.toMatchSnapshot();
+ });
+ });
+});
+
describe('#deref', () => {
it('should dereference a definition', async () => {
const openapi = await import('@readme/oas-examples/3.0/json/petstore.json').then(r => r.default);
@@ -222,14 +283,14 @@ describe('#validate', () => {
const swagger = await import('@readme/oas-examples/2.0/json/petstore.json').then(r => r.default);
const o = new OASNormalize(structuredClone(swagger));
- await expect(o.validate()).resolves.toStrictEqual(swagger);
+ await expect(o.validate()).resolves.toBe(true);
});
it('should not attempt to upconvert an OpenAPI definition if we dont need to', async () => {
const webhooks = await import('@readme/oas-examples/3.1/json/webhooks.json').then(r => r.default);
const o = new OASNormalize(structuredClone(webhooks));
- await expect(o.validate({ convertToLatest: true })).resolves.toStrictEqual(webhooks);
+ await expect(o.validate()).resolves.toBe(true);
});
it('should error out on a definition a missing component', async () => {
@@ -271,13 +332,22 @@ describe('#validate', () => {
);
});
+ /* eslint-disable vitest/no-conditional-expect */
it('should error out, and show all errors, when a definition has lots of problems', async () => {
const o = new OASNormalize(require.resolve('./__fixtures__/invalid/openapi-very-invalid.json'), {
enablePaths: true,
});
- await expect(o.validate()).rejects.toMatchSnapshot();
+ try {
+ await o.validate();
+ assert.fail();
+ } catch (err) {
+ expect(err).toBeInstanceOf(SyntaxError);
+ expect(err.message).toMatchSnapshot();
+ expect(err.details).toMatchSnapshot();
+ }
});
+ /* eslint-enable vitest/no-conditional-expect */
it('should error out for empty file', async () => {
const o = new OASNormalize(require.resolve('./__fixtures__/invalid/empty.json'), {
@@ -310,7 +380,7 @@ describe('#validate', () => {
nock('http://example.com').get(`/api-${version}.json`).reply(200, structuredClone(json));
const o = new OASNormalize(`http://example.com/api-${version}.json`);
- await expect(o.validate({ convertToLatest: true })).resolves.toMatchSnapshot();
+ await expect(o.validate()).resolves.toBe(true);
});
it('should validate a JSON path as expected', async () => {
@@ -318,7 +388,7 @@ describe('#validate', () => {
enablePaths: true,
});
- await expect(o.validate({ convertToLatest: true })).resolves.toMatchSnapshot();
+ await expect(o.validate()).resolves.toBe(true);
});
it('should validate a URL hosting YAML as expected', async () => {
@@ -326,7 +396,7 @@ describe('#validate', () => {
nock('http://example.com').get(`/api-${version}.yaml`).reply(200, yaml);
const o = new OASNormalize(`http://example.com/api-${version}.yaml`);
- await expect(o.validate({ convertToLatest: true })).resolves.toMatchSnapshot();
+ await expect(o.validate()).resolves.toBe(true);
});
it('should validate a YAML path as expected', async () => {
@@ -334,7 +404,7 @@ describe('#validate', () => {
enablePaths: true,
});
- await expect(o.validate({ convertToLatest: true })).resolves.toMatchSnapshot();
+ await expect(o.validate()).resolves.toBe(true);
});
});
@@ -344,7 +414,7 @@ describe('#validate', () => {
enablePaths: true,
});
- await expect(o.validate({ convertToLatest: true })).resolves.toMatchSnapshot();
+ await expect(o.validate()).resolves.toBe(true);
});
});
});
diff --git a/packages/oas/package.json b/packages/oas/package.json
index 7f31f499..a8d068b6 100644
--- a/packages/oas/package.json
+++ b/packages/oas/package.json
@@ -94,7 +94,6 @@
"jsonpath-plus": "^10.0.0",
"jsonpointer": "^5.0.0",
"memoizee": "^0.4.16",
- "oas-normalize": "file:../oas-normalize",
"openapi-types": "^12.1.1",
"path-to-regexp": "^8.1.0",
"remove-undefined-objects": "^5.0.0"
diff --git a/packages/oas/src/reducer/index.ts b/packages/oas/src/reducer/index.ts
index 5cec4cfa..0d80c430 100644
--- a/packages/oas/src/reducer/index.ts
+++ b/packages/oas/src/reducer/index.ts
@@ -1,7 +1,6 @@
import type { ComponentsObject, HttpMethods, OASDocument, TagObject } from '../types.js';
import jsonPointer from 'jsonpointer';
-import { getAPIDefinitionType } from 'oas-normalize/lib/utils';
import { query } from '../analyzer/util.js';
@@ -81,7 +80,7 @@ export default function reducer(definition: OASDocument, opts: ReducerOptions =
const $refs: Set = new Set();
const usedTags: Set = new Set();
- if (getAPIDefinitionType(definition) !== 'openapi') {
+ if (!definition.openapi) {
throw new Error('Sorry, only OpenAPI definitions are supported.');
}