├── .babelrc ├── .eslintrc.yml ├── .github ├── actions │ └── setup-js │ │ └── action.yml └── workflows │ └── test-and-deploy-docker.yml ├── .gitignore ├── .mocharc.json ├── .nvmrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── dist ├── Dockerfile ├── cli.js ├── cli.js.map ├── index.js └── index.js.map ├── etc └── src │ └── build-dockerfile.js ├── package-lock.json ├── package.json ├── src ├── application-error.js ├── cli.js ├── const │ └── result-type.js ├── impl │ ├── index.js │ ├── service │ │ ├── all-properties-required.js │ │ ├── common.js │ │ └── no-additional-properties.js │ ├── v2 │ │ └── index.js │ └── v3 │ │ └── index.js ├── index.js ├── utils │ └── index.js └── validator.js ├── stryker.conf.js ├── test ├── data │ ├── output-help.js │ ├── output │ │ ├── api-additional-properties.js │ │ ├── api-with-examples-and-additional-properties.js │ │ └── api-with-examples-and-all-properties-required.js │ ├── v2 │ │ ├── additional-properties │ │ │ ├── errors-schema-invalid-with-examples.json │ │ │ └── invalid-with-examples.yaml │ │ ├── external-examples-invalid-missing-link.json │ │ ├── external-examples-invalid-type.json │ │ ├── external-examples-schema-referencing-fraction.json │ │ ├── external-examples-schema-referencing-invalid.json │ │ ├── external-examples-schema-referencing-sub-schema.json │ │ ├── external-examples-schema-referencing-valid.json │ │ ├── external-examples-schema.json │ │ ├── external-examples-valid-example1.json │ │ ├── external-examples-valid-example2.json │ │ ├── invalid-array-response.json │ │ ├── invalid-format.json │ │ ├── invalid-type.json │ │ ├── map-external-examples-glob-invalid1.json │ │ ├── map-external-examples-glob-invalid2.json │ │ ├── map-external-examples-map-with-missing-examples.json │ │ ├── map-external-examples-map-with-wrong-schema-path.json │ │ ├── map-external-examples-relative-invalid.json │ │ ├── map-external-examples-relative.json │ │ ├── map-external-examples-with-wildcards.json │ │ ├── map-external-examples-without-wildcards.json │ │ ├── map-external-examples.json │ │ ├── multiple-errors.json │ │ ├── output-map-external-examples.js │ │ ├── output-single-external-example-valid.js │ │ ├── response-valid-content-array.yaml │ │ ├── simple-example-mime-complex.json │ │ ├── simple-example.json │ │ ├── valid-array-response.json │ │ ├── valid-multiple-examples.json │ │ ├── valid-single-example.json │ │ ├── valid-with-all-properties-required.json │ │ ├── valid-with-no-additional-properties.json │ │ ├── valid-without-examples.json │ │ └── valid-without-schema.json │ └── v3 │ │ ├── additional-properties │ │ ├── errors-list.json │ │ ├── errors-map-external-examples.json │ │ ├── errors-schema-invalid-with-examples.json │ │ ├── errors-schema-with-examples.json │ │ ├── errors-schema-with-schema-combiner-as-property.json │ │ ├── errors-single.json │ │ ├── example-list-with-additional-properties.json │ │ ├── example-single-with-additional-properties.json │ │ ├── invalid-with-examples.yaml │ │ ├── map-external-examples-with-additional-properties.json │ │ ├── schema-with-examples.yaml │ │ ├── schema-with-schema-combiner-as-property-invalid.yaml │ │ ├── schema-with-schema-combiner-invalid.yaml │ │ ├── schema-with-schema-combiner-valid.yaml │ │ ├── schema.yaml │ │ └── simple-api-with-no-additional-properties.json │ │ ├── all-properties-required │ │ ├── errors-schema-with-examples.json │ │ ├── schema-with-examples.yaml │ │ └── simple-api-with-all-properties-required.json │ │ ├── draft-04-properties │ │ └── errors-exclusive-minimum.json │ │ ├── errors │ │ └── simple-api-with-example-names-to-be-escaped.json │ │ ├── null-values │ │ └── schema-with-null-property.json │ │ ├── request-invalid-parameter-examples.json │ │ ├── request-invalid-parameter.json │ │ ├── request-invalid-requestbody-examples.json │ │ ├── request-invalid-requestbody.json │ │ ├── request-valid-parameter-examples.json │ │ ├── request-valid-parameter.json │ │ ├── request-valid-requestbody-examples-mime-complex.json │ │ ├── request-valid-requestbody-examples.json │ │ ├── request-valid-requestbody.json │ │ ├── response-invalid-date-time-format.json │ │ ├── response-invalid-non-nullable.json │ │ ├── response-invalid-number-formats.json │ │ ├── response-invalid-requestbody-inheritance-examples.json │ │ ├── response-nullable-invalid-definition.json │ │ ├── response-valid-content-array.yaml │ │ ├── response-valid-date-time-format.json │ │ ├── response-valid-nullable.json │ │ ├── response-valid-number-formats.json │ │ ├── response-valid-requestbody-inheritance-examples.json │ │ ├── simple-api-with-example-and-examples-mime-complex-invalid.json │ │ ├── simple-api-with-example-and-examples.json │ │ ├── simple-api-with-example-names-to-be-escaped.json │ │ ├── simple-api-with-example-with-refs-invalid.json │ │ ├── simple-api-with-example.json │ │ ├── simple-api-with-examples-and-missing-schema.json │ │ ├── simple-api-with-examples-exclusive-minimum-invalid.json │ │ ├── simple-api-with-examples-exclusive-minimum.json │ │ ├── simple-api-with-examples-invalid-indentation.yml │ │ ├── simple-api-with-examples-with-refs-invalid.json │ │ ├── simple-api-with-examples-with-refs-invalid.yaml │ │ ├── simple-api-with-examples-with-refs-invalid.yml │ │ ├── simple-api-with-examples-with-refs.json │ │ ├── simple-api-with-examples-with-refs.yaml │ │ ├── simple-api-with-examples-with-refs.yml │ │ ├── simple-api-with-examples.json │ │ ├── simple-api-with-request-examples.json │ │ ├── unknown-formats.json │ │ └── valid-single-with-value-property.yaml ├── specs │ ├── application-error.js │ ├── cli.js │ ├── impl │ │ ├── index.js │ │ ├── service │ │ │ └── schema-extender.js │ │ ├── v2 │ │ │ ├── index-dereferencing.js │ │ │ └── index.js │ │ └── v3 │ │ │ ├── index.js │ │ │ └── inheritance.js │ └── index.js └── util │ └── setup-tests.js └── webpack ├── config.babel.js └── constants.babel.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "16" 8 | } 9 | } 10 | ] 11 | ], 12 | "plugins": [] 13 | } 14 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | node: true 3 | es6: true 4 | mocha: true 5 | globals: {} 6 | parser: "@babel/eslint-parser" 7 | parserOptions: 8 | sourceType: module 9 | rules: 10 | array-bracket-spacing: 11 | - 2 12 | - never 13 | arrow-parens: 0 14 | block-scoped-var: 0 15 | brace-style: 16 | - 2 17 | - 1tbs 18 | - allowSingleLine: true 19 | camelcase: 20 | - 2 21 | - properties: always 22 | comma-dangle: 23 | - 2 24 | - never 25 | comma-spacing: 26 | - 2 27 | - before: false 28 | after: true 29 | comma-style: 30 | - 2 31 | - last 32 | complexity: 33 | - 2 34 | - 7 35 | curly: 36 | - 2 37 | - all 38 | dot-notation: 2 39 | eol-last: 2 40 | eqeqeq: 41 | - 2 42 | - allow-null 43 | func-names: 0 44 | func-style: 45 | - 2 46 | - declaration 47 | generator-star-spacing: 0 48 | guard-for-in: 2 49 | indent: 50 | - 2 51 | - 4 52 | - SwitchCase: 1 53 | ignoreComments: true 54 | key-spacing: 55 | - 2 56 | - beforeColon: false 57 | afterColon: true 58 | mode: minimum 59 | keyword-spacing: 60 | - 2 61 | - overrides: 62 | else: 63 | before: true 64 | while: 65 | before: true 66 | catch: 67 | before: true 68 | linebreak-style: 69 | - 2 70 | - unix 71 | max-depth: 72 | - 2 73 | - 4 74 | max-len: 75 | - 2 76 | - 120 77 | - ignoreTrailingComments: true 78 | ignoreUrls: true 79 | max-params: 80 | - 2 81 | - 4 82 | new-cap: 83 | - 2 84 | - capIsNewExceptions: [] 85 | no-bitwise: 2 86 | no-caller: 2 87 | no-else-return: 2 88 | no-empty: 2 89 | no-eq-null: 0 90 | no-extra-semi: 2 91 | no-irregular-whitespace: 2 92 | no-mixed-spaces-and-tabs: 2 93 | no-multi-str: 2 94 | no-nested-ternary: 2 95 | no-new: 2 96 | no-new-func: 0 97 | no-new-wrappers: 0 98 | no-plusplus: 0 99 | no-restricted-syntax: 0 100 | no-sequences: 2 101 | no-spaced-func: 2 102 | no-trailing-spaces: 2 103 | no-undef: 2 104 | no-unused-expressions: 105 | - 2 106 | - allowShortCircuit: true 107 | allowTernary: false 108 | no-unused-vars: 109 | - 2 110 | - vars: all 111 | args: after-used 112 | no-use-before-define: 113 | - 2 114 | - nofunc 115 | no-warning-comments: 116 | - 2 117 | - terms: 118 | - 2do 119 | location: anywhere 120 | no-with: 2 121 | object-curly-spacing: 122 | - 2 123 | - always 124 | one-var: 0 125 | operator-linebreak: 126 | - 2 127 | - before 128 | padded-blocks: 129 | - 2 130 | - never 131 | quotes: 132 | - 2 133 | - single 134 | - avoidEscape: true 135 | semi: 136 | - 2 137 | - always 138 | semi-spacing: 139 | - 2 140 | - before: false 141 | after: true 142 | space-before-blocks: 143 | - 2 144 | - always 145 | space-before-function-paren: 146 | - 2 147 | - never 148 | space-in-parens: 149 | - 2 150 | - never 151 | space-unary-ops: 152 | - 2 153 | - words: false 154 | nonwords: false 155 | strict: 156 | - error 157 | - safe 158 | wrap-iife: 159 | - 2 160 | - inside 161 | -------------------------------------------------------------------------------- /.github/actions/setup-js/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Set repository up, with a NodeJS environment' 2 | description: | 3 | Checks out repository and sets NodeJS up with cached global and local dependencies 4 | inputs: 5 | node-version: 6 | description: 'NodeJS version' 7 | required: true 8 | outputs: 9 | has-local-cache: 10 | description: 'Was cache found' 11 | value: ${{ steps.restore-cached-dependencies.outputs.cache-hit }} 12 | runs: 13 | using: "composite" 14 | steps: 15 | - name: Use Node.js ${{ inputs.node-version }} 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: ${{ inputs.node-version }} 19 | - id: restore-cached-dependencies 20 | name: Restore cached dependencies 21 | uses: actions/cache@v4 22 | with: 23 | path: ./node_modules/ 24 | key: ${{ runner.os }}-install-${{ inputs.node-version }}-${{ hashFiles('**/package-lock.json') }} 25 | restore-keys: | 26 | ${{ runner.os }}-install-${{ inputs.node-version }}- 27 | ${{ runner.os }}-install- 28 | - name: Install dependencies 29 | shell: bash 30 | run: npm install 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .idea 3 | .stryker-tmp 4 | /reports 5 | /.nyc_output 6 | /coverage 7 | /node_modules 8 | /tmp -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec": ["./test/specs/**/*.js"], 3 | "require": [ 4 | "./test/util/setup-tests" 5 | ], 6 | "recursive": true 7 | } 8 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18* 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "18" 5 | - "20" 6 | - "22" 7 | - "node" 8 | 9 | before_script: 10 | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter 11 | - chmod +x ./cc-test-reporter 12 | - ./cc-test-reporter before-build 13 | 14 | script: 15 | - npm run test 16 | 17 | after_script: 18 | - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT 19 | 20 | after_success: 21 | - npm run coverage 22 | - npm run test-mutations 23 | - npm run coveralls 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Code Kie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18.16.0-alpine3.17 2 | 3 | RUN npm install -g openapi-examples-validator@6.0.3 4 | 5 | ENV NODE_OPTIONS="--unhandled-rejections=strict" 6 | ENTRYPOINT ["openapi-examples-validator"] 7 | CMD ["--help"] -------------------------------------------------------------------------------- /etc/src/build-dockerfile.js: -------------------------------------------------------------------------------- 1 | const path = require('path'), 2 | fs = require('fs'); 3 | 4 | const VERSION = require('../../package.json').version, 5 | FILE_PATH__DOCKERFILE = path.join(__dirname, '../../dist/Dockerfile'); 6 | 7 | _writeDockerfile(); 8 | 9 | function _writeDockerfile() { 10 | const dockerfile = _createDockerfile().trim(); 11 | fs.writeFileSync(FILE_PATH__DOCKERFILE, dockerfile, 'utf8'); 12 | } 13 | 14 | 15 | function _createDockerfile() { 16 | return ` 17 | FROM node:18.16.0-alpine3.17 18 | 19 | RUN npm install -g openapi-examples-validator@${ VERSION } 20 | 21 | ENV NODE_OPTIONS="--unhandled-rejections=strict" 22 | ENTRYPOINT ["openapi-examples-validator"] 23 | CMD ["--help"] 24 | `; 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openapi-examples-validator", 3 | "version": "6.0.3", 4 | "description": "Validates embedded examples in OpenAPI-JSONs", 5 | "main": "dist/index.js", 6 | "engines": { 7 | "node": ">=18" 8 | }, 9 | "bin": { 10 | "openapi-examples-validator": "dist/cli.js" 11 | }, 12 | "standard-version": { 13 | "scripts": { 14 | "postchangelog": "npm run release:create-dockerfile && npm run release:stage-artifacts" 15 | } 16 | }, 17 | "scripts": { 18 | "start-dev": "babel-node src/cli", 19 | "build": "npm run build:clean && npm run build:webpack", 20 | "build:clean": "rimraf dist", 21 | "build:webpack": "webpack --bail --progress --profile --mode production --config ./webpack/config.babel.js", 22 | "coverage": "rimraf ./coverage && nyc --reporter=lcov --reporter=text -x \"dist/**/*\" -x \"test/**/*.js\" npm test", 23 | "coveralls": "cat ./coverage/lcov.info | coveralls", 24 | "test": "npm run build && npm run test:mocha", 25 | "test-mutations": "stryker run", 26 | "test:mocha": "mocha --require \"./test/util/setup-tests\" --recursive \"./test/specs/**/*.js\"", 27 | "release": "npm run build && standard-version -a", 28 | "release:create-dockerfile": "npm run build && node etc/src/build-dockerfile.js", 29 | "release:stage-artifacts": "git add dist/*" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "git+https://github.com/codekie/openapi-examples-validator.git" 34 | }, 35 | "keywords": [ 36 | "swagger", 37 | "openapi", 38 | "json", 39 | "validate", 40 | "examples" 41 | ], 42 | "author": "Josua Amann", 43 | "license": "MIT", 44 | "bugs": { 45 | "url": "https://github.com/codekie/openapi-examples-validator/issues" 46 | }, 47 | "homepage": "https://github.com/codekie/openapi-examples-validator#readme", 48 | "devDependencies": { 49 | "@babel/cli": "^7.27.0", 50 | "@babel/core": "^7.26.10", 51 | "@babel/eslint-parser": "^7.27.0", 52 | "@babel/node": "^7.26.0", 53 | "@babel/preset-env": "^7.26.9", 54 | "@babel/register": "^7.25.9", 55 | "@stryker-mutator/core": "^8.7.1", 56 | "@stryker-mutator/mocha-runner": "^8.7.1", 57 | "babel-loader": "^9.2.1", 58 | "chai": "^4.3.6", 59 | "chai-string": "^1.6.0", 60 | "core-js-pure": "^3.41.0", 61 | "coveralls": "^3.1.1", 62 | "eslint": "^8.41.0", 63 | "eslint-webpack-plugin": "^4.2.0", 64 | "json-loader": "^0.5.7", 65 | "mocha": "^10.8.2", 66 | "mocha-lcov-reporter": "^1.3.0", 67 | "nyc": "^15.1.0", 68 | "rimraf": "^5.0.1", 69 | "standard-version": "^9.5.0", 70 | "stryker-cli": "^1.0.2", 71 | "webpack": "^5.99.5", 72 | "webpack-cli": "^5.1.4" 73 | }, 74 | "dependencies": { 75 | "ajv": "^8.17.1", 76 | "ajv-draft-04": "^1.0.0", 77 | "ajv-formats": "^2.1.1", 78 | "commander": "^6.2.1", 79 | "errno": "^1.0.0", 80 | "glob": "^8.1.0", 81 | "json-pointer": "^0.6.2", 82 | "json-schema-ref-parser": "^9.0.9", 83 | "jsonpath-plus": "^10.3.0", 84 | "lodash.clonedeep": "^4.5.0", 85 | "lodash.flatmap": "^4.5.0", 86 | "lodash.flatten": "^4.4.0", 87 | "lodash.merge": "^4.6.2", 88 | "yaml": "^2.7.1" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/application-error.js: -------------------------------------------------------------------------------- 1 | const 2 | merge = require('lodash.merge'), 3 | { ENOENT } = require('errno').code; 4 | 5 | // TYPEDEFINITIONS 6 | 7 | /** 8 | * @typedef {{}} CustomError 9 | * @augments Error 10 | */ 11 | 12 | /** 13 | * ApplicationErrorOptions 14 | * @typedef {{ 15 | * [instancePath]: string, 16 | * [examplePath]: string, 17 | * [exampleFilePath]: string, 18 | * [keyword]: string, 19 | * [message]: string, 20 | * [mapFilePath]: string, 21 | * [params]: { 22 | * [path]: string, 23 | * [missingProperty]: string, 24 | * [type]: string 25 | * }, 26 | * [schemaPath]: string 27 | * }} ApplicationErrorOptions 28 | */ 29 | 30 | // CONSTANTS 31 | 32 | const ErrorType = { 33 | jsENOENT: ENOENT.code, 34 | jsonPathNotFound: 'JsonPathNotFound', 35 | errorAndErrorsMutuallyExclusive: 'ErrorErrorsMutuallyExclusive', 36 | parseError: 'ParseError', 37 | validation: 'Validation' 38 | }; 39 | 40 | // CLASSES 41 | 42 | /** 43 | * Unified application-error 44 | */ 45 | class ApplicationError { 46 | /** 47 | * Factory-function, which is able to consume validation-errors and JS-errors. If a validation error is passed, all 48 | * properties will be adopted. 49 | * @param {Error|CustomError} err Javascript-, validation- or custom-error, to create the application-error 50 | * from 51 | * @returns {ApplicationError} Unified application-error instance 52 | */ 53 | static create(err) { 54 | const { code, message, path, cause } = err, // Certain properties of Javascript-errors 55 | type = code || err.type || ErrorType.validation, // If `code` is available then it's a Javascript-error 56 | options = { message }; 57 | if (ErrorType.validation === type || ErrorType.errorAndErrorsMutuallyExclusive === type) { 58 | // For certain, created error-types, copy all properties 59 | merge(options, err); 60 | } else { 61 | // Copy certain properties of Javascript-error (but only if available) 62 | path && merge(options, { params: { path } }); 63 | cause && merge(options, cause); 64 | } 65 | return new ApplicationError(type, options); 66 | } 67 | 68 | /** 69 | * Constructor 70 | * @param {string} type Type of error (see statics) 71 | * @param {ApplicationErrorOptions} [options] Optional properties 72 | */ 73 | constructor(type, options = {}) { 74 | Object.assign(this, { 75 | type, 76 | ...options 77 | }); 78 | } 79 | } 80 | 81 | // PUBLIC API 82 | 83 | module.exports = { 84 | ApplicationError, 85 | ErrorType 86 | }; 87 | -------------------------------------------------------------------------------- /src/cli.js: -------------------------------------------------------------------------------- 1 | // Shebang will be added by webpack 2 | //#!/usr/bin/env node --harmony 3 | 4 | /** 5 | * Command Line Interface for the validator 6 | */ 7 | 8 | const 9 | VERSION = require('../package.json').version, 10 | program = require('commander'), 11 | { validateFile, validateExample, validateExamplesByMap } = require('./index'); 12 | 13 | // FOR AUTOMATED TESTS 14 | 15 | const ENV_TEST = process.env.OPENAPI_EXAMPLES_VALIDATOR_TESTS === 'true'; 16 | 17 | // DEFINE CLI 18 | 19 | program 20 | .version(VERSION) 21 | .arguments('') 22 | .description('Validate embedded examples in OpenAPI-specs (JSON and YAML supported).\n' 23 | + ' To validate external examples, use the `-s` and `-e` option.\n' 24 | + ' To pass a mapping-file, to validate multiple external examples, use the `-m` option.') 25 | .option('-s, --schema-jsonpath ', 'Path to OpenAPI-schema, to validate the example file against') 26 | .option('-e, --example-filepath ', 'file path to example file, to be validated') 27 | .option('-m, --mapping-filepath ', 'file path to map, containing schema-paths as key and the' 28 | + ' file-path(s) to examples as value. If wildcards are used, the parameter has to be put in quotes.') 29 | .option('-c, --cwd-to-mapping-file', "changes to the directory of the mapping-file, before resolving the example's" 30 | + ' paths. Use this option, if your mapping-files use relative paths for the examples') 31 | .option('-n, --no-additional-properties', 'don\'t allow properties that are not described in the schema') 32 | .option('-r, --all-properties-required', 'make all the properties in the schema required') 33 | .option('-o, --ignore-formats ', 'Datatype formats to ignore ' 34 | + '(to prevent "unknown format" message in the error-console.)') 35 | .action(processAction); 36 | program.on('--help', () => { 37 | console.log('\n\n Example for external example-file:\n'); 38 | console.log(' $ openapi-examples-validator -s $.paths./.get.responses.200.schema -e example.json' 39 | + ' openapi-spec.json\n\n'); 40 | }); 41 | // Execute and export promise (for automated tests) 42 | module.exports = program.parseAsync(process.argv); 43 | 44 | // IMPLEMENTATION DETAILS 45 | 46 | async function processAction(filepath, options) { 47 | const { schemaJsonpath, exampleFilepath, mappingFilepath, cwdToMappingFile, allPropertiesRequired } = options, 48 | noAdditionalProperties = !options.additionalProperties, 49 | ignoreFormats = _prepareIgnoreFormats(options.ignoreFormats); 50 | let result; 51 | if (mappingFilepath) { 52 | console.log('Validating with mapping file'); 53 | result = await validateExamplesByMap(filepath, mappingFilepath, { 54 | cwdToMappingFile, 55 | noAdditionalProperties, 56 | ignoreFormats, 57 | allPropertiesRequired 58 | }); 59 | } else if (schemaJsonpath && exampleFilepath) { 60 | console.log('Validating single external example'); 61 | result = await validateExample(filepath, schemaJsonpath, exampleFilepath, { 62 | noAdditionalProperties, 63 | ignoreFormats, 64 | allPropertiesRequired 65 | }); 66 | } else { 67 | console.log('Validating examples'); 68 | result = await validateFile(filepath, { 69 | noAdditionalProperties, 70 | ignoreFormats, 71 | allPropertiesRequired 72 | }); 73 | } 74 | _handleResult(result); 75 | } 76 | 77 | function _handleResult(result) { 78 | const noExit = ENV_TEST; 79 | _printStatistics(result.statistics); 80 | if (result.valid) { 81 | process.stdout.write('\nNo errors found.\n\n'); 82 | !noExit && process.exit(0); 83 | return; 84 | } 85 | process.stdout.write('\nErrors found.\n\n'); 86 | process.stderr.write(JSON.stringify(result.errors, null, ' ')); 87 | !noExit && process.exit(1); 88 | } 89 | 90 | function _printStatistics(statistics) { 91 | const { 92 | schemasWithExamples, 93 | examplesWithoutSchema, 94 | examplesTotal, 95 | matchingFilePathsMapping 96 | } = statistics, 97 | strStatistics = [ 98 | `Schemas with examples found: ${ schemasWithExamples }`, 99 | `Examples without schema found: ${ examplesWithoutSchema }`, 100 | `Total examples found: ${ examplesTotal }` 101 | ]; 102 | if (matchingFilePathsMapping != null) { 103 | strStatistics.push(`Matching mapping files found: ${ matchingFilePathsMapping }`); 104 | } 105 | process.stdout.write(`${ strStatistics.join('\n') }\n`); 106 | } 107 | 108 | function _prepareIgnoreFormats(ignoreFormats) { 109 | if (ignoreFormats == null || !Array.isArray(ignoreFormats)) { return ignoreFormats; } 110 | if (ignoreFormats.length !== 1) { return ignoreFormats; } 111 | // If only one argument has been passed, with all formats separated by newlines 112 | if (ignoreFormats[0].indexOf('\n') === -1) { return ignoreFormats; } 113 | return ignoreFormats[0].split('\n').filter(entry => !entry.match(/^\s*$/)); 114 | } 115 | -------------------------------------------------------------------------------- /src/const/result-type.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parent: 'parent', 3 | parentProperty: 'parentProperty', 4 | path: 'path', 5 | pointer: 'pointer', 6 | value: 'value' 7 | }; 8 | -------------------------------------------------------------------------------- /src/impl/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Entry point for logic that only applies to specific versions of the OpenAPI-spec 3 | */ 4 | 5 | const implV2 = require('./v2/index'), 6 | implV3 = require('./v3/index'); 7 | 8 | const REGEX__OPEN_API = /^3\./; 9 | 10 | module.exports = { 11 | getImplementation 12 | }; 13 | 14 | /** 15 | * Get the version-specific implementation for the OpenAPI-spec. Currently v2 and v3 are supported 16 | * @param {Object} openapiSpec OpenAPI-spec 17 | * @returns {Object|null} 18 | */ 19 | function getImplementation(openapiSpec) { 20 | if (typeof openapiSpec.swagger === 'string') { 21 | return implV2; 22 | } 23 | if (openapiSpec.openapi && openapiSpec.openapi.match(REGEX__OPEN_API)) { 24 | return implV3; 25 | } 26 | return null; 27 | } 28 | -------------------------------------------------------------------------------- /src/impl/service/all-properties-required.js: -------------------------------------------------------------------------------- 1 | const { applyCallbackToAllObjectModels } = require('./common'); 2 | 3 | module.exports = { 4 | setAllPropertiesRequired 5 | }; 6 | 7 | /** 8 | * Sets all properties of each object to required 9 | * @param {Object} openApiSpec The to-be-modified schema 10 | * @param {Array.} [examplePaths=[]] The paths to the examples, which's content must not be modified 11 | */ 12 | function setAllPropertiesRequired(openApiSpec, examplePaths = []) { 13 | applyCallbackToAllObjectModels(openApiSpec, examplePaths, 14 | () => { 15 | return (value) => { 16 | if (value.hasOwnProperty('properties')) { 17 | value.required = Object.keys(value.properties); 18 | } 19 | }; 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /src/impl/service/common.js: -------------------------------------------------------------------------------- 1 | const { JSONPath: jsonPath } = require('jsonpath-plus'), 2 | ResultType = require('../../const/result-type'); 3 | 4 | module.exports = { 5 | applyCallbackToAllObjectModels 6 | }; 7 | 8 | /** 9 | * @typedef {{ 10 | * path: String, 11 | * value: Object, 12 | * parent: Object, 13 | * parentProperty: String, 14 | * hasArrExpr: Boolean 15 | * }} JsonPathMatchData 16 | */ 17 | 18 | /** 19 | * Callback that is applied to a JSONPath-match. 20 | * @callback JsonPathMatchCallback 21 | * @param {Object} value Value of the matched property 22 | * @param {String} resultType Result-type of the query 23 | * @param {JsonPathMatchData} data Object that contains additional data to the match 24 | */ 25 | 26 | /** 27 | * Function to build a callback that is applied to a JSONPath-match. 28 | * @callback JsonPathMatchCallbackBuilder 29 | * @param {string} jsPath Path to the property that matched 30 | * @return {JsonPathMatchCallback} Callback that is applied to a JSONPath-match 31 | */ 32 | 33 | /** 34 | * Apply the input rule to all models of type object in the input openApiSpec 35 | * @param {Object} openApiSpec The to-be-modified schema 36 | * @param {Array.} [examplePaths] The paths to the examples, which's content must not be modified 37 | * @param {JsonPathMatchCallbackBuilder} [matchCallbackBuilder] Function to build a callback 38 | * that will be called on each match 39 | */ 40 | function applyCallbackToAllObjectModels(openApiSpec, examplePaths, matchCallbackBuilder) { 41 | // Find all matches 42 | const paths = new Set(); 43 | _find(openApiSpec, '$..schema..') 44 | .forEach(match => { 45 | if (_isPropertiesDefinition(match)) { return; } 46 | paths.add(match); 47 | }); 48 | // Exclude examples 49 | _excludeExamples(openApiSpec, paths, examplePaths); 50 | // Set flag 51 | for (const jsPath of paths) { 52 | const callback = matchCallbackBuilder(jsPath); 53 | _find(openApiSpec, jsPath, ResultType.value, (result, resultType, data) => { 54 | if (!_isObjectDefinition(result)) { return; } 55 | callback(result, resultType, data); 56 | }); 57 | } 58 | } 59 | 60 | /** 61 | * Find matching elements in JSON. 62 | * @param {Object} json JSON to be searched 63 | * @param {String} path JSON-path to search 64 | * @param {String} [resultType="path"] Result-type of the query 65 | * @param {JsonPathMatchCallback} [callback] Function to be called on a match 66 | * @returns {any} Result of the query, depending on the `resultType` 67 | * @private 68 | */ 69 | function _find(json, path, resultType = ResultType.path, callback) { 70 | return jsonPath({ 71 | json, 72 | path, 73 | flatten: true, 74 | resultType, 75 | callback 76 | }); 77 | } 78 | 79 | /** 80 | * Remove JSON-paths from `paths` that are included in `examplePaths` 81 | * @param {Object} openApiSpec Open-API spec to search in 82 | * @param {Set.} paths Paths where the examples have to be removed from 83 | * @param {Array.} examplePaths JSON-paths of the examples 84 | * @private 85 | */ 86 | function _excludeExamples(openApiSpec, paths, examplePaths) { 87 | examplePaths 88 | .forEach(examplePath => { 89 | _find(openApiSpec, examplePath) 90 | .forEach(exampleMatch => { 91 | for (const jsPath of paths) { 92 | jsPath.startsWith(exampleMatch) && paths.delete(jsPath); 93 | } 94 | }); 95 | }); 96 | } 97 | 98 | function _isPropertiesDefinition(path) { 99 | // Path has to end with `properties` 100 | if (!path.match(/\['properties']$/)) { return; } 101 | // Every second consecutive `properties` actually is not a property-definition, but a property itself 102 | const consecutiveMatch = path.match(/(?} [examplePaths=[]] The paths to the examples, which's content must not be modified 18 | */ 19 | function setNoAdditionalProperties(openApiSpec, examplePaths = []) { 20 | // Match all combiner keywords that are not preceded by a 'properties' keyword. 21 | // This allow to have objects that have as property name one of the combiner keywords. 22 | const hasJsonCombinerParentRegex 23 | = new RegExp('(? { 27 | return (schema) => { 28 | // Exclude schema that have a JSON combiner as parent 29 | if (hasJsonCombinerParentRegex.test(path)) { 30 | console.warn('"additionalProperties" flag not set ' 31 | + `for ${path} because it has a parent with a JSON-schema combiner keyword.`); 32 | return; 33 | } 34 | // Exclude schema that contains a JSON combiner 35 | if (JSON_SCHEMA_COMBINERS.some((combiner) => schema.hasOwnProperty(combiner))) { 36 | console.warn('"additionalProperties" flag not set ' 37 | + `for ${path} because it contains JSON-schema combiner keyword.`); 38 | return; 39 | } 40 | // Exclude schema that already contains additionalProperties 41 | if (schema.hasOwnProperty('additionalProperties')) { 42 | return; 43 | } 44 | schema.additionalProperties = false; 45 | }; 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /src/impl/v2/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains validation-logic that is specific to V2 of the OpenAPI-spec 3 | */ 4 | 5 | const cloneDeep = require('lodash.clonedeep'), 6 | { setAllPropertiesRequired } = require('../service/all-properties-required'), 7 | { setNoAdditionalProperties } = require('../service/no-additional-properties'); 8 | 9 | // CONSTANTS 10 | 11 | const PATH__EXAMPLES = '$..examples[?(@property && typeof @property === "string" && @property.match(/[\/+]json/))]', 12 | PROP__SCHEMA = 'schema', 13 | PROP__EXAMPLES = 'examples'; 14 | 15 | module.exports = { 16 | buildValidationMap, 17 | getJsonPathsToExamples, 18 | prepare 19 | }; 20 | 21 | // IMPLEMENTATION DETAILS 22 | 23 | /** 24 | * Get the JSONPaths to the examples 25 | * @returns {Array.} JSONPaths to the examples 26 | */ 27 | function getJsonPathsToExamples() { return [PATH__EXAMPLES]; } 28 | 29 | 30 | 31 | /** 32 | * Builds a map with the json-pointers to the response-schema as key and the json-pointers to the examples, as value. 33 | * The pointer of the schema is derived from the pointer to the example and doesn't necessarily mean 34 | * that the schema actually exists. 35 | * @param {Array.} pathsExamples Paths to the examples 36 | * @returns {Object.} Map with schema-pointers as key and example-pointers as value 37 | * @private 38 | */ 39 | function buildValidationMap(pathsExamples) { 40 | return pathsExamples.reduce((validationMap, pathExample) => { 41 | const pathSchema = _getSchemaPointerOfExample(pathExample); 42 | validationMap[pathSchema] = (validationMap[pathSchema] || new Set()) 43 | .add(pathExample); 44 | return validationMap; 45 | }, {}); 46 | } 47 | 48 | /** 49 | * Pre-processes the OpenAPI-spec, for further use. 50 | * The passed spec won't be modified. If a modification happens, a modified copy will be returned. 51 | * @param {Object} openapiSpec The OpenAPI-spec as JSON-schema 52 | * @param {boolean} [noAdditionalProperties=false] Don't allow properties that are not defined in the schema 53 | * @param {boolean} [allPropertiesRequired=false] Make all properties required 54 | * @return {Object} The prepared OpenAPI-spec 55 | */ 56 | function prepare(openapiSpec, { noAdditionalProperties, allPropertiesRequired } = {}) { 57 | const openapiSpecCopy = cloneDeep(openapiSpec); 58 | noAdditionalProperties && setNoAdditionalProperties(openapiSpecCopy, getJsonPathsToExamples()); 59 | allPropertiesRequired && setAllPropertiesRequired(openapiSpecCopy, getJsonPathsToExamples()); 60 | return openapiSpecCopy; 61 | } 62 | 63 | /** 64 | * Gets a JSON-pointer to the corresponding response-schema, based on a JSON-pointer to an example. 65 | * @param {String} examplePointer JSON-pointer to example 66 | * @returns {String} JSON-pointer to the corresponding response-schema 67 | * @private 68 | */ 69 | function _getSchemaPointerOfExample(examplePointer) { 70 | const pathSegs = examplePointer.split('/'), 71 | idxExamples = pathSegs.lastIndexOf(PROP__EXAMPLES); 72 | pathSegs.splice(idxExamples, pathSegs.length - idxExamples, PROP__SCHEMA); 73 | return pathSegs.join('/'); 74 | } 75 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'), 2 | refParser = require('json-schema-ref-parser'); 3 | 4 | module.exports = { 5 | createValidationResponse, 6 | dereferenceJsonSchema 7 | }; 8 | 9 | /** 10 | * Creates a unified response for the validation-result 11 | * @param {Array.} errors 12 | * @param {ValidationStatistics} statistics 13 | * @returns {ValidationResponse} 14 | * @private 15 | */ 16 | function createValidationResponse({ errors, statistics = {} }) { 17 | return { 18 | valid: !errors.length, 19 | statistics, 20 | errors 21 | }; 22 | } 23 | 24 | /** 25 | * Includes all referenced, external schemas (by the keyword `$ref`) into the schema 26 | * 27 | * CAUTION: This function is not concurrency-safe !! 28 | * This function changes the working dir and sets it back. This may become an concurrency issue when there are 29 | * other tasks running that rely on the working dir while this function waits for the asynchronous task of 30 | * dereferencing to complete. 31 | * 32 | * @param {String} pathToSchema File-path to the schema 33 | * @param {Object} jsonSchema Schema with potential externally referenced schemas 34 | * @returns {Promise} Dereferenced schema 35 | */ 36 | async function dereferenceJsonSchema(pathToSchema, jsonSchema) { 37 | const currentWorkingDir = process.cwd(); 38 | // Change the working dir to the schema-path, to make sure that relative paths can be resolved 39 | process.chdir(path.dirname(pathToSchema)); 40 | const dereferencedSchema = await refParser.dereference(jsonSchema); 41 | // Restore original working dir 42 | process.chdir(currentWorkingDir); 43 | return dereferencedSchema; 44 | } 45 | -------------------------------------------------------------------------------- /src/validator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Wrapper for the JSONSchema-validator 3 | */ 4 | 5 | const { JSONPath: jsonPath } = require('jsonpath-plus'), 6 | JsonPointer = require('json-pointer'), 7 | Ajv = require('ajv-draft-04'), 8 | addFormats = require('ajv-formats'); 9 | 10 | const PROP__ID = '$id', 11 | JSON_PATH__REFS = '$..\$ref', 12 | ID__SPEC_SCHEMA = 'https://www.npmjs.com/package/openapi-examples-validator/defs.json', 13 | ID__RESPONSE_SCHEMA = 'https://www.npmjs.com/package/openapi-examples-validator/schema.json'; 14 | 15 | module.exports = { 16 | getValidatorFactory, 17 | compileValidate 18 | }; 19 | 20 | /** 21 | * Get a factory-function to create a prepared validator-instance 22 | * @param {Object} specSchema OpenAPI-spec of which potential local references will be extracted 23 | * @param {Object} [options] Options for the validator 24 | * @returns {function(): (ajv | ajv.Ajv)} 25 | */ 26 | function getValidatorFactory(specSchema, options) { 27 | const preparedSpecSchema = _createReferenceSchema(specSchema); 28 | return () => { 29 | const validator = new Ajv(options); 30 | addFormats(validator); 31 | 32 | validator.addSchema(preparedSpecSchema); 33 | 34 | return validator; 35 | }; 36 | } 37 | 38 | /** 39 | * Compiles the validator-function. 40 | * @param {ajv | ajv.Ajv} validator Validator-instance 41 | * @param {Object} responseSchema The response-schema, against the examples will be validated 42 | * @returns {ajv.ValidateFunction} 43 | */ 44 | function compileValidate(validator, responseSchema) { 45 | const preparedResponseSchema = _prepareResponseSchema(responseSchema, ID__RESPONSE_SCHEMA); 46 | _replaceRefsToPreparedSpecSchema(preparedResponseSchema); 47 | 48 | let result; 49 | try { 50 | result = validator.compile(preparedResponseSchema); 51 | } catch (e) { 52 | result = () => {}; 53 | result.errors = [e]; 54 | } 55 | return result; 56 | } 57 | 58 | /** 59 | * Prepares the schema, to be used with internal-references 60 | * @param {Object} specSchema The schema to be prebared 61 | * @param {String} idSchema The unique ID for the schema 62 | * @returns {Object} 63 | * @private 64 | */ 65 | function _prepareResponseSchema(specSchema, idSchema) { 66 | const preparedSchema = Object.assign({}, specSchema); 67 | preparedSchema[PROP__ID] = idSchema; 68 | return preparedSchema; 69 | } 70 | 71 | /** 72 | * Replaces all internal references to the schema, with the extracted references, based on the origin OpenAPI-spec 73 | * @param {Object} schema The schema, containing references have to be replaced 74 | * @private 75 | */ 76 | function _replaceRefsToPreparedSpecSchema(schema) { 77 | jsonPath({ 78 | path: JSON_PATH__REFS, 79 | json: schema, 80 | callback(value, type, payload) { 81 | if (!value.startsWith('#')) { return; } 82 | payload.parent[payload.parentProperty] = `${ ID__SPEC_SCHEMA }${ value }`; 83 | } 84 | }); 85 | } 86 | 87 | /** 88 | * Extracts all references and returns a new schema, containing only those. 89 | * @param {Object} specSchema Schema, which references shall be extracted 90 | * @returns {Object} 91 | * @private 92 | */ 93 | function _createReferenceSchema(specSchema) { 94 | const refSchema = { 95 | [PROP__ID]: ID__SPEC_SCHEMA 96 | }; 97 | jsonPath({ 98 | path: JSON_PATH__REFS, 99 | json: specSchema, 100 | callback(value) { 101 | if (!value.startsWith('#')) { return; } 102 | const pointer = value.substring(1), 103 | definition = JsonPointer.get(specSchema, pointer); 104 | JsonPointer.set(refSchema, pointer, definition); 105 | } 106 | }); 107 | return refSchema; 108 | } 109 | -------------------------------------------------------------------------------- /stryker.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mutate: [ 3 | 'src/**/*.js' 4 | ], 5 | packageManager: 'npm', 6 | reporters: ['html', 'clear-text', 'progress', 'dashboard'], 7 | testRunner: 'mocha', 8 | coverageAnalysis: 'perTest' 9 | }; 10 | -------------------------------------------------------------------------------- /test/data/output-help.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | module.exports = { 3 | text: `Usage: cli [options] 4 | 5 | Validate embedded examples in OpenAPI-specs (JSON and YAML supported). 6 | To validate external examples, use the \`-s\` and \`-e\` option. 7 | To pass a mapping-file, to validate multiple external examples, use the \`-m\` option. 8 | 9 | Options: 10 | -V, --version output the version number 11 | -s, --schema-jsonpath Path to OpenAPI-schema, to validate the example file against 12 | -e, --example-filepath file path to example file, to be validated 13 | -m, --mapping-filepath file path to map, containing schema-paths as key and the file-path(s) to examples as value. If wildcards are used, the parameter has to be put in quotes. 14 | -c, --cwd-to-mapping-file changes to the directory of the mapping-file, before resolving the example's paths. Use this option, if your mapping-files use relative paths for the examples 15 | -n, --no-additional-properties don't allow properties that are not described in the schema 16 | -r, --all-properties-required make all the properties in the schema required 17 | -o, --ignore-formats Datatype formats to ignore (to prevent "unknown format" message in the error-console.) 18 | -h, --help display help for command 19 | 20 | 21 | Example for external example-file: 22 | 23 | $ openapi-examples-validator -s $.paths./.get.responses.200.schema -e example.json openapi-spec.json 24 | 25 | 26 | ` 27 | }; 28 | -------------------------------------------------------------------------------- /test/data/output/api-additional-properties.js: -------------------------------------------------------------------------------- 1 | module.exports.value = `Validating examples 2 | Schemas with examples found: 2 3 | Examples without schema found: 0 4 | Total examples found: 2 5 | 6 | Errors found. 7 | 8 | `; 9 | -------------------------------------------------------------------------------- /test/data/output/api-with-examples-and-additional-properties.js: -------------------------------------------------------------------------------- 1 | module.exports.value = `Validating examples 2 | Schemas with examples found: 2 3 | Examples without schema found: 0 4 | Total examples found: 2 5 | 6 | Errors found. 7 | 8 | `; 9 | -------------------------------------------------------------------------------- /test/data/output/api-with-examples-and-all-properties-required.js: -------------------------------------------------------------------------------- 1 | module.exports.value = `Validating examples 2 | Schemas with examples found: 2 3 | Examples without schema found: 0 4 | Total examples found: 3 5 | 6 | Errors found. 7 | 8 | `; 9 | -------------------------------------------------------------------------------- /test/data/v2/additional-properties/errors-schema-invalid-with-examples.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must NOT have additional properties", 5 | "instancePath": "/0", 6 | "schemaPath": "#/items/additionalProperties", 7 | "keyword": "additionalProperties", 8 | "params": { 9 | "additionalProperty": "location" 10 | }, 11 | "examplePath": "/paths/~1pets/get/responses/200/examples/application~1json" 12 | }, 13 | { 14 | "type": "Validation", 15 | "message": "must NOT have additional properties", 16 | "instancePath": "/0/schema", 17 | "schemaPath": "#/items/properties/schema/additionalProperties", 18 | "keyword": "additionalProperties", 19 | "params": { 20 | "additionalProperty": "spec" 21 | }, 22 | "examplePath": "/paths/~1pets/get/responses/200/examples/application~1json" 23 | }, 24 | { 25 | "type": "Validation", 26 | "message": "must NOT have additional properties", 27 | "instancePath": "/0/schema/properties", 28 | "schemaPath": "#/items/properties/schema/properties/properties/additionalProperties", 29 | "keyword": "additionalProperties", 30 | "params": { 31 | "additionalProperty": "nickname" 32 | }, 33 | "examplePath": "/paths/~1pets/get/responses/200/examples/application~1json" 34 | }, 35 | { 36 | "type": "Validation", 37 | "message": "must NOT have additional properties", 38 | "instancePath": "/0/schema/properties/properties", 39 | "schemaPath": "#/items/properties/schema/properties/properties/properties/properties/additionalProperties", 40 | "keyword": "additionalProperties", 41 | "params": { 42 | "additionalProperty": "some" 43 | }, 44 | "examplePath": "/paths/~1pets/get/responses/200/examples/application~1json" 45 | }, 46 | { 47 | "type": "Validation", 48 | "message": "must NOT have additional properties", 49 | "instancePath": "", 50 | "schemaPath": "#/additionalProperties", 51 | "keyword": "additionalProperties", 52 | "params": { 53 | "additionalProperty": "age" 54 | }, 55 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/examples/application~1json" 56 | }, 57 | { 58 | "type": "Validation", 59 | "message": "must NOT have additional properties", 60 | "instancePath": "", 61 | "schemaPath": "#/additionalProperties", 62 | "keyword": "additionalProperties", 63 | "params": { 64 | "additionalProperty": "owner" 65 | }, 66 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/examples/application~1json" 67 | }, 68 | { 69 | "type": "Validation", 70 | "message": "must NOT have additional properties", 71 | "instancePath": "/schema", 72 | "schemaPath": "#/properties/schema/additionalProperties", 73 | "keyword": "additionalProperties", 74 | "params": { 75 | "additionalProperty": "spec" 76 | }, 77 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/examples/application~1json" 78 | }, 79 | { 80 | "type": "Validation", 81 | "message": "must NOT have additional properties", 82 | "instancePath": "/schema/properties", 83 | "schemaPath": "#/properties/schema/properties/properties/additionalProperties", 84 | "keyword": "additionalProperties", 85 | "params": { 86 | "additionalProperty": "callname" 87 | }, 88 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/examples/application~1json" 89 | }, 90 | { 91 | "type": "Validation", 92 | "message": "must NOT have additional properties", 93 | "instancePath": "/0/schema/properties/type", 94 | "schemaPath": "#/items/properties/schema/properties/properties/properties/type/additionalProperties", 95 | "keyword": "additionalProperties", 96 | "params": { 97 | "additionalProperty": "bar" 98 | }, 99 | "examplePath": "/paths/~1pets/get/responses/200/examples/application~1json" 100 | } 101 | ] 102 | -------------------------------------------------------------------------------- /test/data/v2/additional-properties/invalid-with-examples.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | swagger: '2.0' 3 | info: 4 | license: 5 | name: MIT 6 | title: Swagger Petstore 7 | version: 1.0.0 8 | host: petstore.swagger.io 9 | basePath: "/v1" 10 | schemes: 11 | - http 12 | paths: 13 | "/pets": 14 | get: 15 | produces: 16 | - application/json 17 | parameters: [] 18 | responses: 19 | '200': 20 | description: An array of pets 21 | schema: 22 | items: 23 | properties: 24 | id: 25 | type: number 26 | name: 27 | type: string 28 | schema: 29 | properties: 30 | properties: 31 | properties: 32 | color: 33 | type: string 34 | properties: 35 | properties: 36 | foo: 37 | type: number 38 | type: object 39 | type: 40 | type: object 41 | type: object 42 | type: object 43 | tag: 44 | type: string 45 | required: 46 | - id 47 | - name 48 | type: array 49 | examples: 50 | application/json: 51 | - id: 1 52 | name: john 53 | location: home 54 | schema: 55 | spec: 'pet_definition' 56 | properties: 57 | nickname: buddy 58 | color: black 59 | type: 60 | bar: 'baz' 61 | properties: 62 | foo: 5 63 | some: id 64 | default: 65 | description: unexpected error 66 | schema: 67 | properties: 68 | code: 69 | type: number 70 | message: 71 | type: string 72 | required: 73 | - code 74 | - message 75 | operationId: listPets 76 | summary: List all pets 77 | post: 78 | produces: 79 | - application/json 80 | parameters: [] 81 | responses: 82 | '201': 83 | description: Null response 84 | default: 85 | description: unexpected error 86 | schema: 87 | properties: 88 | code: 89 | type: number 90 | message: 91 | type: string 92 | required: 93 | - code 94 | - message 95 | tags: 96 | - pets 97 | operationId: createPets 98 | summary: Create a pet 99 | "/pets/{petId}": 100 | get: 101 | produces: 102 | - application/json 103 | parameters: 104 | - description: The id of the pet to retrieve 105 | in: path 106 | name: petId 107 | required: true 108 | type: string 109 | responses: 110 | '200': 111 | description: Expected response to a valid request 112 | examples: 113 | application/json: 114 | age: 5 115 | id: 0 116 | name: Herbert 117 | owner: John 118 | schema: 119 | spec: pet_definition 120 | properties: 121 | callname: buddy 122 | color: black 123 | tag: Doggo 124 | schema: 125 | properties: 126 | id: 127 | type: number 128 | name: 129 | type: string 130 | schema: 131 | properties: 132 | properties: 133 | properties: 134 | color: 135 | type: string 136 | type: object 137 | type: object 138 | tag: 139 | type: string 140 | required: 141 | - id 142 | - name 143 | default: 144 | description: unexpected error 145 | schema: 146 | properties: 147 | code: 148 | type: number 149 | message: 150 | type: string 151 | required: 152 | - code 153 | - message 154 | operationId: showPetById 155 | summary: Info for a specific pet 156 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-invalid-missing-link.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | { 4 | "status": "CURRENT", 5 | "updated": "2011-01-21T11:33:21Z", 6 | "id": "v2.0" 7 | }, 8 | { 9 | "status": "EXPERIMENTAL", 10 | "updated": "2013-07-23T11:33:21Z", 11 | "id": "v3.0", 12 | "links": [ 13 | { 14 | "href": "http://127.0.0.1:8774/v3/", 15 | "rel": "self" 16 | } 17 | ] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-invalid-type.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | { 4 | "status": "CURRENT", 5 | "updated": "2016-01-21T11:33:21Z", 6 | "id": 1.0, 7 | "links": [ 8 | { 9 | "href": "http://127.0.0.1:8774/v1/", 10 | "rel": "self" 11 | } 12 | ] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-schema-referencing-fraction.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "200 response", 3 | "schema": { 4 | "type": "object", 5 | "required": [ 6 | "versions" 7 | ], 8 | "properties": { 9 | "versions": { 10 | "type": "array", 11 | "items": { 12 | "type": "object", 13 | "required": [ 14 | "status", 15 | "id", 16 | "links" 17 | ], 18 | "properties": { 19 | "status": { 20 | "type": "string" 21 | }, 22 | "updated": { 23 | "type": "string" 24 | }, 25 | "id": { 26 | "type": "string" 27 | }, 28 | "links": { 29 | "type": "array", 30 | "items": { 31 | "type": "object", 32 | "required": [ 33 | "href", 34 | "rel" 35 | ], 36 | "properties": { 37 | "href": { 38 | "type": "string" 39 | }, 40 | "rel": { 41 | "type": "string" 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | }, 51 | "examples": { 52 | "application/json": { 53 | "$ref": "./external-examples-valid-example1.json" 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-schema-referencing-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "schema": { 19 | "type": "object", 20 | "required": [ 21 | "versions" 22 | ], 23 | "properties": { 24 | "versions": { 25 | "type": "array", 26 | "items": { 27 | "type": "object", 28 | "required": [ 29 | "status", 30 | "id", 31 | "links" 32 | ], 33 | "properties": { 34 | "status": { 35 | "type": "string" 36 | }, 37 | "updated": { 38 | "type": "string" 39 | }, 40 | "id": { 41 | "type": "string" 42 | }, 43 | "links": { 44 | "type": "array", 45 | "items": { 46 | "type": "object", 47 | "required": [ 48 | "href", 49 | "rel" 50 | ], 51 | "properties": { 52 | "href": { 53 | "type": "string" 54 | }, 55 | "rel": { 56 | "type": "string" 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | }, 66 | "examples": { 67 | "application/json": { 68 | "$ref": "./external-examples-invalid-type.json" 69 | } 70 | } 71 | }, 72 | "300": { 73 | "description": "300 response", 74 | "schema": { 75 | "type": "object", 76 | "required": [ 77 | "versions" 78 | ], 79 | "properties": { 80 | "versions": { 81 | "type": "array", 82 | "items": { 83 | "type": "object", 84 | "required": [ 85 | "status", 86 | "id", 87 | "links" 88 | ], 89 | "properties": { 90 | "status": { 91 | "type": "string" 92 | }, 93 | "updated": { 94 | "type": "string" 95 | }, 96 | "id": { 97 | "type": "string" 98 | }, 99 | "links": { 100 | "type": "array", 101 | "items": { 102 | "type": "object", 103 | "required": [ 104 | "href", 105 | "rel" 106 | ], 107 | "properties": { 108 | "href": { 109 | "type": "string" 110 | }, 111 | "rel": { 112 | "type": "string" 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | }, 127 | "consumes": [ 128 | "application/json" 129 | ] 130 | } 131 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-schema-referencing-sub-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "$ref": "external-examples-schema-referencing-fraction.json" 18 | }, 19 | "300": { 20 | "description": "300 response", 21 | "schema": { 22 | "type": "object", 23 | "required": [ 24 | "versions" 25 | ], 26 | "properties": { 27 | "versions": { 28 | "type": "array", 29 | "items": { 30 | "type": "object", 31 | "required": [ 32 | "status", 33 | "id", 34 | "links" 35 | ], 36 | "properties": { 37 | "status": { 38 | "type": "string" 39 | }, 40 | "updated": { 41 | "type": "string" 42 | }, 43 | "id": { 44 | "type": "string" 45 | }, 46 | "links": { 47 | "type": "array", 48 | "items": { 49 | "type": "object", 50 | "required": [ 51 | "href", 52 | "rel" 53 | ], 54 | "properties": { 55 | "href": { 56 | "type": "string" 57 | }, 58 | "rel": { 59 | "type": "string" 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | "consumes": [ 75 | "application/json" 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-schema-referencing-valid.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "schema": { 19 | "type": "object", 20 | "required": [ 21 | "versions" 22 | ], 23 | "properties": { 24 | "versions": { 25 | "type": "array", 26 | "items": { 27 | "type": "object", 28 | "required": [ 29 | "status", 30 | "id", 31 | "links" 32 | ], 33 | "properties": { 34 | "status": { 35 | "type": "string" 36 | }, 37 | "updated": { 38 | "type": "string" 39 | }, 40 | "id": { 41 | "type": "string" 42 | }, 43 | "links": { 44 | "type": "array", 45 | "items": { 46 | "type": "object", 47 | "required": [ 48 | "href", 49 | "rel" 50 | ], 51 | "properties": { 52 | "href": { 53 | "type": "string" 54 | }, 55 | "rel": { 56 | "type": "string" 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | }, 66 | "examples": { 67 | "application/json": { 68 | "$ref": "./external-examples-valid-example1.json" 69 | } 70 | } 71 | }, 72 | "300": { 73 | "description": "300 response", 74 | "schema": { 75 | "type": "object", 76 | "required": [ 77 | "versions" 78 | ], 79 | "properties": { 80 | "versions": { 81 | "type": "array", 82 | "items": { 83 | "type": "object", 84 | "required": [ 85 | "status", 86 | "id", 87 | "links" 88 | ], 89 | "properties": { 90 | "status": { 91 | "type": "string" 92 | }, 93 | "updated": { 94 | "type": "string" 95 | }, 96 | "id": { 97 | "type": "string" 98 | }, 99 | "links": { 100 | "type": "array", 101 | "items": { 102 | "type": "object", 103 | "required": [ 104 | "href", 105 | "rel" 106 | ], 107 | "properties": { 108 | "href": { 109 | "type": "string" 110 | }, 111 | "rel": { 112 | "type": "string" 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | }, 127 | "consumes": [ 128 | "application/json" 129 | ] 130 | } 131 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "schema": { 19 | "type": "object", 20 | "required": [ 21 | "versions" 22 | ], 23 | "properties": { 24 | "versions": { 25 | "type": "array", 26 | "items": { 27 | "type": "object", 28 | "required": [ 29 | "status", 30 | "id", 31 | "links" 32 | ], 33 | "properties": { 34 | "status": { 35 | "type": "string" 36 | }, 37 | "updated": { 38 | "type": "string" 39 | }, 40 | "id": { 41 | "type": "string" 42 | }, 43 | "links": { 44 | "type": "array", 45 | "items": { 46 | "type": "object", 47 | "required": [ 48 | "href", 49 | "rel" 50 | ], 51 | "properties": { 52 | "href": { 53 | "type": "string" 54 | }, 55 | "rel": { 56 | "type": "string" 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | }, 67 | "300": { 68 | "description": "300 response", 69 | "schema": { 70 | "type": "object", 71 | "required": [ 72 | "versions" 73 | ], 74 | "properties": { 75 | "versions": { 76 | "type": "array", 77 | "items": { 78 | "type": "object", 79 | "required": [ 80 | "status", 81 | "id", 82 | "links" 83 | ], 84 | "properties": { 85 | "status": { 86 | "type": "string" 87 | }, 88 | "updated": { 89 | "type": "string" 90 | }, 91 | "id": { 92 | "type": "string" 93 | }, 94 | "links": { 95 | "type": "array", 96 | "items": { 97 | "type": "object", 98 | "required": [ 99 | "href", 100 | "rel" 101 | ], 102 | "properties": { 103 | "href": { 104 | "type": "string" 105 | }, 106 | "rel": { 107 | "type": "string" 108 | } 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | } 121 | }, 122 | "consumes": [ 123 | "application/json" 124 | ] 125 | } 126 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-valid-example1.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | { 4 | "status": "CURRENT", 5 | "updated": "2011-01-21T11:33:21Z", 6 | "id": "v2.0", 7 | "links": [ 8 | { 9 | "href": "http://127.0.0.1:8774/v2/", 10 | "rel": "self" 11 | } 12 | ] 13 | }, 14 | { 15 | "status": "EXPERIMENTAL", 16 | "updated": "2013-07-23T11:33:21Z", 17 | "id": "v3.0", 18 | "links": [ 19 | { 20 | "href": "http://127.0.0.1:8774/v3/", 21 | "rel": "self" 22 | } 23 | ] 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/data/v2/external-examples-valid-example2.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | { 4 | "status": "CURRENT", 5 | "updated": "2016-01-21T11:33:21Z", 6 | "id": "v1.0", 7 | "links": [ 8 | { 9 | "href": "http://127.0.0.1:8774/v1/", 10 | "rel": "self" 11 | } 12 | ] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /test/data/v2/invalid-array-response.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": [ 20 | { 21 | "status": "CURRENT", 22 | "updated": "2011-01-21T11:33:21Z", 23 | "links": [ 24 | { 25 | "href": "http://127.0.0.1:8774/v2/", 26 | "rel": "self" 27 | } 28 | ] 29 | }, 30 | { 31 | "status": "EXPERIMENTAL", 32 | "updated": "2013-07-23T11:33:21Z", 33 | "id": "v3.0", 34 | "links": "http://127.0.0.1:8774/v3/" 35 | } 36 | ] 37 | }, 38 | "schema": { 39 | "type": "array", 40 | "items": { 41 | "type": "object", 42 | "required": [ 43 | "status", 44 | "id", 45 | "links" 46 | ], 47 | "properties": { 48 | "status": { 49 | "type": "string" 50 | }, 51 | "updated": { 52 | "type": "string" 53 | }, 54 | "id": { 55 | "type": "string" 56 | }, 57 | "links": { 58 | "type": "array", 59 | "items": { 60 | "type": "object", 61 | "required": [ 62 | "href", 63 | "rel" 64 | ], 65 | "properties": { 66 | "href": { 67 | "type": "string" 68 | }, 69 | "rel": { 70 | "type": "string" 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | }, 83 | "consumes": [ 84 | "application/json" 85 | ] 86 | } 87 | -------------------------------------------------------------------------------- /test/data/v2/invalid-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": { 20 | "versions": [ 21 | { 22 | "status": "CURRENT", 23 | "updated": "2016-01-21T11:33:21Z", 24 | "occurred": "2020-01-01" 25 | } 26 | ] 27 | } 28 | }, 29 | "schema": { 30 | "type": "object", 31 | "required": [ 32 | "versions" 33 | ], 34 | "properties": { 35 | "versions": { 36 | "type": "array", 37 | "items": { 38 | "type": "object", 39 | "required": [ 40 | "status", 41 | "id", 42 | "links" 43 | ], 44 | "properties": { 45 | "status": { 46 | "type": "string" 47 | }, 48 | "updated": { 49 | "type": "string" 50 | }, 51 | "occurred": { 52 | "type": "string", 53 | "format": "timestamp" 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | }, 65 | "consumes": [ 66 | "application/json" 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /test/data/v2/invalid-type.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": { 20 | "versions": [ 21 | { 22 | "status": "CURRENT", 23 | "updated": "2016-01-21T11:33:21Z", 24 | "id": 1.0, 25 | "links": [ 26 | { 27 | "href": "http://127.0.0.1:8774/v1/", 28 | "rel": "self" 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | }, 35 | "schema": { 36 | "type": "object", 37 | "required": [ 38 | "versions" 39 | ], 40 | "properties": { 41 | "versions": { 42 | "type": "array", 43 | "items": { 44 | "type": "object", 45 | "required": [ 46 | "status", 47 | "id", 48 | "links" 49 | ], 50 | "properties": { 51 | "status": { 52 | "type": "string" 53 | }, 54 | "updated": { 55 | "type": "string" 56 | }, 57 | "id": { 58 | "type": "string" 59 | }, 60 | "links": { 61 | "type": "array", 62 | "items": { 63 | "type": "object", 64 | "required": [ 65 | "href", 66 | "rel" 67 | ], 68 | "properties": { 69 | "href": { 70 | "type": "string" 71 | }, 72 | "rel": { 73 | "type": "string" 74 | } 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | }, 88 | "consumes": [ 89 | "application/json" 90 | ] 91 | } 92 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-glob-invalid1.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "test/data/v2/external-examples-valid-example1.json", 4 | "test/data/v2/external-examples-valid-example2.json", 5 | "test/data/v2/external-examples-invalid-missing-link.json" 6 | ], 7 | "$.paths./.get.responses.300.schema": "test/data/v2/external-examples-invalid-type.json" 8 | } 9 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-glob-invalid2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "test/data/v2/external-examples-valid-example1.json", 4 | "test/data/v2/external-examples-valid-example2.json" 5 | ], 6 | "$.paths./.get.responses.300.schema": "test/data/v2/external-examples-invalid-missing-link.json" 7 | } 8 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-map-with-missing-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "test/data/v2/external-examples-valid-example1.json", 4 | "test/data/v2/blegh forgot the sugar in the coffee", 5 | "test/data/v2/external-examples-valid-example2.json" 6 | ], 7 | "$.paths./.get.responses.300.schema": "test/data/v2/external-examples-invalid-missing-link.json" 8 | } 9 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-map-with-wrong-schema-path.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.hmm.what.am.i.gonna.get.for.lunch": [ 3 | "test/data/v2/external-examples-valid-example1.json", 4 | "test/data/v2/external-examples-invalid-type.json" 5 | ], 6 | "$.paths./.get.responses.300.schema": "test/data/v2/external-examples-valid-example2.json" 7 | } 8 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-relative-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "external-examples-invalid-missing-link.json", 4 | "external-examples-valid-example1.json" 5 | ], 6 | "$.paths./.get.responses.300.schema": "./external-examples-valid-example1.json" 7 | } 8 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-relative.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "external-examples-valid-example1.json", 4 | "external-examples-valid-example2.json" 5 | ], 6 | "$.paths./.get.responses.300.schema": "./external-examples-valid-example1.json" 7 | } 8 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-with-wildcards.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "test/data/v2/external-examples-valid-example1.json", 4 | "test/data/v2/external-*-valid-*.json", 5 | "test/data/v2/external-*-invalid-*.json" 6 | ], 7 | "$.paths./.get.responses.300.schema": "test/data/v2/external-examples-valid-*.json" 8 | } 9 | -------------------------------------------------------------------------------- /test/data/v2/map-external-examples-without-wildcards.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "test/data/v2/external-examples-valid-example1.json", 4 | "test/data/v2/external-examples-valid-example1.json", 5 | "test/data/v2/external-examples-valid-example2.json", 6 | "test/data/v2/external-examples-invalid-missing-link.json", 7 | "test/data/v2/external-examples-invalid-type.json" 8 | ], 9 | "$.paths./.get.responses.300.schema": [ 10 | "test/data/v2/external-examples-valid-example1.json", 11 | "test/data/v2/external-examples-valid-example2.json" 12 | ] 13 | } -------------------------------------------------------------------------------- /test/data/v2/map-external-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./.get.responses.200.schema": [ 3 | "test/data/v2/external-examples-valid-example1.json", 4 | "test/data/v2/external-examples-valid-example2.json", 5 | "test/data/v2/external-examples-invalid-type.json" 6 | ], 7 | "$.paths./.get.responses.300.schema": "test/data/v2/external-examples-invalid-missing-link.json" 8 | } 9 | -------------------------------------------------------------------------------- /test/data/v2/output-map-external-examples.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | module.exports = { 3 | text: `Validating with mapping file 4 | Schemas with examples found: 2 5 | Examples without schema found: 0 6 | Total examples found: 3 7 | Matching mapping files found: 1 8 | 9 | Errors found. 10 | 11 | ` 12 | }; 13 | -------------------------------------------------------------------------------- /test/data/v2/output-single-external-example-valid.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | module.exports = { 3 | text: `Validating single external example 4 | Schemas with examples found: 1 5 | Examples without schema found: 0 6 | Total examples found: 1 7 | 8 | No errors found. 9 | 10 | ` 11 | }; 12 | -------------------------------------------------------------------------------- /test/data/v2/response-valid-content-array.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | title: API 4 | version: 1.0.0 5 | paths: 6 | /metrics: 7 | get: 8 | summary: Get info 9 | operationId: get_info 10 | description: | 11 | This API hook returns server metrics. 12 | produces: 13 | - application/json 14 | responses: 15 | 200: 16 | description: OK 17 | schema: 18 | type: object 19 | properties: 20 | examples: 21 | type: array 22 | description: Array of valid entries 23 | items: 24 | type: object 25 | properties: 26 | type: 27 | type: integer 28 | description: RR type of entry 29 | examples: 30 | application/json: 31 | examples: 32 | - type: 0 33 | -------------------------------------------------------------------------------- /test/data/v2/valid-array-response.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": [ 20 | { 21 | "status": "CURRENT", 22 | "updated": "2011-01-21T11:33:21Z", 23 | "id": "v2.0", 24 | "links": [ 25 | { 26 | "href": "http://127.0.0.1:8774/v2/", 27 | "rel": "self" 28 | } 29 | ] 30 | }, 31 | { 32 | "status": "EXPERIMENTAL", 33 | "updated": "2013-07-23T11:33:21Z", 34 | "id": "v3.0", 35 | "links": [ 36 | { 37 | "href": "http://127.0.0.1:8774/v3/", 38 | "rel": "self" 39 | } 40 | ] 41 | } 42 | ] 43 | }, 44 | "schema": { 45 | "type": "array", 46 | "items": { 47 | "type": "object", 48 | "required": [ 49 | "status", 50 | "id", 51 | "links" 52 | ], 53 | "properties": { 54 | "status": { 55 | "type": "string" 56 | }, 57 | "updated": { 58 | "type": "string" 59 | }, 60 | "id": { 61 | "type": "string" 62 | }, 63 | "links": { 64 | "type": "array", 65 | "items": { 66 | "type": "object", 67 | "required": [ 68 | "href", 69 | "rel" 70 | ], 71 | "properties": { 72 | "href": { 73 | "type": "string" 74 | }, 75 | "rel": { 76 | "type": "string" 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | }, 89 | "consumes": [ 90 | "application/json" 91 | ] 92 | } 93 | -------------------------------------------------------------------------------- /test/data/v2/valid-multiple-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": { 20 | "versions": [ 21 | { 22 | "status": "CURRENT", 23 | "updated": "2011-01-21T11:33:21Z", 24 | "id": "v2.0", 25 | "links": [ 26 | { 27 | "href": "http://127.0.0.1:8774/v2/", 28 | "rel": "self" 29 | } 30 | ] 31 | }, 32 | { 33 | "status": "EXPERIMENTAL", 34 | "updated": "2013-07-23T11:33:21Z", 35 | "id": "v3.0", 36 | "links": [ 37 | { 38 | "href": "http://127.0.0.1:8774/v3/", 39 | "rel": "self" 40 | } 41 | ] 42 | } 43 | ] 44 | } 45 | }, 46 | "schema": { 47 | "type": "object", 48 | "required": [ 49 | "versions" 50 | ], 51 | "properties": { 52 | "versions": { 53 | "type": "array", 54 | "items": { 55 | "type": "object", 56 | "required": [ 57 | "status", 58 | "id", 59 | "links" 60 | ], 61 | "properties": { 62 | "status": { 63 | "type": "string" 64 | }, 65 | "updated": { 66 | "type": "string" 67 | }, 68 | "id": { 69 | "type": "string" 70 | }, 71 | "links": { 72 | "type": "array", 73 | "items": { 74 | "type": "object", 75 | "required": [ 76 | "href", 77 | "rel" 78 | ], 79 | "properties": { 80 | "href": { 81 | "type": "string" 82 | }, 83 | "rel": { 84 | "type": "string" 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "consumes": [ 100 | "application/json" 101 | ] 102 | } 103 | -------------------------------------------------------------------------------- /test/data/v2/valid-single-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": { 20 | "versions": [ 21 | { 22 | "status": "CURRENT", 23 | "updated": "2016-01-21T11:33:21Z", 24 | "id": "v1.0", 25 | "links": [ 26 | { 27 | "href": "http://127.0.0.1:8774/v1/", 28 | "rel": "self" 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | }, 35 | "schema": { 36 | "type": "object", 37 | "required": [ 38 | "versions" 39 | ], 40 | "properties": { 41 | "versions": { 42 | "type": "array", 43 | "items": { 44 | "type": "object", 45 | "required": [ 46 | "status", 47 | "id", 48 | "links" 49 | ], 50 | "properties": { 51 | "status": { 52 | "type": "string" 53 | }, 54 | "updated": { 55 | "type": "string" 56 | }, 57 | "id": { 58 | "type": "string" 59 | }, 60 | "links": { 61 | "type": "array", 62 | "items": { 63 | "type": "object", 64 | "required": [ 65 | "href", 66 | "rel" 67 | ], 68 | "properties": { 69 | "href": { 70 | "type": "string" 71 | }, 72 | "rel": { 73 | "type": "string" 74 | } 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | }, 88 | "consumes": [ 89 | "application/json" 90 | ] 91 | } 92 | -------------------------------------------------------------------------------- /test/data/v2/valid-with-all-properties-required.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": { 20 | "versions": [ 21 | { 22 | "status": "CURRENT", 23 | "updated": "2011-01-21T11:33:21Z", 24 | "id": "v2.0", 25 | "links": [ 26 | { 27 | "href": "http://127.0.0.1:8774/v2/", 28 | "rel": "self" 29 | } 30 | ] 31 | }, 32 | { 33 | "status": "EXPERIMENTAL", 34 | "updated": "2013-07-23T11:33:21Z", 35 | "id": "v3.0", 36 | "links": [ 37 | { 38 | "href": "http://127.0.0.1:8774/v3/", 39 | "rel": "self" 40 | } 41 | ] 42 | } 43 | ] 44 | } 45 | }, 46 | "schema": { 47 | "type": "object", 48 | "required": [ 49 | "versions" 50 | ], 51 | "properties": { 52 | "versions": { 53 | "type": "array", 54 | "items": { 55 | "type": "object", 56 | "required": [ 57 | "status", 58 | "updated", 59 | "id", 60 | "links" 61 | ], 62 | "properties": { 63 | "status": { 64 | "type": "string" 65 | }, 66 | "updated": { 67 | "type": "string" 68 | }, 69 | "id": { 70 | "type": "string" 71 | }, 72 | "links": { 73 | "type": "array", 74 | "items": { 75 | "type": "object", 76 | "required": [ 77 | "href", 78 | "rel" 79 | ], 80 | "properties": { 81 | "href": { 82 | "type": "string" 83 | }, 84 | "rel": { 85 | "type": "string" 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | }, 96 | "300": { 97 | "description": "300 response", 98 | "schema": { 99 | "type": "object", 100 | "required": [ 101 | "versions" 102 | ], 103 | "properties": { 104 | "versions": { 105 | "type": "array", 106 | "items": { 107 | "type": "object", 108 | "required": [ 109 | "status", 110 | "updated", 111 | "id", 112 | "links" 113 | ], 114 | "properties": { 115 | "status": { 116 | "type": "string" 117 | }, 118 | "updated": { 119 | "type": "string" 120 | }, 121 | "id": { 122 | "type": "string" 123 | }, 124 | "links": { 125 | "type": "array", 126 | "items": { 127 | "type": "object", 128 | "required": [ 129 | "href", 130 | "rel" 131 | ], 132 | "properties": { 133 | "href": { 134 | "type": "string" 135 | }, 136 | "rel": { 137 | "type": "string" 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | } 148 | } 149 | } 150 | } 151 | }, 152 | "consumes": [ 153 | "application/json" 154 | ] 155 | } 156 | -------------------------------------------------------------------------------- /test/data/v2/valid-without-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": { 20 | "versions": [ 21 | { 22 | "status": "CURRENT", 23 | "updated": "2011-01-21T11:33:21Z", 24 | "id": "v2.0", 25 | "links": [ 26 | { 27 | "href": "http://127.0.0.1:8774/v2/", 28 | "rel": "self" 29 | } 30 | ] 31 | }, 32 | { 33 | "status": "EXPERIMENTAL", 34 | "updated": "2013-07-23T11:33:21Z", 35 | "id": "v3.0", 36 | "links": [ 37 | { 38 | "href": "http://127.0.0.1:8774/v3/", 39 | "rel": "self" 40 | } 41 | ] 42 | } 43 | ] 44 | } 45 | }, 46 | "schema": { 47 | "type": "object", 48 | "required": [ 49 | "versions" 50 | ], 51 | "properties": { 52 | "versions": { 53 | "type": "array", 54 | "items": { 55 | "type": "object", 56 | "required": [ 57 | "status", 58 | "id", 59 | "links" 60 | ], 61 | "properties": { 62 | "status": { 63 | "type": "string" 64 | }, 65 | "updated": { 66 | "type": "string" 67 | }, 68 | "id": { 69 | "type": "string" 70 | }, 71 | "links": { 72 | "type": "array", 73 | "items": { 74 | "type": "object", 75 | "required": [ 76 | "href", 77 | "rel" 78 | ], 79 | "properties": { 80 | "href": { 81 | "type": "string" 82 | }, 83 | "rel": { 84 | "type": "string" 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | }, 95 | "300": { 96 | "description": "300 response", 97 | "schema": { 98 | "type": "object", 99 | "required": [ 100 | "versions" 101 | ], 102 | "properties": { 103 | "versions": { 104 | "type": "array", 105 | "items": { 106 | "type": "object", 107 | "required": [ 108 | "status", 109 | "id", 110 | "links" 111 | ], 112 | "properties": { 113 | "status": { 114 | "type": "string" 115 | }, 116 | "updated": { 117 | "type": "string" 118 | }, 119 | "id": { 120 | "type": "string" 121 | }, 122 | "links": { 123 | "type": "array", 124 | "items": { 125 | "type": "object", 126 | "required": [ 127 | "href", 128 | "rel" 129 | ], 130 | "properties": { 131 | "href": { 132 | "type": "string" 133 | }, 134 | "rel": { 135 | "type": "string" 136 | } 137 | } 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | } 148 | } 149 | }, 150 | "consumes": [ 151 | "application/json" 152 | ] 153 | } 154 | -------------------------------------------------------------------------------- /test/data/v2/valid-without-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "Simple API overview", 5 | "version": "v2" 6 | }, 7 | "paths": { 8 | "/": { 9 | "get": { 10 | "operationId": "listVersionsv2", 11 | "summary": "List API versions", 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "responses": { 16 | "200": { 17 | "description": "200 response", 18 | "examples": { 19 | "application/json": { 20 | "versions": [ 21 | { 22 | "status": "CURRENT", 23 | "updated": "2011-01-21T11:33:21Z", 24 | "id": "v2.0", 25 | "links": [ 26 | { 27 | "href": "http://127.0.0.1:8774/v2/", 28 | "rel": "self" 29 | } 30 | ] 31 | }, 32 | { 33 | "status": "EXPERIMENTAL", 34 | "updated": "2013-07-23T11:33:21Z", 35 | "id": "v3.0", 36 | "links": [ 37 | { 38 | "href": "http://127.0.0.1:8774/v3/", 39 | "rel": "self" 40 | } 41 | ] 42 | } 43 | ] 44 | } 45 | } 46 | }, 47 | "300": { 48 | "description": "300 response", 49 | "examples": { 50 | "application/json": { 51 | "versions": [ 52 | { 53 | "status": "CURRENT", 54 | "updated": "2011-01-21T11:33:21Z", 55 | "id": "v2.0", 56 | "links": [ 57 | { 58 | "href": "http://127.0.0.1:8774/v2/", 59 | "rel": "self" 60 | } 61 | ] 62 | }, 63 | { 64 | "status": "EXPERIMENTAL", 65 | "updated": "2013-07-23T11:33:21Z", 66 | "id": "v3.0", 67 | "links": [ 68 | { 69 | "href": "http://127.0.0.1:8774/v3/", 70 | "rel": "self" 71 | } 72 | ] 73 | } 74 | ] 75 | } 76 | }, 77 | "schema": { 78 | "type": "object", 79 | "required": [ 80 | "versions" 81 | ], 82 | "properties": { 83 | "versions": { 84 | "type": "array", 85 | "items": { 86 | "type": "object", 87 | "required": [ 88 | "status", 89 | "id", 90 | "links" 91 | ], 92 | "properties": { 93 | "status": { 94 | "type": "string" 95 | }, 96 | "updated": { 97 | "type": "string" 98 | }, 99 | "id": { 100 | "type": "string" 101 | }, 102 | "links": { 103 | "type": "array", 104 | "items": { 105 | "type": "object", 106 | "required": [ 107 | "href", 108 | "rel" 109 | ], 110 | "properties": { 111 | "href": { 112 | "type": "string" 113 | }, 114 | "rel": { 115 | "type": "string" 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | } 127 | } 128 | } 129 | }, 130 | "consumes": [ 131 | "application/json" 132 | ] 133 | } 134 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/errors-list.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must NOT have additional properties", 5 | "instancePath": "/0", 6 | "schemaPath": "#/items/additionalProperties", 7 | "keyword": "additionalProperties", 8 | "params": { 9 | "additionalProperty": "owner" 10 | }, 11 | "exampleFilePath": "/test/data/v3/additional-properties/example-list-with-additional-properties.json" 12 | }, 13 | { 14 | "type": "Validation", 15 | "message": "must NOT have additional properties", 16 | "instancePath": "/0", 17 | "schemaPath": "#/items/additionalProperties", 18 | "keyword": "additionalProperties", 19 | "params": { 20 | "additionalProperty": "age" 21 | }, 22 | "exampleFilePath": "/test/data/v3/additional-properties/example-list-with-additional-properties.json" 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/errors-map-external-examples.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must NOT have additional properties", 5 | "mapFilePath": "/test/data/v3/additional-properties/map-external-examples-with-additional-properties.json", 6 | "instancePath": "/0", 7 | "schemaPath": "#/items/additionalProperties", 8 | "keyword": "additionalProperties", 9 | "params": { 10 | "additionalProperty": "owner" 11 | }, 12 | "exampleFilePath": "test/data/v3/additional-properties/example-list-with-additional-properties.json" 13 | }, 14 | { 15 | "type": "Validation", 16 | "message": "must NOT have additional properties", 17 | "mapFilePath": "/test/data/v3/additional-properties/map-external-examples-with-additional-properties.json", 18 | "instancePath": "/0", 19 | "schemaPath": "#/items/additionalProperties", 20 | "keyword": "additionalProperties", 21 | "params": { 22 | "additionalProperty": "age" 23 | }, 24 | "exampleFilePath": "test/data/v3/additional-properties/example-list-with-additional-properties.json" 25 | }, 26 | { 27 | "type": "Validation", 28 | "message": "must NOT have additional properties", 29 | "mapFilePath": "/test/data/v3/additional-properties/map-external-examples-with-additional-properties.json", 30 | "instancePath": "", 31 | "schemaPath": "#/additionalProperties", 32 | "keyword": "additionalProperties", 33 | "params": { 34 | "additionalProperty": "owner" 35 | }, 36 | "exampleFilePath": "test/data/v3/additional-properties/example-single-with-additional-properties.json" 37 | }, 38 | { 39 | "type": "Validation", 40 | "message": "must NOT have additional properties", 41 | "mapFilePath": "/test/data/v3/additional-properties/map-external-examples-with-additional-properties.json", 42 | "instancePath": "", 43 | "schemaPath": "#/additionalProperties", 44 | "keyword": "additionalProperties", 45 | "params": { 46 | "additionalProperty": "age" 47 | }, 48 | "exampleFilePath": "test/data/v3/additional-properties/example-single-with-additional-properties.json" 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/errors-schema-invalid-with-examples.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must NOT have additional properties", 5 | "instancePath": "/0", 6 | "schemaPath": "#/items/additionalProperties", 7 | "keyword": "additionalProperties", 8 | "params": { 9 | "additionalProperty": "location" 10 | }, 11 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/response/value" 12 | }, 13 | { 14 | "type": "Validation", 15 | "message": "must NOT have additional properties", 16 | "instancePath": "/0/schema", 17 | "schemaPath": "#/items/properties/schema/additionalProperties", 18 | "keyword": "additionalProperties", 19 | "params": { 20 | "additionalProperty": "spec" 21 | }, 22 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/response/value" 23 | }, 24 | { 25 | "type": "Validation", 26 | "message": "must NOT have additional properties", 27 | "instancePath": "/0/schema/properties", 28 | "schemaPath": "#/items/properties/schema/properties/properties/additionalProperties", 29 | "keyword": "additionalProperties", 30 | "params": { 31 | "additionalProperty": "nickname" 32 | }, 33 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/response/value" 34 | }, 35 | { 36 | "type": "Validation", 37 | "message": "must NOT have additional properties", 38 | "instancePath": "/0/schema/properties/properties", 39 | "schemaPath": "#/items/properties/schema/properties/properties/properties/properties/additionalProperties", 40 | "keyword": "additionalProperties", 41 | "params": { 42 | "additionalProperty": "some" 43 | }, 44 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/response/value" 45 | }, 46 | { 47 | "type": "Validation", 48 | "message": "must NOT have additional properties", 49 | "instancePath": "", 50 | "schemaPath": "#/additionalProperties", 51 | "keyword": "additionalProperties", 52 | "params": { 53 | "additionalProperty": "age" 54 | }, 55 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/response/value" 56 | }, 57 | { 58 | "type": "Validation", 59 | "message": "must NOT have additional properties", 60 | "instancePath": "", 61 | "schemaPath": "#/additionalProperties", 62 | "keyword": "additionalProperties", 63 | "params": { 64 | "additionalProperty": "owner" 65 | }, 66 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/response/value" 67 | }, 68 | { 69 | "type": "Validation", 70 | "message": "must NOT have additional properties", 71 | "instancePath": "/schema", 72 | "schemaPath": "#/properties/schema/additionalProperties", 73 | "keyword": "additionalProperties", 74 | "params": { 75 | "additionalProperty": "spec" 76 | }, 77 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/response/value" 78 | }, 79 | { 80 | "type": "Validation", 81 | "message": "must NOT have additional properties", 82 | "instancePath": "/schema/properties", 83 | "schemaPath": "#/properties/schema/properties/properties/additionalProperties", 84 | "keyword": "additionalProperties", 85 | "params": { 86 | "additionalProperty": "callname" 87 | }, 88 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/response/value" 89 | }, 90 | { 91 | "type": "Validation", 92 | "message": "must NOT have additional properties", 93 | "instancePath": "/0/schema/properties/type", 94 | "schemaPath": "#/items/properties/schema/properties/properties/properties/type/additionalProperties", 95 | "keyword": "additionalProperties", 96 | "params": { 97 | "additionalProperty": "bar" 98 | }, 99 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/response/value" 100 | } 101 | ] 102 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/errors-schema-with-examples.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must NOT have additional properties", 5 | "instancePath": "", 6 | "schemaPath": "#/additionalProperties", 7 | "keyword": "additionalProperties", 8 | "params": { 9 | "additionalProperty": "owner" 10 | }, 11 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/example" 12 | }, 13 | { 14 | "type": "Validation", 15 | "message": "must NOT have additional properties", 16 | "instancePath": "/0", 17 | "schemaPath": "#/items/additionalProperties", 18 | "keyword": "additionalProperties", 19 | "params": { 20 | "additionalProperty": "owner" 21 | }, 22 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/single/value" 23 | }, 24 | { 25 | "type": "Validation", 26 | "message": "must NOT have additional properties", 27 | "instancePath": "/0", 28 | "schemaPath": "#/items/additionalProperties", 29 | "keyword": "additionalProperties", 30 | "params": { 31 | "additionalProperty": "age" 32 | }, 33 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/single/value" 34 | }, 35 | { 36 | "type": "Validation", 37 | "message": "must NOT have additional properties", 38 | "instancePath": "", 39 | "schemaPath": "#/additionalProperties", 40 | "keyword": "additionalProperties", 41 | "params": { 42 | "additionalProperty": "age" 43 | }, 44 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/example" 45 | } 46 | ] 47 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/errors-schema-with-schema-combiner-as-property.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must NOT have additional properties", 5 | "instancePath": "/allOf/anyOf/oneOf/not", 6 | "schemaPath": "#/properties/allOf/properties/anyOf/properties/oneOf/properties/not/additionalProperties", 7 | "keyword": "additionalProperties", 8 | "params": { 9 | "additionalProperty": "anotherProperty" 10 | }, 11 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/example" 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/errors-single.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must NOT have additional properties", 5 | "instancePath": "", 6 | "schemaPath": "#/additionalProperties", 7 | "keyword": "additionalProperties", 8 | "params": { 9 | "additionalProperty": "owner" 10 | }, 11 | "exampleFilePath": "/test/data/v3/additional-properties/example-single-with-additional-properties.json" 12 | }, 13 | { 14 | "type": "Validation", 15 | "message": "must NOT have additional properties", 16 | "instancePath": "", 17 | "schemaPath": "#/additionalProperties", 18 | "keyword": "additionalProperties", 19 | "params": { 20 | "additionalProperty": "age" 21 | }, 22 | "exampleFilePath": "/test/data/v3/additional-properties/example-single-with-additional-properties.json" 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/example-list-with-additional-properties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "name": "Herbert", 5 | "tag": "Doggo", 6 | "owner": "John", 7 | "age": 5, 8 | "schema": { 9 | "properties": { 10 | "color": "black" 11 | } 12 | } 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/example-single-with-additional-properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "name": "Herbert", 4 | "tag": "Doggo", 5 | "owner": "John", 6 | "age": 5, 7 | "schema": { 8 | "properties": { 9 | "color": "black" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/invalid-with-examples.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | license: 4 | name: MIT 5 | title: Swagger Petstore 6 | version: 1.0.0 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | responses: 13 | '200': 14 | content: 15 | application/json: 16 | examples: 17 | response: 18 | value: 19 | - location: home 20 | id: 1 21 | name: john 22 | schema: 23 | spec: pet_definition 24 | properties: 25 | nickname: buddy 26 | color: black 27 | properties: 28 | some: id 29 | foo: 5 30 | type: 31 | bar: baz 32 | schema: 33 | items: 34 | properties: 35 | id: 36 | type: number 37 | name: 38 | type: string 39 | schema: 40 | properties: 41 | properties: 42 | properties: 43 | color: 44 | type: string 45 | properties: 46 | properties: 47 | foo: 48 | type: number 49 | type: object 50 | type: 51 | type: object 52 | type: object 53 | type: object 54 | tag: 55 | type: string 56 | required: 57 | - id 58 | - name 59 | type: object 60 | type: array 61 | description: An array of pets 62 | default: 63 | content: 64 | application/json: 65 | schema: 66 | properties: 67 | code: 68 | type: number 69 | message: 70 | type: string 71 | required: 72 | - code 73 | - message 74 | type: object 75 | description: unexpected error 76 | operationId: listPets 77 | summary: List all pets 78 | post: 79 | responses: 80 | '201': 81 | description: Null response 82 | default: 83 | content: 84 | application/json: 85 | schema: 86 | properties: 87 | code: 88 | type: number 89 | message: 90 | type: string 91 | required: 92 | - code 93 | - message 94 | type: object 95 | description: unexpected error 96 | tags: 97 | - pets 98 | operationId: createPets 99 | summary: Create a pet 100 | '/pets/{petId}': 101 | get: 102 | parameters: 103 | - description: The id of the pet to retrieve 104 | in: path 105 | name: petId 106 | required: true 107 | schema: 108 | type: string 109 | responses: 110 | '200': 111 | content: 112 | application/json: 113 | examples: 114 | response: 115 | value: 116 | age: 5 117 | id: 0 118 | name: Herbert 119 | owner: John 120 | schema: 121 | spec: pet_definition 122 | properties: 123 | callname: buddy 124 | color: black 125 | tag: Doggo 126 | schema: 127 | properties: 128 | id: 129 | type: number 130 | name: 131 | type: string 132 | schema: 133 | properties: 134 | properties: 135 | properties: 136 | color: 137 | type: string 138 | type: object 139 | type: object 140 | tag: 141 | type: string 142 | required: 143 | - id 144 | - name 145 | type: object 146 | description: Expected response to a valid request 147 | default: 148 | content: 149 | application/json: 150 | schema: 151 | properties: 152 | code: 153 | type: number 154 | message: 155 | type: string 156 | required: 157 | - code 158 | - message 159 | type: object 160 | description: unexpected error 161 | operationId: showPetById 162 | summary: Info for a specific pet 163 | 164 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/map-external-examples-with-additional-properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "$.paths./pets.get.responses.200.content.application/json.schema": [ 3 | "test/data/v3/additional-properties/example-list-with-additional-properties.json" 4 | ], 5 | "$.paths./pets/{petId}.get.responses.200.content.application/json.schema": 6 | "test/data/v3/additional-properties/example-single-with-additional-properties.json" 7 | } 8 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/schema-with-examples.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | responses: 15 | '200': 16 | description: An array of pets 17 | content: 18 | application/json: 19 | schema: 20 | $ref: '#/components/schemas/Pets' 21 | examples: 22 | single: 23 | value: 24 | - id: 0 25 | name: Herbert 26 | tag: Doggo 27 | owner: John 28 | age: 5 29 | schema: 30 | properties: 31 | color: black 32 | default: 33 | description: unexpected error 34 | content: 35 | application/json: 36 | schema: 37 | $ref: '#/components/schemas/Error' 38 | post: 39 | summary: Create a pet 40 | operationId: createPets 41 | tags: 42 | - pets 43 | responses: 44 | '201': 45 | description: Null response 46 | default: 47 | description: unexpected error 48 | content: 49 | application/json: 50 | schema: 51 | $ref: '#/components/schemas/Error' 52 | '/pets/{petId}': 53 | get: 54 | summary: Info for a specific pet 55 | operationId: showPetById 56 | parameters: 57 | - name: petId 58 | in: path 59 | required: true 60 | description: The id of the pet to retrieve 61 | schema: 62 | type: string 63 | responses: 64 | '200': 65 | description: Expected response to a valid request 66 | content: 67 | application/json: 68 | schema: 69 | $ref: '#/components/schemas/Pet' 70 | example: 71 | id: 0 72 | name: Herbert 73 | tag: Doggo 74 | owner: John 75 | age: 5 76 | schema: 77 | properties: 78 | color: black 79 | default: 80 | description: unexpected error 81 | content: 82 | application/json: 83 | schema: 84 | $ref: '#/components/schemas/Error' 85 | components: 86 | schemas: 87 | Pet: 88 | required: 89 | - id 90 | - name 91 | type: object 92 | properties: 93 | id: 94 | type: number 95 | name: 96 | type: string 97 | tag: 98 | type: string 99 | # This intentionally is a property called `schema` 100 | schema: 101 | type: object 102 | properties: 103 | # This intentionally is a property called `properties` 104 | properties: 105 | type: object 106 | # This should not be extended with an `additionalProperties: false` 107 | properties: 108 | color: 109 | type: string 110 | 111 | Pets: 112 | type: array 113 | items: 114 | $ref: '#/components/schemas/Pet' 115 | Error: 116 | required: 117 | - code 118 | - message 119 | properties: 120 | code: 121 | type: number 122 | message: 123 | type: string 124 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/schema-with-schema-combiner-as-property-invalid.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | '/pets/{petId}': 11 | get: 12 | summary: Info for a specific pet 13 | operationId: showPetById 14 | parameters: 15 | - name: petId 16 | in: path 17 | required: true 18 | description: The id of the pet to retrieve 19 | schema: 20 | type: string 21 | responses: 22 | '200': 23 | description: Expected response to a valid request 24 | content: 25 | application/json: 26 | schema: 27 | $ref: '#/components/schemas/Pet' 28 | example: 29 | id: 0 30 | name: Marco 31 | allOf: 32 | anyOf: 33 | oneOf: 34 | not: 35 | color: black 36 | anotherProperty: 'This property will be marked as error in case of --no-additional-properties' 37 | default: 38 | description: unexpected error 39 | content: 40 | application/json: 41 | schema: 42 | $ref: '#/components/schemas/Error' 43 | components: 44 | schemas: 45 | Pet: 46 | required: 47 | - id 48 | - name 49 | type: object 50 | properties: 51 | id: 52 | type: number 53 | name: 54 | type: string 55 | # This intentionally is a property called `allOf` 56 | allOf: 57 | type: object 58 | properties: 59 | # This intentionally is a property called `anyOf` 60 | anyOf: 61 | type: object 62 | properties: 63 | # This intentionally is a property called `oneOf` 64 | oneOf: 65 | type: object 66 | properties: 67 | # This intentionally is a property called `not` 68 | not: 69 | # This should be extended with an `additionalProperties: false` 70 | type: object 71 | properties: 72 | color: 73 | type: string 74 | Error: 75 | required: 76 | - code 77 | - message 78 | properties: 79 | code: 80 | type: number 81 | message: 82 | type: string 83 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/schema-with-schema-combiner-invalid.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | '/pets/{petId}': 11 | get: 12 | summary: Info for a specific pet 13 | operationId: showPetById 14 | parameters: 15 | - name: petId 16 | in: path 17 | required: true 18 | description: The id of the pet to retrieve 19 | schema: 20 | type: string 21 | responses: 22 | '200': 23 | description: successful response 24 | content: 25 | application/json: 26 | schema: 27 | oneOf: 28 | - $ref: '#/components/schemas/Bird' 29 | - $ref: '#/components/schemas/Cat' 30 | - $ref: '#/components/schemas/Dog' 31 | examples: 32 | 'Dog example': 33 | value: 34 | name: 'Dog 1' 35 | bark: true 36 | breed: 'Dingo' 37 | 'Cat example': 38 | value: 39 | name: 'Cat 1' 40 | hunts: true 41 | age: 3 42 | 'Bird example': 43 | value: 44 | name: 'Birb' 45 | sizeWings: 'smol' 46 | '404': 47 | description: unexpected error 48 | content: 49 | application/json: 50 | schema: 51 | $ref: '#/components/schemas/Error' 52 | example: 53 | code: 1000 54 | message: 'could not find pet' 55 | extra_property: 'test' # not allowed and outside of JSON schema combiner, should be picked up 56 | components: 57 | schemas: 58 | Error: 59 | type: object 60 | properties: 61 | code: 62 | type: number 63 | message: 64 | type: string 65 | Pet: 66 | type: object 67 | required: 68 | - name 69 | properties: 70 | name: 71 | type: string 72 | Dog: 73 | allOf: 74 | - $ref: '#/components/schemas/Pet' 75 | - type: object 76 | required: 77 | - bark 78 | - breed 79 | properties: 80 | bark: 81 | type: boolean 82 | breed: 83 | type: string 84 | enum: [ Dingo, Husky, Retriever, Shepherd ] 85 | Cat: 86 | allOf: 87 | - $ref: '#/components/schemas/Pet' 88 | - type: object 89 | required: 90 | - hunts 91 | - age 92 | properties: 93 | hunts: 94 | type: boolean 95 | age: 96 | type: integer 97 | Bird: 98 | anyOf: 99 | - type: object 100 | required: 101 | - name 102 | - sizeWings 103 | properties: 104 | name: 105 | type: string 106 | sizeWings: 107 | type: string 108 | - type: object 109 | required: 110 | - name 111 | - eggSize 112 | properties: 113 | name: 114 | type: string 115 | sizeEggs: 116 | type: string 117 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/schema-with-schema-combiner-valid.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | '/pets/{petId}': 11 | get: 12 | summary: Info for a specific pet 13 | operationId: showPetById 14 | parameters: 15 | - name: petId 16 | in: path 17 | required: true 18 | description: The id of the pet to retrieve 19 | schema: 20 | type: string 21 | responses: 22 | '200': 23 | description: successful response 24 | content: 25 | application/json: 26 | schema: 27 | oneOf: 28 | - $ref: '#/components/schemas/Cat' 29 | - $ref: '#/components/schemas/Dog' 30 | examples: 31 | 'Dog example': 32 | value: 33 | name: 'Dog 1' 34 | bark: true 35 | breed: 'Dingo' 36 | 'Cat example': 37 | value: 38 | name: 'Cat 1' 39 | hunts: true 40 | age: 3 41 | '404': 42 | description: unexpected error 43 | content: 44 | application/json: 45 | schema: 46 | $ref: '#/components/schemas/Error' 47 | example: 48 | code: 1000 49 | message: 'could not find pet' 50 | components: 51 | schemas: 52 | Error: 53 | type: object 54 | properties: 55 | code: 56 | type: number 57 | message: 58 | type: string 59 | Pet: 60 | type: object 61 | required: 62 | - name 63 | properties: 64 | name: 65 | type: string 66 | Dog: 67 | allOf: 68 | - $ref: '#/components/schemas/Pet' 69 | - type: object 70 | required: 71 | - bark 72 | - breed 73 | properties: 74 | bark: 75 | type: boolean 76 | breed: 77 | type: string 78 | enum: [ Dingo, Husky, Retriever, Shepherd ] 79 | Cat: 80 | allOf: 81 | - $ref: '#/components/schemas/Pet' 82 | - type: object 83 | required: 84 | - hunts 85 | - age 86 | properties: 87 | hunts: 88 | type: boolean 89 | age: 90 | type: integer 91 | -------------------------------------------------------------------------------- /test/data/v3/additional-properties/schema.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | responses: 15 | '200': 16 | description: An array of pets 17 | content: 18 | application/json: 19 | schema: 20 | $ref: '#/components/schemas/Pets' 21 | default: 22 | description: unexpected error 23 | content: 24 | application/json: 25 | schema: 26 | $ref: '#/components/schemas/Error' 27 | post: 28 | summary: Create a pet 29 | operationId: createPets 30 | tags: 31 | - pets 32 | responses: 33 | '201': 34 | description: Null response 35 | default: 36 | description: unexpected error 37 | content: 38 | application/json: 39 | schema: 40 | $ref: '#/components/schemas/Error' 41 | '/pets/{petId}': 42 | get: 43 | summary: Info for a specific pet 44 | operationId: showPetById 45 | parameters: 46 | - name: petId 47 | in: path 48 | required: true 49 | description: The id of the pet to retrieve 50 | schema: 51 | type: string 52 | responses: 53 | '200': 54 | description: Expected response to a valid request 55 | content: 56 | application/json: 57 | schema: 58 | $ref: '#/components/schemas/Pet' 59 | default: 60 | description: unexpected error 61 | content: 62 | application/json: 63 | schema: 64 | $ref: '#/components/schemas/Error' 65 | components: 66 | schemas: 67 | Pet: 68 | required: 69 | - id 70 | - name 71 | type: object 72 | properties: 73 | id: 74 | type: number 75 | name: 76 | type: string 77 | tag: 78 | type: string 79 | # This intentionally is a property called `schema` 80 | schema: 81 | type: object 82 | properties: 83 | # This intentionally is a property called `properties` 84 | properties: 85 | type: object 86 | # This should not be extended with an `additionalProperties: false` 87 | properties: 88 | color: 89 | type: string 90 | 91 | Pets: 92 | type: array 93 | items: 94 | $ref: '#/components/schemas/Pet' 95 | Error: 96 | required: 97 | - code 98 | - message 99 | properties: 100 | code: 101 | type: number 102 | message: 103 | type: string 104 | -------------------------------------------------------------------------------- /test/data/v3/all-properties-required/errors-schema-with-examples.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must have required property 'age'", 5 | "instancePath": "", 6 | "schemaPath": "#/oneOf/0/allOf/1/required", 7 | "keyword": "required", 8 | "params": { 9 | "missingProperty": "age" 10 | }, 11 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value" 12 | }, 13 | { 14 | "type": "Validation", 15 | "message": "must have required property 'bark'", 16 | "instancePath": "", 17 | "schemaPath": "#/oneOf/1/allOf/1/required", 18 | "keyword": "required", 19 | "params": { 20 | "missingProperty": "bark" 21 | }, 22 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value" 23 | }, 24 | { 25 | "type": "Validation", 26 | "message": "must have required property 'breed'", 27 | "instancePath": "", 28 | "schemaPath": "#/oneOf/1/allOf/1/required", 29 | "keyword": "required", 30 | "params": { 31 | "missingProperty": "breed" 32 | }, 33 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value" 34 | }, 35 | { 36 | "type": "Validation", 37 | "message": "must match exactly one schema in oneOf", 38 | "instancePath": "", 39 | "schemaPath": "#/oneOf", 40 | "keyword": "oneOf", 41 | "params": { 42 | "passingSchemas": null 43 | }, 44 | "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value" 45 | } 46 | ] 47 | -------------------------------------------------------------------------------- /test/data/v3/all-properties-required/schema-with-examples.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | '/pets/{petId}': 11 | get: 12 | summary: Info for a specific pet 13 | operationId: showPetById 14 | parameters: 15 | - name: petId 16 | in: path 17 | required: true 18 | description: The id of the pet to retrieve 19 | schema: 20 | type: string 21 | responses: 22 | '200': 23 | description: successful response 24 | content: 25 | application/json: 26 | schema: 27 | oneOf: 28 | - $ref: '#/components/schemas/Cat' 29 | - $ref: '#/components/schemas/Dog' 30 | examples: 31 | 'Dog example': 32 | value: 33 | name: 'Dog 1' 34 | bark: true 35 | breed: 'Dingo' 36 | 'Cat example': 37 | value: 38 | name: 'Cat 1' 39 | hunts: true 40 | # This example don't have the optional property 'age' 41 | '404': 42 | description: unexpected error 43 | content: 44 | application/json: 45 | schema: 46 | $ref: '#/components/schemas/Error' 47 | example: 48 | code: 1000 49 | message: 'could not find pet' 50 | components: 51 | schemas: 52 | Error: 53 | type: object 54 | properties: 55 | code: 56 | type: number 57 | message: 58 | type: string 59 | Pet: 60 | type: object 61 | required: 62 | - name 63 | properties: 64 | name: 65 | type: string 66 | Dog: 67 | allOf: 68 | - $ref: '#/components/schemas/Pet' 69 | - type: object 70 | required: 71 | - bark 72 | - breed 73 | properties: 74 | bark: 75 | type: boolean 76 | breed: 77 | type: string 78 | enum: [ Dingo, Husky, Retriever, Shepherd ] 79 | Cat: 80 | allOf: 81 | - $ref: '#/components/schemas/Pet' 82 | - type: object 83 | required: 84 | - hunts 85 | properties: 86 | hunts: 87 | type: boolean 88 | age: 89 | type: integer 90 | -------------------------------------------------------------------------------- /test/data/v3/draft-04-properties/errors-exclusive-minimum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "instancePath": "/code", 4 | "examplePath": "/paths/~1pets/get/responses/default/content/application~1json/example", 5 | "keyword": "minimum", 6 | "message": "must be > 10", 7 | "params": { 8 | "comparison": ">", 9 | "limit": 10 10 | }, 11 | "schemaPath": "#/properties/code/minimum", 12 | "type": "Validation" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /test/data/v3/errors/simple-api-with-example-names-to-be-escaped.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "Validation", 4 | "message": "must be number", 5 | "keyword": "type", 6 | "instancePath": "/0/id", 7 | "schemaPath": "#/items/properties/id/type", 8 | "params": { 9 | "type": "number" 10 | }, 11 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/`mrcat/value" 12 | }, 13 | { 14 | "type": "Validation", 15 | "message": "must be number", 16 | "keyword": "type", 17 | "instancePath": "/0/id", 18 | "schemaPath": "#/items/properties/id/type", 19 | "params": { 20 | "type": "number" 21 | }, 22 | "examplePath": "/paths/~1pets/get/responses/200/content/application~1json/examples/herbert,doggo/value" 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /test/data/v3/null-values/schema-with-null-property.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "paths": { 4 | "/test": { 5 | "get": { 6 | "responses": { 7 | "200": { 8 | "content": { 9 | "application/json": { 10 | "schema": { 11 | "type": "object", 12 | "properties": { 13 | "status": { 14 | "enum": [ 15 | "active", 16 | "inactive", 17 | null 18 | ], 19 | "type": "string", 20 | "nullable": true, 21 | "description": "The status of the item" 22 | } 23 | }, 24 | "required": [ 25 | "status" 26 | ] 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/data/v3/request-invalid-parameter.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "post": { 18 | "summary": "Create a pet", 19 | "operationId": "createPets", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "requestBody": { 24 | "description": "Pet data", 25 | "content": { 26 | "application/json": { 27 | "schema": { 28 | "required": [ 29 | "name", 30 | "tag" 31 | ], 32 | "properties": { 33 | "name": { 34 | "description": "Name of the pet", 35 | "type": "string" 36 | }, 37 | "tag": { 38 | "description": "Category of pet", 39 | "type": "string" 40 | } 41 | } 42 | } 43 | } 44 | } 45 | }, 46 | "responses": { 47 | "201": { 48 | "description": "Created pet", 49 | "content": { 50 | "application/json": { 51 | "schema": { 52 | "required": [ 53 | "id", 54 | "name", 55 | "tag" 56 | ], 57 | "properties": { 58 | "id": { 59 | "description": "Unique ID", 60 | "type": "number" 61 | }, 62 | "name": { 63 | "description": "Name of the pet", 64 | "type": "string" 65 | }, 66 | "tag": { 67 | "description": "Category of pet", 68 | "type": "string" 69 | } 70 | } 71 | } 72 | } 73 | } 74 | }, 75 | "default": { 76 | "description": "unexpected error", 77 | "content": { 78 | "application/json": { 79 | "schema": { 80 | "required": [ 81 | "code", 82 | "message" 83 | ], 84 | "properties": { 85 | "code": { 86 | "type": "number" 87 | }, 88 | "message": { 89 | "type": "string" 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "/pets/{petId}": { 100 | "get": { 101 | "summary": "Info for a specific pet", 102 | "operationId": "showPetById", 103 | "tags": [ 104 | "pets" 105 | ], 106 | "parameters": [ 107 | { 108 | "name": "petId", 109 | "in": "path", 110 | "required": true, 111 | "description": "The id of the pet to retrieve", 112 | "schema": { 113 | "type": "number" 114 | }, 115 | "example": "Lassie" 116 | } 117 | ], 118 | "responses": { 119 | "200": { 120 | "description": "Expected response to a valid request", 121 | "content": { 122 | "application/json": { 123 | "schema": { 124 | "type": "array", 125 | "items": { 126 | "required": [ 127 | "id", 128 | "name" 129 | ], 130 | "properties": { 131 | "id": { 132 | "type": "number" 133 | }, 134 | "name": { 135 | "type": "string" 136 | }, 137 | "tag": { 138 | "type": "string" 139 | } 140 | } 141 | } 142 | } 143 | } 144 | } 145 | }, 146 | "default": { 147 | "description": "unexpected error", 148 | "content": { 149 | "application/json": { 150 | "schema": { 151 | "required": [ 152 | "code", 153 | "message" 154 | ], 155 | "properties": { 156 | "code": { 157 | "type": "number" 158 | }, 159 | "message": { 160 | "type": "string" 161 | } 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | } 170 | } 171 | } -------------------------------------------------------------------------------- /test/data/v3/request-valid-parameter.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "post": { 18 | "summary": "Create a pet", 19 | "operationId": "createPets", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "requestBody": { 24 | "description": "Pet data", 25 | "content": { 26 | "application/json": { 27 | "schema": { 28 | "required": [ 29 | "name", 30 | "tag" 31 | ], 32 | "properties": { 33 | "name": { 34 | "description": "Name of the pet", 35 | "type": "string" 36 | }, 37 | "tag": { 38 | "description": "Category of pet", 39 | "type": "string" 40 | } 41 | } 42 | } 43 | } 44 | } 45 | }, 46 | "responses": { 47 | "201": { 48 | "description": "Created pet", 49 | "content": { 50 | "application/json": { 51 | "schema": { 52 | "required": [ 53 | "id", 54 | "name", 55 | "tag" 56 | ], 57 | "properties": { 58 | "id": { 59 | "description": "Unique ID", 60 | "type": "number" 61 | }, 62 | "name": { 63 | "description": "Name of the pet", 64 | "type": "string" 65 | }, 66 | "tag": { 67 | "description": "Category of pet", 68 | "type": "string" 69 | } 70 | } 71 | } 72 | } 73 | } 74 | }, 75 | "default": { 76 | "description": "unexpected error", 77 | "content": { 78 | "application/json": { 79 | "schema": { 80 | "required": [ 81 | "code", 82 | "message" 83 | ], 84 | "properties": { 85 | "code": { 86 | "type": "number" 87 | }, 88 | "message": { 89 | "type": "string" 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "/pets/{petId}": { 100 | "get": { 101 | "summary": "Info for a specific pet", 102 | "operationId": "showPetById", 103 | "tags": [ 104 | "pets" 105 | ], 106 | "parameters": [ 107 | { 108 | "name": "petId", 109 | "in": "path", 110 | "required": true, 111 | "description": "The id of the pet to retrieve", 112 | "schema": { 113 | "type": "number" 114 | }, 115 | "example": 5 116 | } 117 | ], 118 | "responses": { 119 | "200": { 120 | "description": "Expected response to a valid request", 121 | "content": { 122 | "application/json": { 123 | "schema": { 124 | "type": "array", 125 | "items": { 126 | "required": [ 127 | "id", 128 | "name" 129 | ], 130 | "properties": { 131 | "id": { 132 | "type": "number" 133 | }, 134 | "name": { 135 | "type": "string" 136 | }, 137 | "tag": { 138 | "type": "string" 139 | } 140 | } 141 | } 142 | } 143 | } 144 | } 145 | }, 146 | "default": { 147 | "description": "unexpected error", 148 | "content": { 149 | "application/json": { 150 | "schema": { 151 | "required": [ 152 | "code", 153 | "message" 154 | ], 155 | "properties": { 156 | "code": { 157 | "type": "number" 158 | }, 159 | "message": { 160 | "type": "string" 161 | } 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | } 170 | } 171 | } -------------------------------------------------------------------------------- /test/data/v3/response-invalid-date-time-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Sample number formats", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://example.com/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/get-numbers": { 17 | "get": { 18 | "summary": "Gets some big numbers", 19 | "operationId": "getNumbers", 20 | "responses": { 21 | "200": { 22 | "description": "Some big numbers", 23 | "content": { 24 | "application/json": { 25 | "schema": { 26 | "type": "object", 27 | "properties": { 28 | "date": { 29 | "type": "string", 30 | "format": "date-time" 31 | } 32 | } 33 | }, 34 | "example": { 35 | "date": "42" 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/data/v3/response-invalid-number-formats.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Sample number formats", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://example.com/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/get-numbers": { 17 | "get": { 18 | "summary": "Gets some big numbers", 19 | "operationId": "getNumbers", 20 | "responses": { 21 | "200": { 22 | "description": "Some big numbers", 23 | "content": { 24 | "application/json": { 25 | "schema": { 26 | "type": "object", 27 | "properties": { 28 | "number": { 29 | "type": "number" 30 | }, 31 | "int32": { 32 | "type": "number", 33 | "format": "int32" 34 | }, 35 | "int64": { 36 | "type": "number", 37 | "format": "int64" 38 | }, 39 | "float": { 40 | "type": "number", 41 | "format": "float" 42 | }, 43 | "double": { 44 | "type": "number", 45 | "format": "double" 46 | } 47 | } 48 | }, 49 | "example": { 50 | "number": "42", 51 | "int32": 21474836470, 52 | "int64": 92233720368547.75807, 53 | "float": "3.402823466", 54 | "double": "1.797693134" 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/data/v3/response-invalid-requestbody-inheritance-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.2", 3 | "info": { 4 | "title": "petstore Inheritance", 5 | "version": "1.0.7" 6 | }, 7 | "paths": { 8 | "/pet": { 9 | "post": { 10 | "tags": [ 11 | "pet" 12 | ], 13 | "summary": "Add a new pet to the store", 14 | "description": "Add a new pet to the store", 15 | "operationId": "addPet", 16 | "requestBody": { 17 | "description": "Create a new pet in the store", 18 | "content": { 19 | "application/json": { 20 | "schema": { 21 | "$ref": "#/components/schemas/Pet" 22 | }, 23 | "examples": { 24 | "dog": { 25 | "value": { 26 | "name": "12", 27 | "catName": 123, 28 | "type": "CAT" 29 | } 30 | }, 31 | "fish": { 32 | "value": { 33 | "name": "fish_01", 34 | "fishName": "Nemo", 35 | "type": "FISH" 36 | } 37 | } 38 | } 39 | } 40 | }, 41 | "required": true 42 | }, 43 | "responses": { 44 | "200": { 45 | "description": "Successful operation", 46 | "content": { 47 | "application/json": { 48 | "schema": { 49 | "$ref": "#/components/schemas/Pet" 50 | } 51 | } 52 | } 53 | }, 54 | "405": { 55 | "description": "Invalid input" 56 | } 57 | } 58 | } 59 | } 60 | }, 61 | "components": { 62 | "schemas": { 63 | "Dog": { 64 | "type": "object", 65 | "required": [ 66 | "dogName" 67 | ], 68 | "properties": { 69 | "dogName": { 70 | "type": "string" 71 | }, 72 | "type": { 73 | "type": "string", 74 | "enum": [ 75 | "DOG" 76 | ] 77 | } 78 | } 79 | }, 80 | "Cat": { 81 | "type": "object", 82 | "required": [ 83 | "dogName" 84 | ], 85 | "properties": { 86 | "catName": { 87 | "type": "string" 88 | }, 89 | "type": { 90 | "type": "string", 91 | "enum": [ 92 | "CAT" 93 | ] 94 | } 95 | } 96 | }, 97 | "Pet": { 98 | "required": [ 99 | "name", 100 | "type" 101 | ], 102 | "type": "object", 103 | "properties": { 104 | "id": { 105 | "type": "integer", 106 | "format": "int64", 107 | "example": 10 108 | }, 109 | "name": { 110 | "type": "string", 111 | "example": "doggie" 112 | }, 113 | "type": { 114 | "type": "string" 115 | } 116 | }, 117 | "discriminator": { 118 | "propertyName": "type" 119 | }, 120 | "oneOf": [ 121 | { 122 | "$ref": "#/components/schemas/Cat" 123 | }, 124 | { 125 | "$ref": "#/components/schemas/Dog" 126 | } 127 | ] 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /test/data/v3/response-valid-content-array.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.2 2 | components: 3 | paths: 4 | metrics: 5 | get: 6 | summary: Get info 7 | operationId: "get_info" 8 | description: | 9 | This API hook returns server metrics. 10 | responses: 11 | '200': 12 | description: OK 13 | content: 14 | application/json: 15 | schema: 16 | type: object 17 | properties: 18 | content: 19 | type: array 20 | description: Array of valid entries 21 | items: 22 | type: object 23 | properties: 24 | type: 25 | type: integer 26 | description: RR type of entry 27 | examples: 28 | metrics: 29 | summary: Server metrics 30 | value: 31 | content: 32 | - type: 0 33 | -------------------------------------------------------------------------------- /test/data/v3/response-valid-date-time-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Sample number formats", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://example.com/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/get-numbers": { 17 | "get": { 18 | "summary": "Gets some big numbers", 19 | "operationId": "getNumbers", 20 | "responses": { 21 | "200": { 22 | "description": "Some big numbers", 23 | "content": { 24 | "application/json": { 25 | "schema": { 26 | "type": "object", 27 | "properties": { 28 | "date": { 29 | "type": "string", 30 | "format": "date-time" 31 | } 32 | } 33 | }, 34 | "example": { 35 | "date": "2017-07-21T17:32:28Z" 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/data/v3/response-valid-number-formats.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Sample number formats", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://example.com/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/get-numbers": { 17 | "get": { 18 | "summary": "Gets some big numbers", 19 | "operationId": "getNumbers", 20 | "responses": { 21 | "200": { 22 | "description": "Some big numbers", 23 | "content": { 24 | "application/json": { 25 | "schema": { 26 | "type": "object", 27 | "properties": { 28 | "number": { 29 | "type": "number" 30 | }, 31 | "int32": { 32 | "type": "number", 33 | "format": "int32" 34 | }, 35 | "int64": { 36 | "type": "string", 37 | "format": "int64" 38 | }, 39 | "float": { 40 | "type": "number", 41 | "format": "float" 42 | }, 43 | "double": { 44 | "type": "number", 45 | "format": "double" 46 | } 47 | } 48 | }, 49 | "example": { 50 | "number": 42, 51 | "int32": 2147483647, 52 | "int64": "9223372036854775807", 53 | "float": 3.4028234664e38, 54 | "double": 1.7976931348623157e308 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/data/v3/response-valid-requestbody-inheritance-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.2", 3 | "info": { 4 | "title": "petstore Inheritance", 5 | "version": "1.0.7" 6 | }, 7 | "paths": { 8 | "/pet": { 9 | "post": { 10 | "tags": [ 11 | "pet" 12 | ], 13 | "summary": "Add a new pet to the store", 14 | "description": "Add a new pet to the store", 15 | "operationId": "addPet", 16 | "requestBody": { 17 | "description": "Create a new pet in the store", 18 | "content": { 19 | "application/json": { 20 | "schema": { 21 | "$ref": "#/components/schemas/Pet" 22 | }, 23 | "examples": { 24 | "dog": { 25 | "value": { 26 | "name": "12", 27 | "catName": "123", 28 | "type": "CAT" 29 | } 30 | } 31 | } 32 | } 33 | }, 34 | "required": true 35 | }, 36 | "responses": { 37 | "200": { 38 | "description": "Successful operation", 39 | "content": { 40 | "application/json": { 41 | "schema": { 42 | "$ref": "#/components/schemas/Pet" 43 | } 44 | } 45 | } 46 | }, 47 | "405": { 48 | "description": "Invalid input" 49 | } 50 | } 51 | } 52 | } 53 | }, 54 | "components": { 55 | "schemas": { 56 | "Dog": { 57 | "type": "object", 58 | "properties": { 59 | "dogName": { 60 | "type": "string" 61 | }, 62 | "type": { 63 | "type": "string", 64 | "enum": [ 65 | "DOG" 66 | ] 67 | } 68 | } 69 | }, 70 | "Cat": { 71 | "type": "object", 72 | "properties": { 73 | "catName": { 74 | "type": "string" 75 | }, 76 | "type": { 77 | "type": "string", 78 | "enum": [ 79 | "CAT" 80 | ] 81 | } 82 | } 83 | }, 84 | "Pet": { 85 | "required": [ 86 | "name", 87 | "type" 88 | ], 89 | "type": "object", 90 | "properties": { 91 | "id": { 92 | "type": "integer", 93 | "format": "int64", 94 | "example": 10 95 | }, 96 | "name": { 97 | "type": "string", 98 | "example": "doggie" 99 | }, 100 | "type": { 101 | "type": "string" 102 | } 103 | }, 104 | "discriminator": { 105 | "propertyName": "type" 106 | }, 107 | "oneOf": [ 108 | { 109 | "$ref": "#/components/schemas/Cat" 110 | }, 111 | { 112 | "$ref": "#/components/schemas/Dog" 113 | } 114 | ] 115 | } 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-example-names-to-be-escaped.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "get": { 18 | "summary": "List all pets", 19 | "operationId": "listPets", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "parameters": [ 24 | { 25 | "name": "limit", 26 | "in": "query", 27 | "description": "How many items to return at one time (max 100)", 28 | "required": false, 29 | "schema": { 30 | "type": "number" 31 | } 32 | } 33 | ], 34 | "responses": { 35 | "200": { 36 | "description": "An paged array of pets", 37 | "headers": { 38 | "x-next": { 39 | "description": "A link to the next page of responses", 40 | "schema": { 41 | "type": "string" 42 | } 43 | } 44 | }, 45 | "content": { 46 | "application/json": { 47 | "schema": { 48 | "type": "array", 49 | "items": { 50 | "required": [ 51 | "id", 52 | "name" 53 | ], 54 | "properties": { 55 | "id": { 56 | "type": "number" 57 | }, 58 | "name": { 59 | "type": "string" 60 | }, 61 | "tag": { 62 | "type": "string" 63 | } 64 | } 65 | } 66 | }, 67 | "examples": { 68 | "herbert,doggo": { 69 | "value": [ 70 | { 71 | "id": "invalid-id", 72 | "name": "Herbert", 73 | "tag": "Doggo" 74 | } 75 | ] 76 | }, 77 | "`mrcat": { 78 | "value": [ 79 | { 80 | "id": "invalid-id", 81 | "name": "`mrcat", 82 | "tag": "Kitty" 83 | } 84 | ] 85 | } 86 | } 87 | } 88 | } 89 | }, 90 | "default": { 91 | "description": "unexpected error", 92 | "content": { 93 | "application/json": { 94 | "schema": { 95 | "required": [ 96 | "code", 97 | "message" 98 | ], 99 | "properties": { 100 | "code": { 101 | "type": "number" 102 | }, 103 | "message": { 104 | "type": "string" 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-example-with-refs-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "get": { 18 | "summary": "List all pets", 19 | "operationId": "listPets", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "parameters": [ 24 | { 25 | "name": "limit", 26 | "in": "query", 27 | "description": "How many items to return at one time (max 100)", 28 | "required": false, 29 | "schema": { 30 | "type": "number" 31 | } 32 | } 33 | ], 34 | "responses": { 35 | "200": { 36 | "description": "An paged array of pets", 37 | "headers": { 38 | "x-next": { 39 | "description": "A link to the next page of responses", 40 | "schema": { 41 | "type": "string" 42 | } 43 | } 44 | }, 45 | "content": { 46 | "application/json": { 47 | "schema": { 48 | "$ref": "#/components/schemas/Pets" 49 | }, 50 | "example": [ 51 | { 52 | "id": "0", 53 | "tag": 5 54 | } 55 | ] 56 | } 57 | } 58 | }, 59 | "default": { 60 | "description": "unexpected error", 61 | "content": { 62 | "application/json": { 63 | "schema": { 64 | "$ref": "#/components/schemas/Error" 65 | } 66 | } 67 | } 68 | } 69 | } 70 | }, 71 | "post": { 72 | "summary": "Create a pet", 73 | "operationId": "createPets", 74 | "tags": [ 75 | "pets" 76 | ], 77 | "responses": { 78 | "201": { 79 | "description": "Null response" 80 | }, 81 | "default": { 82 | "description": "unexpected error", 83 | "content": { 84 | "application/json": { 85 | "schema": { 86 | "$ref": "#/components/schemas/Error" 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | }, 94 | "/pets/{petId}": { 95 | "get": { 96 | "summary": "Info for a specific pet", 97 | "operationId": "showPetById", 98 | "tags": [ 99 | "pets" 100 | ], 101 | "parameters": [ 102 | { 103 | "name": "petId", 104 | "in": "path", 105 | "required": true, 106 | "description": "The id of the pet to retrieve", 107 | "schema": { 108 | "type": "string" 109 | } 110 | } 111 | ], 112 | "responses": { 113 | "200": { 114 | "description": "Expected response to a valid request", 115 | "content": { 116 | "application/json": { 117 | "schema": { 118 | "$ref": "#/components/schemas/Pets" 119 | } 120 | } 121 | } 122 | }, 123 | "default": { 124 | "description": "unexpected error", 125 | "content": { 126 | "application/json": { 127 | "schema": { 128 | "$ref": "#/components/schemas/Error" 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | }, 137 | "components": { 138 | "schemas": { 139 | "Pet": { 140 | "required": [ 141 | "id", 142 | "name" 143 | ], 144 | "properties": { 145 | "id": { 146 | "type": "number" 147 | }, 148 | "name": { 149 | "type": "string" 150 | }, 151 | "tag": { 152 | "type": "string" 153 | } 154 | } 155 | }, 156 | "Pets": { 157 | "type": "array", 158 | "items": { 159 | "$ref": "#/components/schemas/Pet" 160 | } 161 | }, 162 | "Error": { 163 | "required": [ 164 | "code", 165 | "message" 166 | ], 167 | "properties": { 168 | "code": { 169 | "type": "number" 170 | }, 171 | "message": { 172 | "type": "string" 173 | } 174 | } 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-exclusive-minimum-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "get": { 18 | "summary": "Info for a specific pet", 19 | "operationId": "showPetById", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "parameters": [ 24 | { 25 | "name": "petId", 26 | "in": "path", 27 | "required": true, 28 | "description": "The id of the pet to retrieve", 29 | "schema": { 30 | "type": "string" 31 | } 32 | } 33 | ], 34 | "responses": { 35 | "default": { 36 | "description": "unexpected error", 37 | "content": { 38 | "application/json": { 39 | "schema": { 40 | "$ref": "#/components/schemas/Error" 41 | }, 42 | "example": { 43 | "code": 10, 44 | "message": "An unexpected error has occurred." 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | }, 53 | "components": { 54 | "schemas": { 55 | "Error": { 56 | "required": [ 57 | "code", 58 | "message" 59 | ], 60 | "properties": { 61 | "code": { 62 | "type": "number", 63 | "minimum": 10, 64 | "exclusiveMinimum": true 65 | }, 66 | "message": { 67 | "type": "string" 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-exclusive-minimum.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "get": { 18 | "summary": "Info for a specific pet", 19 | "operationId": "showPetById", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "parameters": [ 24 | { 25 | "name": "petId", 26 | "in": "path", 27 | "required": true, 28 | "description": "The id of the pet to retrieve", 29 | "schema": { 30 | "type": "string" 31 | } 32 | } 33 | ], 34 | "responses": { 35 | "default": { 36 | "description": "unexpected error", 37 | "content": { 38 | "application/json": { 39 | "schema": { 40 | "$ref": "#/components/schemas/Error" 41 | }, 42 | "example": { 43 | "code": 10, 44 | "message": "An unexpected error has occurred." 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | }, 53 | "components": { 54 | "schemas": { 55 | "Error": { 56 | "required": [ 57 | "code", 58 | "message" 59 | ], 60 | "properties": { 61 | "code": { 62 | "type": "number", 63 | "minimum": 10, 64 | "exclusiveMinimum": false 65 | }, 66 | "message": { 67 | "type": "string" 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-invalid-indentation.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | tags: 15 | - pets 16 | parameters: 17 | - name: limit 18 | in: query 19 | description: How many items to return at one time (max 100) 20 | required: false 21 | schema: 22 | type: number 23 | responses: 24 | '200': 25 | description: An paged array of pets 26 | headers: 27 | x-next: 28 | description: A link to the next page of responses 29 | schema: 30 | type: string 31 | content: 32 | application/json: 33 | schema: 34 | $ref: '#/components/schemas/Pets' 35 | examples: 36 | single: 37 | value: 38 | - id: 0 39 | name: Herbert 40 | tag: Doggo 41 | default: 42 | description: unexpected error 43 | content: 44 | application/json: 45 | schema: 46 | $ref: '#/components/schemas/Error' 47 | post: 48 | summary: Create a pet 49 | operationId: createPets 50 | tags: 51 | - pets 52 | responses: 53 | '201': 54 | description: Null response 55 | default: 56 | description: unexpected error 57 | content: 58 | application/json: 59 | schema: 60 | $ref: '#/components/schemas/Error' 61 | '/pets/{petId}': 62 | get: 63 | summary: Info for a specific pet 64 | operationId: showPetById 65 | tags: 66 | - pets 67 | parameters: 68 | - name: petId 69 | in: path 70 | required: true 71 | description: The id of the pet to retrieve 72 | schema: 73 | type: string 74 | responses: 75 | '200': 76 | description: Expected response to a valid request 77 | content: 78 | application/json: 79 | schema: 80 | $ref: '#/components/schemas/Pets' 81 | default: 82 | description: unexpected error 83 | content: 84 | application/json: 85 | schema: 86 | $ref: '#/components/schemas/Error' 87 | components: 88 | schemas: 89 | Pet: 90 | required: 91 | - id 92 | - name 93 | properties: 94 | id: 95 | type: number 96 | name: 97 | type: string 98 | tag: 99 | type: string 100 | Pets: 101 | type: array 102 | items: 103 | $ref: '#/components/schemas/Pet' 104 | Error: 105 | required: 106 | - code 107 | - message 108 | properties: 109 | code: 110 | type: number 111 | message: 112 | type: string 113 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-with-refs-invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "get": { 18 | "summary": "List all pets", 19 | "operationId": "listPets", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "parameters": [ 24 | { 25 | "name": "limit", 26 | "in": "query", 27 | "description": "How many items to return at one time (max 100)", 28 | "required": false, 29 | "schema": { 30 | "type": "number" 31 | } 32 | } 33 | ], 34 | "responses": { 35 | "200": { 36 | "description": "An paged array of pets", 37 | "headers": { 38 | "x-next": { 39 | "description": "A link to the next page of responses", 40 | "schema": { 41 | "type": "string" 42 | } 43 | } 44 | }, 45 | "content": { 46 | "application/json": { 47 | "schema": { 48 | "$ref": "#/components/schemas/Pets" 49 | }, 50 | "examples": { 51 | "single": { 52 | "value": [ 53 | { 54 | "id": "0", 55 | "tag": 5 56 | } 57 | ] 58 | } 59 | } 60 | } 61 | } 62 | }, 63 | "default": { 64 | "description": "unexpected error", 65 | "content": { 66 | "application/json": { 67 | "schema": { 68 | "$ref": "#/components/schemas/Error" 69 | } 70 | } 71 | } 72 | } 73 | } 74 | }, 75 | "post": { 76 | "summary": "Create a pet", 77 | "operationId": "createPets", 78 | "tags": [ 79 | "pets" 80 | ], 81 | "responses": { 82 | "201": { 83 | "description": "Null response" 84 | }, 85 | "default": { 86 | "description": "unexpected error", 87 | "content": { 88 | "application/json": { 89 | "schema": { 90 | "$ref": "#/components/schemas/Error" 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | }, 98 | "/pets/{petId}": { 99 | "get": { 100 | "summary": "Info for a specific pet", 101 | "operationId": "showPetById", 102 | "tags": [ 103 | "pets" 104 | ], 105 | "parameters": [ 106 | { 107 | "name": "petId", 108 | "in": "path", 109 | "required": true, 110 | "description": "The id of the pet to retrieve", 111 | "schema": { 112 | "type": "string" 113 | } 114 | } 115 | ], 116 | "responses": { 117 | "200": { 118 | "description": "Expected response to a valid request", 119 | "content": { 120 | "application/json": { 121 | "schema": { 122 | "$ref": "#/components/schemas/Pets" 123 | } 124 | } 125 | } 126 | }, 127 | "default": { 128 | "description": "unexpected error", 129 | "content": { 130 | "application/json": { 131 | "schema": { 132 | "$ref": "#/components/schemas/Error" 133 | } 134 | } 135 | } 136 | } 137 | } 138 | } 139 | } 140 | }, 141 | "components": { 142 | "schemas": { 143 | "Pet": { 144 | "required": [ 145 | "id", 146 | "name" 147 | ], 148 | "properties": { 149 | "id": { 150 | "type": "number" 151 | }, 152 | "name": { 153 | "type": "string" 154 | }, 155 | "tag": { 156 | "type": "string" 157 | } 158 | } 159 | }, 160 | "Pets": { 161 | "type": "array", 162 | "items": { 163 | "$ref": "#/components/schemas/Pet" 164 | } 165 | }, 166 | "Error": { 167 | "required": [ 168 | "code", 169 | "message" 170 | ], 171 | "properties": { 172 | "code": { 173 | "type": "number" 174 | }, 175 | "message": { 176 | "type": "string" 177 | } 178 | } 179 | } 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-with-refs-invalid.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | tags: 15 | - pets 16 | parameters: 17 | - name: limit 18 | in: query 19 | description: How many items to return at one time (max 100) 20 | required: false 21 | schema: 22 | type: number 23 | responses: 24 | '200': 25 | description: An paged array of pets 26 | headers: 27 | x-next: 28 | description: A link to the next page of responses 29 | schema: 30 | type: string 31 | content: 32 | application/json: 33 | schema: 34 | $ref: '#/components/schemas/Pets' 35 | examples: 36 | single: 37 | value: 38 | - id: '0' 39 | tag: 5 40 | default: 41 | description: unexpected error 42 | content: 43 | application/json: 44 | schema: 45 | $ref: '#/components/schemas/Error' 46 | post: 47 | summary: Create a pet 48 | operationId: createPets 49 | tags: 50 | - pets 51 | responses: 52 | '201': 53 | description: Null response 54 | default: 55 | description: unexpected error 56 | content: 57 | application/json: 58 | schema: 59 | $ref: '#/components/schemas/Error' 60 | '/pets/{petId}': 61 | get: 62 | summary: Info for a specific pet 63 | operationId: showPetById 64 | tags: 65 | - pets 66 | parameters: 67 | - name: petId 68 | in: path 69 | required: true 70 | description: The id of the pet to retrieve 71 | schema: 72 | type: string 73 | responses: 74 | '200': 75 | description: Expected response to a valid request 76 | content: 77 | application/json: 78 | schema: 79 | $ref: '#/components/schemas/Pets' 80 | default: 81 | description: unexpected error 82 | content: 83 | application/json: 84 | schema: 85 | $ref: '#/components/schemas/Error' 86 | components: 87 | schemas: 88 | Pet: 89 | required: 90 | - id 91 | - name 92 | properties: 93 | id: 94 | type: number 95 | name: 96 | type: string 97 | tag: 98 | type: string 99 | Pets: 100 | type: array 101 | items: 102 | $ref: '#/components/schemas/Pet' 103 | Error: 104 | required: 105 | - code 106 | - message 107 | properties: 108 | code: 109 | type: number 110 | message: 111 | type: string 112 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-with-refs-invalid.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | tags: 15 | - pets 16 | parameters: 17 | - name: limit 18 | in: query 19 | description: How many items to return at one time (max 100) 20 | required: false 21 | schema: 22 | type: number 23 | responses: 24 | '200': 25 | description: An paged array of pets 26 | headers: 27 | x-next: 28 | description: A link to the next page of responses 29 | schema: 30 | type: string 31 | content: 32 | application/json: 33 | schema: 34 | $ref: '#/components/schemas/Pets' 35 | examples: 36 | single: 37 | value: 38 | - id: '0' 39 | tag: 5 40 | default: 41 | description: unexpected error 42 | content: 43 | application/json: 44 | schema: 45 | $ref: '#/components/schemas/Error' 46 | post: 47 | summary: Create a pet 48 | operationId: createPets 49 | tags: 50 | - pets 51 | responses: 52 | '201': 53 | description: Null response 54 | default: 55 | description: unexpected error 56 | content: 57 | application/json: 58 | schema: 59 | $ref: '#/components/schemas/Error' 60 | '/pets/{petId}': 61 | get: 62 | summary: Info for a specific pet 63 | operationId: showPetById 64 | tags: 65 | - pets 66 | parameters: 67 | - name: petId 68 | in: path 69 | required: true 70 | description: The id of the pet to retrieve 71 | schema: 72 | type: string 73 | responses: 74 | '200': 75 | description: Expected response to a valid request 76 | content: 77 | application/json: 78 | schema: 79 | $ref: '#/components/schemas/Pets' 80 | default: 81 | description: unexpected error 82 | content: 83 | application/json: 84 | schema: 85 | $ref: '#/components/schemas/Error' 86 | components: 87 | schemas: 88 | Pet: 89 | required: 90 | - id 91 | - name 92 | properties: 93 | id: 94 | type: number 95 | name: 96 | type: string 97 | tag: 98 | type: string 99 | Pets: 100 | type: array 101 | items: 102 | $ref: '#/components/schemas/Pet' 103 | Error: 104 | required: 105 | - code 106 | - message 107 | properties: 108 | code: 109 | type: number 110 | message: 111 | type: string 112 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-with-refs.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://petstore.swagger.io/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/pets": { 17 | "get": { 18 | "summary": "List all pets", 19 | "operationId": "listPets", 20 | "tags": [ 21 | "pets" 22 | ], 23 | "parameters": [ 24 | { 25 | "name": "limit", 26 | "in": "query", 27 | "description": "How many items to return at one time (max 100)", 28 | "required": false, 29 | "schema": { 30 | "type": "number" 31 | } 32 | } 33 | ], 34 | "responses": { 35 | "200": { 36 | "description": "An paged array of pets", 37 | "headers": { 38 | "x-next": { 39 | "description": "A link to the next page of responses", 40 | "schema": { 41 | "type": "string" 42 | } 43 | } 44 | }, 45 | "content": { 46 | "application/json": { 47 | "schema": { 48 | "$ref": "#/components/schemas/Pets" 49 | }, 50 | "examples": { 51 | "single": { 52 | "value": [ 53 | { 54 | "id": 0, 55 | "name": "Herbert", 56 | "tag": "Doggo" 57 | } 58 | ] 59 | } 60 | } 61 | } 62 | } 63 | }, 64 | "default": { 65 | "description": "unexpected error", 66 | "content": { 67 | "application/json": { 68 | "schema": { 69 | "$ref": "#/components/schemas/Error" 70 | } 71 | } 72 | } 73 | } 74 | } 75 | }, 76 | "post": { 77 | "summary": "Create a pet", 78 | "operationId": "createPets", 79 | "tags": [ 80 | "pets" 81 | ], 82 | "responses": { 83 | "201": { 84 | "description": "Null response" 85 | }, 86 | "default": { 87 | "description": "unexpected error", 88 | "content": { 89 | "application/json": { 90 | "schema": { 91 | "$ref": "#/components/schemas/Error" 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "/pets/{petId}": { 100 | "get": { 101 | "summary": "Info for a specific pet", 102 | "operationId": "showPetById", 103 | "tags": [ 104 | "pets" 105 | ], 106 | "parameters": [ 107 | { 108 | "name": "petId", 109 | "in": "path", 110 | "required": true, 111 | "description": "The id of the pet to retrieve", 112 | "schema": { 113 | "type": "string" 114 | } 115 | } 116 | ], 117 | "responses": { 118 | "200": { 119 | "description": "Expected response to a valid request", 120 | "content": { 121 | "application/json": { 122 | "schema": { 123 | "$ref": "#/components/schemas/Pets" 124 | } 125 | } 126 | } 127 | }, 128 | "default": { 129 | "description": "unexpected error", 130 | "content": { 131 | "application/json": { 132 | "schema": { 133 | "$ref": "#/components/schemas/Error" 134 | } 135 | } 136 | } 137 | } 138 | } 139 | } 140 | } 141 | }, 142 | "components": { 143 | "schemas": { 144 | "Pet": { 145 | "required": [ 146 | "id", 147 | "name" 148 | ], 149 | "properties": { 150 | "id": { 151 | "type": "number" 152 | }, 153 | "name": { 154 | "type": "string" 155 | }, 156 | "tag": { 157 | "type": "string" 158 | } 159 | } 160 | }, 161 | "Pets": { 162 | "type": "array", 163 | "items": { 164 | "$ref": "#/components/schemas/Pet" 165 | } 166 | }, 167 | "Error": { 168 | "required": [ 169 | "code", 170 | "message" 171 | ], 172 | "properties": { 173 | "code": { 174 | "type": "number" 175 | }, 176 | "message": { 177 | "type": "string" 178 | } 179 | } 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-with-refs.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | tags: 15 | - pets 16 | parameters: 17 | - name: limit 18 | in: query 19 | description: How many items to return at one time (max 100) 20 | required: false 21 | schema: 22 | type: number 23 | responses: 24 | '200': 25 | description: An paged array of pets 26 | headers: 27 | x-next: 28 | description: A link to the next page of responses 29 | schema: 30 | type: string 31 | content: 32 | application/json: 33 | schema: 34 | $ref: '#/components/schemas/Pets' 35 | examples: 36 | single: 37 | value: 38 | - id: 0 39 | name: Herbert 40 | tag: Doggo 41 | default: 42 | description: unexpected error 43 | content: 44 | application/json: 45 | schema: 46 | $ref: '#/components/schemas/Error' 47 | post: 48 | summary: Create a pet 49 | operationId: createPets 50 | tags: 51 | - pets 52 | responses: 53 | '201': 54 | description: Null response 55 | default: 56 | description: unexpected error 57 | content: 58 | application/json: 59 | schema: 60 | $ref: '#/components/schemas/Error' 61 | '/pets/{petId}': 62 | get: 63 | summary: Info for a specific pet 64 | operationId: showPetById 65 | tags: 66 | - pets 67 | parameters: 68 | - name: petId 69 | in: path 70 | required: true 71 | description: The id of the pet to retrieve 72 | schema: 73 | type: string 74 | responses: 75 | '200': 76 | description: Expected response to a valid request 77 | content: 78 | application/json: 79 | schema: 80 | $ref: '#/components/schemas/Pets' 81 | default: 82 | description: unexpected error 83 | content: 84 | application/json: 85 | schema: 86 | $ref: '#/components/schemas/Error' 87 | components: 88 | schemas: 89 | Pet: 90 | required: 91 | - id 92 | - name 93 | properties: 94 | id: 95 | type: number 96 | name: 97 | type: string 98 | tag: 99 | type: string 100 | Pets: 101 | type: array 102 | items: 103 | $ref: '#/components/schemas/Pet' 104 | Error: 105 | required: 106 | - code 107 | - message 108 | properties: 109 | code: 110 | type: number 111 | message: 112 | type: string 113 | -------------------------------------------------------------------------------- /test/data/v3/simple-api-with-examples-with-refs.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | tags: 15 | - pets 16 | parameters: 17 | - name: limit 18 | in: query 19 | description: How many items to return at one time (max 100) 20 | required: false 21 | schema: 22 | type: number 23 | responses: 24 | '200': 25 | description: An paged array of pets 26 | headers: 27 | x-next: 28 | description: A link to the next page of responses 29 | schema: 30 | type: string 31 | content: 32 | application/json: 33 | schema: 34 | $ref: '#/components/schemas/Pets' 35 | examples: 36 | single: 37 | value: 38 | - id: 0 39 | name: Herbert 40 | tag: Doggo 41 | default: 42 | description: unexpected error 43 | content: 44 | application/json: 45 | schema: 46 | $ref: '#/components/schemas/Error' 47 | post: 48 | summary: Create a pet 49 | operationId: createPets 50 | tags: 51 | - pets 52 | responses: 53 | '201': 54 | description: Null response 55 | default: 56 | description: unexpected error 57 | content: 58 | application/json: 59 | schema: 60 | $ref: '#/components/schemas/Error' 61 | '/pets/{petId}': 62 | get: 63 | summary: Info for a specific pet 64 | operationId: showPetById 65 | tags: 66 | - pets 67 | parameters: 68 | - name: petId 69 | in: path 70 | required: true 71 | description: The id of the pet to retrieve 72 | schema: 73 | type: string 74 | responses: 75 | '200': 76 | description: Expected response to a valid request 77 | content: 78 | application/json: 79 | schema: 80 | $ref: '#/components/schemas/Pets' 81 | default: 82 | description: unexpected error 83 | content: 84 | application/json: 85 | schema: 86 | $ref: '#/components/schemas/Error' 87 | components: 88 | schemas: 89 | Pet: 90 | required: 91 | - id 92 | - name 93 | properties: 94 | id: 95 | type: number 96 | name: 97 | type: string 98 | tag: 99 | type: string 100 | Pets: 101 | type: array 102 | items: 103 | $ref: '#/components/schemas/Pet' 104 | Error: 105 | required: 106 | - code 107 | - message 108 | properties: 109 | code: 110 | type: number 111 | message: 112 | type: string 113 | -------------------------------------------------------------------------------- /test/data/v3/unknown-formats.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Sample number formats", 6 | "license": { 7 | "name": "MIT" 8 | } 9 | }, 10 | "servers": [ 11 | { 12 | "url": "http://example.com/v1" 13 | } 14 | ], 15 | "paths": { 16 | "/get-numbers": { 17 | "get": { 18 | "summary": "Gets some big numbers", 19 | "operationId": "getNumbers", 20 | "responses": { 21 | "200": { 22 | "description": "Some big numbers", 23 | "content": { 24 | "application/json": { 25 | "schema": { 26 | "type": "object", 27 | "properties": { 28 | "name": { 29 | "type": "string" 30 | }, 31 | "status": { 32 | "type": "string", 33 | "format": "continental-status" 34 | }, 35 | "licensePlate": { 36 | "type": "string", 37 | "format": "license-plate" 38 | }, 39 | "country": { 40 | "type": "string", 41 | "format": "country-code-2" 42 | } 43 | } 44 | }, 45 | "example": { 46 | "name": "John Wick", 47 | "status": "Excommunicado", 48 | "licensePlate": "XAB 235", 49 | "country": "US" 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/data/v3/valid-single-with-value-property.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: 'http://petstore.swagger.io/v1' 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all assets 13 | operationId: listAssets 14 | responses: 15 | '200': 16 | description: An array of assets 17 | content: 18 | application/json: 19 | schema: 20 | $ref: '#/components/schemas/Assets' 21 | examples: 22 | single: 23 | summary: a single example 24 | value: 25 | value: 26 | - id: 0 27 | name: Table 28 | tag: furniture 29 | value: 500 30 | currency: USD 31 | components: 32 | schemas: 33 | Asset: 34 | required: 35 | - id 36 | - name 37 | properties: 38 | id: 39 | type: number 40 | name: 41 | type: string 42 | tag: 43 | type: string 44 | value: 45 | type: number 46 | Assets: 47 | type: object 48 | properties: 49 | value: 50 | type: array 51 | items: 52 | $ref: '#/components/schemas/Asset' 53 | -------------------------------------------------------------------------------- /test/specs/application-error.js: -------------------------------------------------------------------------------- 1 | const 2 | chai = require('chai'), 3 | { ApplicationError, ErrorType } = require('../../src/application-error'); 4 | 5 | const TYPE__VALIDATION = 'Validation'; 6 | 7 | const should = chai.should(); 8 | 9 | describe('ApplicationError', function() { 10 | describe('instantiation', function() { 11 | it('should not fail when no options are passed', () => { 12 | should.exist(new ApplicationError(ErrorType.jsonPathNotFound)); 13 | }); 14 | it('should merge the passed options to the instance', function() { 15 | const err = new ApplicationError(ErrorType.validation, { 16 | path: 'foo', 17 | line: 'bar' 18 | }); 19 | err.path.should.equal('foo'); 20 | err.line.should.equal('bar'); 21 | }); 22 | it('should have the right type for the validation-type', function() { 23 | (new ApplicationError(ErrorType.validation)).type.should.equal(TYPE__VALIDATION); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/specs/impl/index.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'), 2 | { loadTestData } = require('../../util/setup-tests'), 3 | { getImplementation } = require('../../../src/impl/index'), 4 | implV2 = require('../../../src/impl/v2/index'), 5 | implV3 = require('../../../src/impl/v3/index'); 6 | 7 | const FILE_PATH__V2__VALID__SINGLE_EXAMPLE = 'v2/valid-single-example', 8 | FILE_PATH__V3__VALID__EXAMPLES = 'v3/simple-api-with-examples'; 9 | 10 | const should = chai.should(); 11 | 12 | describe('Implementation detector', function() { 13 | it('should correctly detect v2', function() { 14 | getImplementation(loadTestData(FILE_PATH__V2__VALID__SINGLE_EXAMPLE)).should.equal(implV2); 15 | }); 16 | it('should correctly detect v3', function() { 17 | getImplementation(loadTestData(FILE_PATH__V3__VALID__EXAMPLES)).should.equal(implV3); 18 | }); 19 | it('should return `null`, if version could not be determined', function() { 20 | should.not.exist(getImplementation({})); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/specs/impl/v3/inheritance.js: -------------------------------------------------------------------------------- 1 | const { validateFile } = require('../../../../src'); 2 | const path = require('path'); 3 | const { ApplicationError, ErrorType } = require('../../../../src/application-error'); 4 | 5 | const FILE_PATH__INVALID__REQUEST_BODY__INHERITANCE_EXAMPLES 6 | = path.join(__dirname, '../../../data/v3/response-invalid-requestbody-inheritance-examples.json'), 7 | FILE_PATH__VALID__REQUEST_BODY__INHERITANCE_EXAMPLES 8 | = path.join(__dirname, '../../../data/v3/response-valid-requestbody-inheritance-examples.json'); 9 | 10 | describe('Inheritance', function() { 11 | describe('with invalid inheritance examples', function() { 12 | beforeEach(async function() { 13 | this.validationResult = await validateFile(FILE_PATH__INVALID__REQUEST_BODY__INHERITANCE_EXAMPLES); 14 | }); 15 | it('should recognize it as invalid', function() { 16 | this.validationResult.valid.should.equal(false); 17 | }); 18 | it('should recognize all errors', function() { 19 | this.validationResult.errors.length.should.equal(3); 20 | this.validationResult.errors[0].should.deep.equal(new ApplicationError(ErrorType.validation, { 21 | message: "must have required property 'dogName'", 22 | instancePath: '', 23 | schemaPath: '#/oneOf/0/required', 24 | keyword: 'required', 25 | params: { 26 | missingProperty: 'dogName' 27 | }, 28 | examplePath: '/paths/~1pet/post/requestBody/content/application~1json/examples/dog/value' 29 | })); 30 | this.validationResult.errors[1].should.deep.equal(new ApplicationError(ErrorType.validation, { 31 | message: 'value of tag "type" must be in oneOf', 32 | instancePath: '', 33 | schemaPath: '#/discriminator', 34 | keyword: 'discriminator', 35 | params: { 36 | error: 'mapping', 37 | tag: 'type', 38 | tagValue: 'FISH' 39 | }, 40 | examplePath: '/paths/~1pet/post/requestBody/content/application~1json/examples/fish/value' 41 | })); 42 | this.validationResult.errors[2].should.deep.equal(new ApplicationError(ErrorType.validation, { 43 | message: 'must be string', 44 | instancePath: '/catName', 45 | schemaPath: '#/oneOf/0/properties/catName/type', 46 | keyword: 'type', 47 | params: { 48 | type: 'string' 49 | }, 50 | examplePath: '/paths/~1pet/post/requestBody/content/application~1json/examples/dog/value' 51 | })); 52 | }); 53 | }); 54 | describe('with valid inheritance examples', function() { 55 | beforeEach(async function() { 56 | this.validationResult = await validateFile(FILE_PATH__VALID__REQUEST_BODY__INHERITANCE_EXAMPLES); 57 | }); 58 | it('should recognize it as valid', function() { 59 | this.validationResult.valid.should.equal(true); 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/util/setup-tests.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'), 2 | path = require('path'), 3 | cloneDeep = require('lodash.clonedeep'), 4 | chai = require('chai'); 5 | 6 | // Environment setup (may be used by Babel as well in .babelrc) 7 | process.env.NODE_ENV = 'test'; 8 | // Activate `should`-notation 9 | const should = chai.should(); 10 | 11 | // PUBLIC API 12 | 13 | module.exports = { 14 | should, 15 | getPathOfTestData, 16 | loadTestData, 17 | normalizeValidationResultPaths 18 | }; 19 | 20 | // IMPLEMENTATION DETAILS 21 | 22 | const 23 | BASE_PATH__TEST_DATA = '../data/', 24 | BASE_PATH__TEST_DATA_STRING = path.join(__dirname, '../data/'), 25 | SUFFIX__JSON = '.json'; 26 | 27 | // Public 28 | 29 | /** 30 | * Loads data from test-data (sub)directory 31 | * @param {String} fileName Filename (without suffix) or path, relative to the test-data path 32 | * @param {Boolean} [asString=false] If true Loads file and returns content as string. Otherwise, it 33 | * will be loaded as JSON 34 | * @returns {Object|String} Test-data as JSON, or String 35 | */ 36 | function loadTestData(fileName, asString) { 37 | return asString 38 | ? fs.readFileSync(path.join(BASE_PATH__TEST_DATA_STRING, fileName), 'utf-8') 39 | : cloneDeep(require(BASE_PATH__TEST_DATA + fileName + SUFFIX__JSON)); 40 | } 41 | 42 | function getPathOfTestData(fileName, asString) { 43 | return path.join(BASE_PATH__TEST_DATA_STRING, fileName + (!asString ? SUFFIX__JSON : '')); 44 | } 45 | 46 | /** 47 | * Normalizes the file paths in the validation results. The passed result will be modified in place. 48 | * @param {ValidationResult} validationResult The modified validation-result 49 | */ 50 | function normalizeValidationResultPaths(validationResult) { 51 | if (!validationResult.errors) { return validationResult; } 52 | validationResult.errors.forEach(error => { 53 | ['mapFilePath', 'exampleFilePath'].forEach(prop => { 54 | if (!error[prop]) { return; } 55 | error[prop] = path.normalize(error[prop]); 56 | }); 57 | }); 58 | return validationResult; 59 | } 60 | -------------------------------------------------------------------------------- /webpack/config.babel.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'), 2 | path = require('path'), 3 | webpack = require('webpack'), 4 | ESLintPlugin = require('eslint-webpack-plugin'), 5 | { 6 | PROJECT_ROOT, 7 | JS_REGEX, 8 | EXCLUDE_REGEX 9 | } = require('./constants.babel'); 10 | 11 | // CONSTANTS 12 | 13 | const BASE_CONFIG = { 14 | target: 'node', 15 | devtool: 'source-map', 16 | module: { 17 | rules: [ 18 | // Regular loaders 19 | { test: /\.json$/, loader: 'json-loader', type: 'javascript/auto' }, 20 | { test: JS_REGEX, exclude: EXCLUDE_REGEX, loader: 'babel-loader' } 21 | ] 22 | }, 23 | output: { 24 | path: path.resolve(PROJECT_ROOT, 'dist'), 25 | filename: '[name].js', 26 | chunkFilename: '[name].js', 27 | libraryTarget: 'commonjs2' 28 | }, 29 | plugins: [ 30 | new ESLintPlugin({ 31 | // files: [ 32 | // '*.js', 33 | // '*.es6', 34 | // '*.babel' 35 | // ], 36 | exclude: 'node_modules/' 37 | }) 38 | ], 39 | // NodeJS options 40 | node: { 41 | __dirname: false, 42 | __filename: false 43 | } 44 | }; 45 | 46 | // PUBLIC API 47 | 48 | module.exports = _createConfig(); 49 | 50 | // IMPLEMENTATION DETAILS 51 | 52 | 53 | // Private 54 | 55 | function _createConfig() { 56 | return [ 57 | // Module 58 | _createSingleConfig({ 59 | entry: { 60 | index: `${PROJECT_ROOT}/src/index.js` 61 | } 62 | }), 63 | // CLI 64 | _createSingleConfig({ 65 | entry: { 66 | cli: `${PROJECT_ROOT}/src/cli.js` 67 | }, 68 | plugins: [ 69 | new webpack.BannerPlugin({ banner: '#!/usr/bin/env node', raw: true }) 70 | ] 71 | }) 72 | ]; 73 | } 74 | 75 | function _createSingleConfig(params) { 76 | const config = Object.assign({}, BASE_CONFIG, { 77 | entry: params.entry, 78 | externals: _getExternals() 79 | }); 80 | if (params.plugins) { config.plugins = config.plugins.concat(...params.plugins); } 81 | return config; 82 | } 83 | 84 | function _getExternals() { 85 | const nodeModules = {}; 86 | fs.readdirSync('node_modules') 87 | // Exclude the `.bin`-directory 88 | .filter(function(dirName) { 89 | return ['.bin'].indexOf(dirName) === -1; 90 | }) 91 | // Include all other `node_modules` 92 | .forEach(function(mod) { 93 | nodeModules[mod] = 'commonjs ' + mod; 94 | }); 95 | return nodeModules; 96 | } 97 | 98 | -------------------------------------------------------------------------------- /webpack/constants.babel.js: -------------------------------------------------------------------------------- 1 | // WEBPACK BUILD CONSTANTS 2 | const JS_REGEX = /\.js$|\.jsx$|\.es6$|\.babel$/; 3 | const EXCLUDE_REGEX = /node_modules/; 4 | const PROJECT_ROOT = __dirname + '/../'; 5 | 6 | module.exports = { 7 | JS_REGEX, 8 | EXCLUDE_REGEX, 9 | PROJECT_ROOT 10 | }; 11 | --------------------------------------------------------------------------------