├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── dependency-review.yml │ ├── deploy-docker.yml │ ├── maven-pulls.yml │ ├── maven.yml │ ├── prepare-release.yml │ └── release.yml ├── .gitignore ├── .whitesource ├── CI ├── CI.md ├── docker-release.sh ├── ghApiClient.py ├── lastRelease.py ├── post-release.sh ├── pre-release.sh ├── prepare-release.sh ├── publishRelease.py ├── releaseNotes.py └── version.sh ├── Dockerfile ├── LICENSE ├── NOTICE ├── README.md ├── inflector.yaml ├── pom.xml └── src ├── main ├── java │ └── io │ │ └── swagger │ │ ├── Utils.java │ │ ├── handler │ │ └── ValidatorController.java │ │ ├── jsonschema │ │ ├── FgeValidator.java │ │ ├── NetworkntValidator.java │ │ └── Validator.java │ │ └── models │ │ ├── Instance.java │ │ ├── Schema.java │ │ ├── SchemaValidationError.java │ │ └── ValidationResponse.java ├── resources │ ├── error.png │ ├── invalid.png │ ├── logback.xml │ ├── schemas │ │ ├── 20 │ │ │ ├── official.json │ │ │ └── schema.json │ │ ├── 30 │ │ │ ├── official.json │ │ │ ├── schema3-fix-format-uri-reference.json │ │ │ └── schema3.json │ │ └── 31 │ │ │ ├── dialect │ │ │ ├── base.schema.json │ │ │ └── base.schema.yaml │ │ │ ├── meta │ │ │ ├── base.schema.json │ │ │ └── base.schema.yaml │ │ │ ├── official.json │ │ │ ├── schema-base.json │ │ │ ├── schema-base.yaml │ │ │ ├── schema.json │ │ │ └── schema.yaml │ ├── upgrade.png │ └── valid.png ├── swagger │ └── swagger.yaml └── webapp │ ├── WEB-INF │ └── web.xml │ └── index.html └── test ├── java └── spec │ └── validator │ └── ValidatorTest.java └── resources ├── invalid_oas3.yaml ├── invalid_oas31.yaml ├── invalid_oas31_simple.yaml ├── invalid_swagger2.yaml ├── logback.xml ├── oas30local ├── petstore30.yaml ├── petstore30ext1.yaml └── petstore30ext2.yaml ├── oas31local ├── petstore31.yaml ├── petstore31ext1.yaml └── petstore31ext2.yaml ├── valid_oas3.yaml ├── valid_oas31.yaml ├── valid_oas31_simple.yaml └── valid_swagger2.yaml /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | target-branch: "master" 5 | open-pull-requests-limit: 5 6 | directory: "/" 7 | schedule: 8 | interval: "daily" 9 | time: "19:00" 10 | allow: 11 | - dependency-name: "io.swagger*:*" 12 | update-types: ["version-update:semver-major"] -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | schedule: 16 | - cron: '16 04 * * 2' 17 | 18 | jobs: 19 | analyze: 20 | name: Analyze (${{ matrix.language }}) 21 | # Runner size impacts CodeQL analysis time. To learn more, please see: 22 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 23 | # - https://gh.io/supported-runners-and-hardware-resources 24 | # - https://gh.io/using-larger-runners (GitHub.com only) 25 | # Consider using larger runners or machines with greater resources for possible analysis time improvements. 26 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 27 | timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} 28 | permissions: 29 | # required for all workflows 30 | security-events: write 31 | 32 | # required to fetch internal or private CodeQL packs 33 | packages: read 34 | 35 | # only required for workflows in private repositories 36 | actions: read 37 | contents: read 38 | 39 | strategy: 40 | fail-fast: false 41 | matrix: 42 | include: 43 | - language: java-kotlin 44 | build-mode: none # This mode only analyzes Java. Set this to 'autobuild' or 'manual' to analyze Kotlin too. 45 | # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 46 | # Use `c-cpp` to analyze code written in C, C++ or both 47 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both 48 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both 49 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 50 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 51 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 52 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 53 | steps: 54 | - name: Checkout repository 55 | uses: actions/checkout@v4 56 | 57 | # Initializes the CodeQL tools for scanning. 58 | - name: Initialize CodeQL 59 | uses: github/codeql-action/init@v3 60 | with: 61 | languages: ${{ matrix.language }} 62 | build-mode: ${{ matrix.build-mode }} 63 | # If you wish to specify custom queries, you can do so here or in a config file. 64 | # By default, queries listed here will override any specified in a config file. 65 | # Prefix the list here with "+" to use these queries and those in the config file. 66 | 67 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 68 | # queries: security-extended,security-and-quality 69 | 70 | # If the analyze step fails for one of the languages you are analyzing with 71 | # "We were unable to automatically build your code", modify the matrix above 72 | # to set the build mode to "manual" for that language. Then modify this step 73 | # to build your code. 74 | # ℹ️ Command-line programs to run using the OS shell. 75 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 76 | - if: matrix.build-mode == 'manual' 77 | shell: bash 78 | run: | 79 | echo 'If you are using a "manual" build mode for one or more of the' \ 80 | 'languages you are analyzing, replace this with the commands to build' \ 81 | 'your code, for example:' 82 | echo ' make bootstrap' 83 | echo ' make release' 84 | exit 1 85 | 86 | - name: Perform CodeQL Analysis 87 | uses: github/codeql-action/analyze@v3 88 | with: 89 | category: "/language:${{matrix.language}}" 90 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: 'Dependency Review' 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | dependency-review: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 'Checkout Repository' 12 | uses: actions/checkout@v4 13 | - name: Dependency Review 14 | uses: actions/dependency-review-action@v3 15 | with: 16 | fail-on-severity: high 17 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docker.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docker 2 | 3 | on: 4 | workflow_dispatch: 5 | branches: ["master"] 6 | inputs: 7 | tag: 8 | description: tag/version to deploy 9 | required: true 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: deploy docker 17 | run: | 18 | SC_RELEASE_TAG="v${{ env.TAG }}" 19 | echo "$SC_RELEASE_TAG" 20 | 21 | TOKEN="${{ secrets.RANCHER2_BEARER_TOKEN }}" 22 | RANCHER_HOST="rancher.tools.swagger.io" 23 | CLUSTER_ID="c-n8zp2" 24 | NAMESPACE_NAME="swagger-oss" 25 | K8S_OBJECT_TYPE="daemonsets" 26 | K8S_OBJECT_NAME="swagger-validator-v2" 27 | DEPLOY_IMAGE="swaggerapi/swagger-validator-v2:$SC_RELEASE_TAG" 28 | 29 | workloadStatus="" 30 | getStatus() { 31 | echo "Getting update status..." 32 | if ! workloadStatus="$(curl -s -X GET \ 33 | -H "Authorization: Bearer ${TOKEN}" \ 34 | -H 'Content-Type: application/json' \ 35 | "https://${RANCHER_HOST}/k8s/clusters/${CLUSTER_ID}/apis/apps/v1/namespaces/${NAMESPACE_NAME}/${K8S_OBJECT_TYPE}/${K8S_OBJECT_NAME}/status")" 36 | then 37 | echo 'ERROR - get status k8s API call failed!' 38 | echo "Exiting build"... 39 | exit 1 40 | fi 41 | } 42 | 43 | # $1 = image to deploy 44 | updateObject() { 45 | local image="${1}" 46 | echo "Updating image value..." 47 | 48 | if ! curl -s -X PATCH \ 49 | -H "Authorization: Bearer ${TOKEN}" \ 50 | -H 'Content-Type: application/json-patch+json' \ 51 | "https://${RANCHER_HOST}/k8s/clusters/${CLUSTER_ID}/apis/apps/v1/namespaces/${NAMESPACE_NAME}/${K8S_OBJECT_TYPE}/${K8S_OBJECT_NAME}" \ 52 | -d "[{\"op\": \"replace\", \"path\": \"/spec/template/spec/containers/0/image\", \"value\": \"${image}\"}]" 53 | then 54 | echo 'ERROR - image update k8s API call failed!' 55 | echo "Exiting build..." 56 | exit 1 57 | fi 58 | } 59 | 60 | 61 | # Check that the TAG is valid 62 | if [[ $SC_RELEASE_TAG =~ ^[vV]?[0-9]*\.[0-9]*\.[0-9]*$ ]]; then 63 | echo "" 64 | echo "This is a Valid TAG..." 65 | 66 | # Get current image/tag in case we need to rollback 67 | getStatus 68 | ROLLBACK_IMAGE="$(echo "${workloadStatus}" | jq -r '.spec.template.spec.containers[0].image')" 69 | echo "" 70 | echo "Current image: ${ROLLBACK_IMAGE}" 71 | 72 | # Update image and validate response 73 | echo "" 74 | updateObject "${DEPLOY_IMAGE}" 75 | echo "" 76 | 77 | echo "" 78 | echo "Waiting for pods to start..." 79 | echo "" 80 | sleep 60s 81 | 82 | # Get state of the k8s object. If numberReady == desiredNumberScheduled, consider the upgrade successful. Else raise error 83 | getStatus 84 | status="$(echo "${workloadStatus}" | jq '.status')" 85 | echo "" 86 | echo "${status}" 87 | echo "" 88 | 89 | numberDesired="$(echo "${status}" | jq -r '.desiredNumberScheduled')" 90 | numberReady="$(echo "${status}" | jq -r '.numberReady')" 91 | 92 | if (( numberReady == numberDesired )); then 93 | echo "${K8S_OBJECT_NAME} has been upgraded to ${DEPLOY_IMAGE}" 94 | 95 | # If pods are not starting, rollback the upgrade and exit the build with error 96 | else 97 | echo "state = error...rolling back upgrade" 98 | updateObject "${ROLLBACK_IMAGE}" 99 | echo "" 100 | 101 | echo "" 102 | echo "Waiting for rollback pods to start..." 103 | echo "" 104 | sleep 60s 105 | 106 | getStatus 107 | status="$(echo "${workloadStatus}" | jq '.status')" 108 | echo "" 109 | echo "${status}" 110 | echo "" 111 | 112 | numberDesired="$(echo "${status}" | jq -r '.desiredNumberScheduled')" 113 | numberReady="$(echo "${status}" | jq -r '.numberReady')" 114 | 115 | if (( numberReady == numberDesired )); then 116 | echo "Rollback to ${ROLLBACK_IMAGE} completed." 117 | else 118 | echo "FATAL - rollback failed" 119 | fi 120 | echo "Exiting Build..." 121 | exit 1 122 | fi 123 | 124 | else 125 | echo "This TAG is not in a valid format..." 126 | echo "Exiting Build..." 127 | exit 0 128 | fi 129 | echo "Exiting Build..." 130 | exit 0 131 | env: 132 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 133 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 134 | TAG: ${{ github.event.inputs.tag }} 135 | -------------------------------------------------------------------------------- /.github/workflows/maven-pulls.yml: -------------------------------------------------------------------------------- 1 | name: Build Test PR 2 | 3 | on: 4 | pull_request: 5 | branches: [ "master" ] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | java: [ 11 ] 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Set up Java 18 | uses: actions/setup-java@v4 19 | with: 20 | java-version: ${{ matrix.java }} 21 | distribution: temurin 22 | server-id: central 23 | server-username: MAVEN_USERNAME 24 | server-password: MAVEN_PASSWORD 25 | - name: Cache local Maven repository 26 | uses: actions/cache@v4 27 | with: 28 | path: ~/.m2/repository 29 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 30 | restore-keys: | 31 | ${{ runner.os }}-maven- 32 | - name: Build with Maven and Gradle 33 | run: | 34 | mvn --no-transfer-progress -B install --file pom.xml 35 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Build Test Deploy master 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | java: [ 11 ] 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Set up Java 18 | uses: actions/setup-java@v4 19 | with: 20 | java-version: ${{ matrix.java }} 21 | distribution: temurin 22 | server-id: central 23 | server-username: MAVEN_USERNAME 24 | server-password: MAVEN_PASSWORD 25 | - name: Cache local Maven repository 26 | uses: actions/cache@v4 27 | with: 28 | path: ~/.m2/repository 29 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 30 | restore-keys: | 31 | ${{ runner.os }}-maven- 32 | - name: Build with Maven, Deploy snapshot to maven central 33 | run: | 34 | export MY_POM_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 35 | echo "POM VERSION" ${MY_POM_VERSION} 36 | if [[ $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; 37 | then 38 | mvn --no-transfer-progress -B install --file pom.xml 39 | export MY_JAVA_VERSION=`java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1` 40 | echo "JAVA VERSION" ${MY_JAVA_VERSION} 41 | if [[ ${MY_JAVA_VERSION} == "11" ]]; 42 | then 43 | export MY_POM_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 44 | echo "POM VERSION" ${MY_POM_VERSION} 45 | mvn --no-transfer-progress -B clean deploy 46 | else 47 | echo "not deploying on java version: " ${MY_JAVA_VERSION} 48 | fi 49 | else 50 | echo "not building and maven publishing project as it is a release version: " ${MY_JAVA_VERSION} 51 | fi 52 | env: 53 | MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 54 | MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 55 | -------------------------------------------------------------------------------- /.github/workflows/prepare-release.yml: -------------------------------------------------------------------------------- 1 | name: Prepare Release 2 | 3 | on: 4 | workflow_dispatch: 5 | branches: ["master"] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: tibdex/github-app-token@v1 15 | id: generate-token 16 | with: 17 | app_id: ${{ secrets.APP_ID }} 18 | private_key: ${{ secrets.APP_PRIVATE_KEY }} 19 | - name: Set up Python 3.10 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.10' 23 | - name: Set up Java 11 24 | uses: actions/setup-java@v4 25 | with: 26 | java-version: 11 27 | distribution: temurin 28 | server-id: central 29 | server-username: MAVEN_USERNAME 30 | server-password: MAVEN_PASSWORD 31 | - name: Cache local Maven repository 32 | uses: actions/cache@v4 33 | with: 34 | path: ~/.m2/repository 35 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 36 | restore-keys: | 37 | ${{ runner.os }}-maven- 38 | - name: Run prepare release script 39 | id: prepare-release 40 | run: | 41 | export MY_POM_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 42 | if [[ $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; 43 | then 44 | . ./CI/prepare-release.sh 45 | echo "PREPARE_RELEASE_OK=yes" >> $GITHUB_ENV 46 | else 47 | echo "not preparing release for release version: " ${MY_POM_VERSION} 48 | echo "PREPARE_RELEASE_OK=no" >> $GITHUB_ENV 49 | fi 50 | echo "SC_VERSION=$SC_VERSION" >> $GITHUB_ENV 51 | echo "SC_NEXT_VERSION=$SC_NEXT_VERSION" >> $GITHUB_ENV 52 | - name: Create Prepare Release Pull Request 53 | uses: peter-evans/create-pull-request@v4 54 | if: env.PREPARE_RELEASE_OK == 'yes' 55 | with: 56 | token: ${{ steps.generate-token.outputs.token }} 57 | commit-message: prepare release ${{ env.SC_VERSION }} 58 | title: 'prepare release ${{ env.SC_VERSION }}' 59 | branch: prepare-release-${{ env.SC_VERSION }} 60 | env: 61 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 62 | MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 63 | MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 64 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | SC_VERSION: 66 | SC_NEXT_VERSION: 67 | 68 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | branches: ["master"] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: tibdex/github-app-token@v1 15 | id: generate-token 16 | with: 17 | app_id: ${{ secrets.APP_ID }} 18 | private_key: ${{ secrets.APP_PRIVATE_KEY }} 19 | - name: Set up Python 3.10 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.10' 23 | - name: Set up Java 11 24 | uses: actions/setup-java@v4 25 | with: 26 | java-version: 11 27 | distribution: temurin 28 | server-id: central 29 | server-username: MAVEN_USERNAME 30 | server-password: MAVEN_PASSWORD 31 | gpg-private-key: ${{ secrets.OSSRH_GPG_PRIVATE_KEY }} 32 | - name: Cache local Maven repository 33 | uses: actions/cache@v4 34 | with: 35 | path: ~/.m2/repository 36 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 37 | restore-keys: | 38 | ${{ runner.os }}-maven- 39 | - name: Run pre release script 40 | id: preRelease 41 | run: | 42 | # export GPG_TTY=$(tty) 43 | export MY_POM_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 44 | if [[ $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; 45 | then 46 | echo "not releasing snapshot version: " ${MY_POM_VERSION} 47 | echo "RELEASE_OK=no" >> $GITHUB_ENV 48 | else 49 | . ./CI/pre-release.sh 50 | echo "RELEASE_OK=yes" >> $GITHUB_ENV 51 | fi 52 | echo "SC_VERSION=$SC_VERSION" >> $GITHUB_ENV 53 | echo "SC_NEXT_VERSION=$SC_NEXT_VERSION" >> $GITHUB_ENV 54 | echo "SC_LAST_RELEASE=$SC_LAST_RELEASE" >> $GITHUB_ENV 55 | - name: configure git user email 56 | run: | 57 | git config --global user.email "action@github.com" 58 | git config --global user.name "GitHub Action" 59 | git config --global hub.protocol https 60 | git remote set-url origin https://\${{ secrets.GITHUB_TOKEN }}:x-oauth-basic@github.com/swagger-api/validator-badge.git 61 | - name: Run maven deploy/release 62 | if: env.RELEASE_OK == 'yes' 63 | run: | 64 | mvn --no-transfer-progress -B -Prelease deploy 65 | - name: docker login 66 | run: | 67 | docker login --username=${{ secrets.DOCKERHUB_SB_USERNAME }} --password=${{ secrets.DOCKERHUB_SB_PASSWORD }} 68 | set -e 69 | - name: Docker build and push 70 | id: docker_build_push 71 | if: env.RELEASE_OK == 'yes' 72 | run: | 73 | . ./CI/docker-release.sh 74 | - name: Run post release script 75 | id: postRelease 76 | if: env.RELEASE_OK == 'yes' 77 | run: | 78 | . ./CI/post-release.sh 79 | - name: Create Next Snapshot Pull Request 80 | uses: peter-evans/create-pull-request@v4 81 | if: env.RELEASE_OK == 'yes' 82 | with: 83 | token: ${{ steps.generate-token.outputs.token }} 84 | commit-message: bump snapshot ${{ env.SC_NEXT_VERSION }}-SNAPSHOT 85 | title: 'bump snapshot ${{ env.SC_NEXT_VERSION }}-SNAPSHOT' 86 | branch: bump-snap-${{ env.SC_NEXT_VERSION }}-SNAPSHOT 87 | - name: deploy docker 88 | run: | 89 | SC_RELEASE_TAG="v${{ env.SC_VERSION }}" 90 | echo "$SC_RELEASE_TAG" 91 | 92 | TOKEN="${{ secrets.RANCHER2_BEARER_TOKEN }}" 93 | RANCHER_HOST="rancher.tools.swagger.io" 94 | CLUSTER_ID="c-n8zp2" 95 | NAMESPACE_NAME="swagger-oss" 96 | K8S_OBJECT_TYPE="daemonsets" 97 | K8S_OBJECT_NAME="swagger-validator-v2" 98 | DEPLOY_IMAGE="swaggerapi/swagger-validator-v2:$SC_RELEASE_TAG" 99 | 100 | workloadStatus="" 101 | getStatus() { 102 | echo "Getting update status..." 103 | if ! workloadStatus="$(curl -s -X GET \ 104 | -H "Authorization: Bearer ${TOKEN}" \ 105 | -H 'Content-Type: application/json' \ 106 | "https://${RANCHER_HOST}/k8s/clusters/${CLUSTER_ID}/apis/apps/v1/namespaces/${NAMESPACE_NAME}/${K8S_OBJECT_TYPE}/${K8S_OBJECT_NAME}/status")" 107 | then 108 | echo 'ERROR - get status k8s API call failed!' 109 | echo "Exiting build"... 110 | exit 1 111 | fi 112 | } 113 | 114 | # $1 = image to deploy 115 | updateObject() { 116 | local image="${1}" 117 | echo "Updating image value..." 118 | 119 | if ! curl -s -X PATCH \ 120 | -H "Authorization: Bearer ${TOKEN}" \ 121 | -H 'Content-Type: application/json-patch+json' \ 122 | "https://${RANCHER_HOST}/k8s/clusters/${CLUSTER_ID}/apis/apps/v1/namespaces/${NAMESPACE_NAME}/${K8S_OBJECT_TYPE}/${K8S_OBJECT_NAME}" \ 123 | -d "[{\"op\": \"replace\", \"path\": \"/spec/template/spec/containers/0/image\", \"value\": \"${image}\"}]" 124 | then 125 | echo 'ERROR - image update k8s API call failed!' 126 | echo "Exiting build..." 127 | exit 1 128 | fi 129 | } 130 | 131 | 132 | # Check that the TAG is valid 133 | if [[ $SC_RELEASE_TAG =~ ^[vV]?[0-9]*\.[0-9]*\.[0-9]*$ ]]; then 134 | echo "" 135 | echo "This is a Valid TAG..." 136 | 137 | # Get current image/tag in case we need to rollback 138 | getStatus 139 | ROLLBACK_IMAGE="$(echo "${workloadStatus}" | jq -r '.spec.template.spec.containers[0].image')" 140 | echo "" 141 | echo "Current image: ${ROLLBACK_IMAGE}" 142 | 143 | # Update image and validate response 144 | echo "" 145 | updateObject "${DEPLOY_IMAGE}" 146 | echo "" 147 | 148 | echo "" 149 | echo "Waiting for pods to start..." 150 | echo "" 151 | sleep 60s 152 | 153 | # Get state of the k8s object. If numberReady == desiredNumberScheduled, consider the upgrade successful. Else raise error 154 | getStatus 155 | status="$(echo "${workloadStatus}" | jq '.status')" 156 | echo "" 157 | echo "${status}" 158 | echo "" 159 | 160 | numberDesired="$(echo "${status}" | jq -r '.desiredNumberScheduled')" 161 | numberReady="$(echo "${status}" | jq -r '.numberReady')" 162 | 163 | if (( numberReady == numberDesired )); then 164 | echo "${K8S_OBJECT_NAME} has been upgraded to ${DEPLOY_IMAGE}" 165 | 166 | # If pods are not starting, rollback the upgrade and exit the build with error 167 | else 168 | echo "state = error...rolling back upgrade" 169 | updateObject "${ROLLBACK_IMAGE}" 170 | echo "" 171 | 172 | echo "" 173 | echo "Waiting for rollback pods to start..." 174 | echo "" 175 | sleep 60s 176 | 177 | getStatus 178 | status="$(echo "${workloadStatus}" | jq '.status')" 179 | echo "" 180 | echo "${status}" 181 | echo "" 182 | 183 | numberDesired="$(echo "${status}" | jq -r '.desiredNumberScheduled')" 184 | numberReady="$(echo "${status}" | jq -r '.numberReady')" 185 | 186 | if (( numberReady == numberDesired )); then 187 | echo "Rollback to ${ROLLBACK_IMAGE} completed." 188 | else 189 | echo "FATAL - rollback failed" 190 | fi 191 | echo "Exiting Build..." 192 | exit 1 193 | fi 194 | 195 | else 196 | echo "This TAG is not in a valid format..." 197 | echo "Exiting Build..." 198 | exit 0 199 | fi 200 | echo "Exiting Build..." 201 | exit 0 202 | env: 203 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 204 | MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 205 | MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 206 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 207 | SC_VERSION: 208 | SC_NEXT_VERSION: 209 | GPG_PRIVATE_KEY: ${{ secrets.OSSRH_GPG_PRIVATE_KEY }} 210 | GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_PRIVATE_PASSPHRASE }} 211 | GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} 212 | GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} 213 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | lib/*.jar 3 | target 4 | .idea 5 | .idea_modules 6 | .settings 7 | .project 8 | .classpath 9 | .cache 10 | atlassian-ide-plugin.xml 11 | *.iml 12 | .java-version 13 | *.ipr 14 | *.iws 15 | .DS_Store 16 | dependency-reduced-pom.xml 17 | *.pyc 18 | /bin/ 19 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "settingsInheritedFrom": "swagger-api/whitesource-config@main", 3 | "scanSettings": { 4 | "baseBranches": ["master", "v1"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CI/CI.md: -------------------------------------------------------------------------------- 1 | ## Continuous integration 2 | 3 | ### Build, test and deploy 4 | Swagger Validator uses Github actions to run jobs/checks building, testing and deploying snapshots on push and PR events. 5 | 6 | These github actions are configured in `.github/workflows`: 7 | 8 | * maven.yml : Build Test Deploy master 9 | * maven-pulls.yml Build Test PR 10 | 11 | 12 | These actions use available actions in combination with short bash scripts. 13 | 14 | ### Release 15 | 16 | Releases are semi-automated and consist in 2 actions using available public actions in combination with bash and python scripts. 17 | **TODO**: Python code is used for historical reasons to execute GitHub APIs calls, in general a more consistent environment would 18 | be more maintainable e.g. implementing a custom JavaScript or Docker Container GitHub Action and/or a bash only script(s). 19 | 20 | #### Workflow summary 21 | 22 | 1. execute `prepare-release.yml` / `Prepare Release` for `master` branch 23 | 1. check and merge the Prepare Release PR pushed by previous step. Delete the branch 24 | 1. execute `release.yml` / `Release` for `master` branch 25 | 1. check and merge the next snaphot PR pushed by previous step. Delete the branch 26 | 27 | #### Prepare Release 28 | 29 | The first action to execute is `prepare-release.yml` / `Prepare Release` 30 | 31 | This is triggered by manually executing the action, selecting `Actions` in project GitHub UI, then `Prepare Release` workflow 32 | and clicking `Run Workflow` 33 | 34 | `Prepare Release` takes care of: 35 | 36 | * create release notes out of merged PRs 37 | * Draft a release with related tag 38 | * bump versions to release, and update all affected files 39 | * build and test maven 40 | * push a Pull Request with the changes for human check. 41 | 42 | After the PR checks complete, the PR can me merged, and the second phase `Release` started. 43 | 44 | #### Release 45 | 46 | Once prepare release PR has been merged, the second phase is provided by `release.yml` / `Release` actions. 47 | 48 | This is triggered by manually executing the action, selecting `Actions` in project GitHub UI, then `Release` workflow 49 | and clicking `Run Workflow` 50 | 51 | `Release` takes care of: 52 | 53 | * build and test maven 54 | * deploy/publish to maven central 55 | * publish the previously prepared GitHub release / tag 56 | * build and push docker image 57 | * deploy/publish docker image to docker hub 58 | * push PR for next snapshot 59 | 60 | 61 | 62 | ### Secrets 63 | 64 | GitHub Actions make use of `Secrets` which can be configured either with Repo or Organization scope; the needed secrets are the following: 65 | 66 | * `APP_ID` and APP_PRIVATE_KEY`: these are the values provided by an account configured GitHub App, allowing to obtain a GitHub token 67 | different from the default used in GitHub Actions (which does not allow to "chain" actions).Actions 68 | 69 | The GitHub App must be configured as detailed in [this doc](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#authenticating-with-github-app-generated-tokens). 70 | 71 | See also [here](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#triggering-further-workflow-runs) 72 | 73 | * `OSSRH_GPG_PRIVATE_KEY` and `OSSRH_GPG_PRIVATE_PASSPHRASE` : gpg key and passphrase to be used for sonatype releases 74 | GPG private key and passphrase defined to be used for sonatype deployments, as detailed in 75 | https://central.sonatype.org/pages/working-with-pgp-signatures.html (I'd say with email matching the one of the sonatype account of point 1 76 | 77 | * `MAVEN_USERNAME` and `MAVEN_PASSWORD`: sonatype user/token 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /CI/docker-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CUR=$(pwd) 4 | 5 | SC_RELEASE_TAG="v$SC_VERSION" 6 | 7 | echo "docker tag:" 8 | echo "$SC_RELEASE_TAG" 9 | 10 | export DOCKER_VALIDATOR_IMAGE_NAME=swaggerapi/swagger-validator-v2 11 | docker build --rm=false -t $DOCKER_VALIDATOR_IMAGE_NAME:$SC_RELEASE_TAG . 12 | docker tag $DOCKER_VALIDATOR_IMAGE_NAME:$SC_RELEASE_TAG $DOCKER_VALIDATOR_IMAGE_NAME:latest 13 | docker push $DOCKER_VALIDATOR_IMAGE_NAME:$SC_RELEASE_TAG 14 | docker push $DOCKER_VALIDATOR_IMAGE_NAME:latest 15 | echo "docker images:" 16 | docker images | grep -i validator 17 | -------------------------------------------------------------------------------- /CI/ghApiClient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import time 5 | import urllib.request, urllib.error, urllib.parse 6 | import http.client 7 | import json 8 | 9 | GH_BASE_URL = "https://api.github.com/" 10 | 11 | GH_TOKEN = os.environ['GH_TOKEN'] 12 | GH_AUTH = "Bearer %s" % GH_TOKEN 13 | 14 | def readUrl(name): 15 | try: 16 | request = urllib.request.Request(GH_BASE_URL + name) 17 | request.add_header("Authorization", GH_AUTH) 18 | content = urllib.request.urlopen(request).read() 19 | jcont = json.loads(content) 20 | return jcont 21 | except urllib.error.HTTPError as e: 22 | print(('HTTPError = ' + str(e.code))) 23 | raise e 24 | except urllib.error.URLError as e: 25 | print(('URLError = ' + str(e.reason))) 26 | raise e 27 | except http.client.HTTPException as e: 28 | print(('HTTPException = ' + str(e))) 29 | raise e 30 | except Exception: 31 | import traceback 32 | print(('generic exception: ' + traceback.format_exc())) 33 | raise IOError 34 | 35 | def postUrl(name, body): 36 | global GH_BASE_URL 37 | try: 38 | time.sleep(0.05) 39 | request = urllib.request.Request(GH_BASE_URL + name) 40 | request.add_header("Authorization", GH_AUTH) 41 | request.add_header("Accept", "application/vnd.github.v3+json") 42 | data = body.encode('utf-8') 43 | content = urllib.request.urlopen(request, data).read() 44 | jcont = json.loads(content) 45 | return jcont 46 | except urllib.error.HTTPError as e: 47 | print(('HTTPError = ' + str(e.code))) 48 | print((str(e))) 49 | raise e 50 | except urllib.error.URLError as e: 51 | print(('URLError = ' + str(e.reason))) 52 | raise e 53 | except http.client.HTTPException as e: 54 | print(('HTTPException = ' + str(e))) 55 | raise e 56 | except Exception: 57 | import traceback 58 | print(('generic exception: ' + traceback.format_exc())) 59 | raise IOError 60 | -------------------------------------------------------------------------------- /CI/lastRelease.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import ghApiClient 4 | 5 | def getLastReleaseTag(): 6 | content = ghApiClient.readUrl('repos/swagger-api/validator-badge/releases') 7 | for l in content: 8 | draft = l["draft"] 9 | tag = l["tag_name"] 10 | if str(draft) != 'True' and tag.startswith("v2"): 11 | return tag[1:] 12 | return "2.1.3" 13 | # main 14 | def main(): 15 | result = getLastReleaseTag() 16 | print (result) 17 | 18 | # here start main 19 | main() 20 | -------------------------------------------------------------------------------- /CI/post-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CUR=$(pwd) 4 | TMPDIR="$(dirname -- "${0}")" 5 | 6 | SC_RELEASE_TAG="v$SC_VERSION" 7 | 8 | ##################### 9 | ### publish pre-prepared release (tag is created) 10 | ##################### 11 | python $CUR/CI/publishRelease.py "$SC_RELEASE_TAG" 12 | 13 | ##################### 14 | ### update the version to next snapshot in maven project with set version 15 | ##################### 16 | mvn versions:set -DnewVersion="${SC_NEXT_VERSION}-SNAPSHOT" 17 | mvn versions:commit 18 | 19 | ##################### 20 | ### update all other versions in files around to the next snapshot or new release, including readme and gradle ### 21 | ##################### 22 | 23 | sc_find="version\: $SC_VERSION" 24 | sc_replace="version: $SC_NEXT_VERSION-SNAPSHOT" 25 | sed -i -e "s/$sc_find/$sc_replace/g" $CUR/src/main/swagger/swagger.yaml 26 | -------------------------------------------------------------------------------- /CI/pre-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CUR=$(pwd) 4 | 5 | export SC_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 6 | export SC_NEXT_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 7 | SC_QUALIFIER=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.qualifier}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 8 | #SC_LAST_RELEASE=`mvn -q -Dexec.executable="echo" -Dexec.args='${releasedVersion.version}' --non-recursive org.codehaus.mojo:build-helper-maven-plugin:3.2.0:released-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 9 | SC_LAST_RELEASE=`python $CUR/CI/lastRelease.py` 10 | 11 | 12 | SC_RELEASE_TAG="v$SC_VERSION" 13 | 14 | 15 | ##################### 16 | ### build and test maven ### 17 | ##################### 18 | mvn --no-transfer-progress -B install --file pom.xml 19 | -------------------------------------------------------------------------------- /CI/prepare-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CUR=$(pwd) 4 | 5 | export SC_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 6 | export SC_NEXT_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 7 | SC_QUALIFIER=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.qualifier}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 8 | #SC_LAST_RELEASE=`mvn -q -Dexec.executable="echo" -Dexec.args='${releasedVersion.version}' --non-recursive org.codehaus.mojo:build-helper-maven-plugin:3.2.0:released-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` 9 | SC_LAST_RELEASE=`python $CUR/CI/lastRelease.py` 10 | 11 | 12 | 13 | SC_RELEASE_TITLE="Swagger Validator $SC_VERSION released!" 14 | SC_RELEASE_TAG="v$SC_VERSION" 15 | 16 | echo "SC_VERSION: $SC_VERSION" 17 | echo "SC_NEXT_VERSION: $SC_NEXT_VERSION" 18 | echo "SC_LAST_RELEASE: $SC_LAST_RELEASE" 19 | echo "SC_RELEASE_TITLE: $SC_RELEASE_TITLE" 20 | echo "SC_RELEASE_TAG: $SC_RELEASE_TAG" 21 | 22 | ##################### 23 | ### draft release Notes with next release after last release, with tag 24 | ##################### 25 | python $CUR/CI/releaseNotes.py "$SC_LAST_RELEASE" "$SC_RELEASE_TITLE" "$SC_RELEASE_TAG" 26 | 27 | ##################### 28 | ### update the version to release in maven project with set version 29 | ##################### 30 | mvn versions:set -DnewVersion=$SC_VERSION 31 | mvn versions:commit 32 | 33 | 34 | ##################### 35 | ### update all other versions in files around to the new release 36 | ##################### 37 | sc_find="swagger\-validator\-v2\:v$SC_LAST_RELEASE" 38 | sc_replace="swagger-validator-v2:v$SC_VERSION" 39 | sed -i -e "s/$sc_find/$sc_replace/g" $CUR/README.md 40 | 41 | 42 | sc_find="version\: $SC_VERSION\-SNAPSHOT" 43 | sc_replace="version: $SC_VERSION" 44 | sed -i -e "s/$sc_find/$sc_replace/g" $CUR/src/main/swagger/swagger.yaml 45 | 46 | 47 | 48 | ##################### 49 | ### build and test maven ### 50 | ##################### 51 | mvn --no-transfer-progress -B install --file pom.xml 52 | 53 | -------------------------------------------------------------------------------- /CI/publishRelease.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import ghApiClient 5 | 6 | def lastReleaseId(tag): 7 | content = ghApiClient.readUrl('repos/swagger-api/validator-badge/releases') 8 | for l in content: 9 | draft = l["draft"] 10 | draft_tag = l["tag_name"] 11 | if str(draft) == 'True' and tag == draft_tag: 12 | return l["id"] 13 | 14 | def publishRelease(tag): 15 | id = lastReleaseId(tag) 16 | payload = "{\"tag_name\":\"" + tag + "\", " 17 | payload += "\"draft\":" + "false" + ", " 18 | payload += "\"target_commitish\":\"" + "master" + "\"}" 19 | content = ghApiClient.postUrl('repos/swagger-api/validator-badge/releases/' + str(id), payload) 20 | return content 21 | 22 | # main 23 | def main(tag): 24 | publishRelease (tag) 25 | 26 | # here start main 27 | main(sys.argv[1]) 28 | -------------------------------------------------------------------------------- /CI/releaseNotes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import json 5 | from datetime import datetime 6 | import ghApiClient 7 | 8 | def allPulls(releaseDate): 9 | 10 | result = "" 11 | 12 | baseurl = "https://api.github.com/repos/swagger-api/validator-badge/pulls/" 13 | content = ghApiClient.readUrl('repos/swagger-api/validator-badge/pulls?state=closed&base=master&per_page=100') 14 | for l in content: 15 | stripped = l["url"][len(baseurl):] 16 | mergedAt = l["merged_at"] 17 | if mergedAt is not None: 18 | if datetime.strptime(mergedAt, '%Y-%m-%dT%H:%M:%SZ') > releaseDate: 19 | if not l['title'].startswith("bump snap"): 20 | result += '\n' 21 | result += "* " + l['title'] + " (#" + stripped + ")" 22 | return result 23 | 24 | 25 | def lastReleaseDate(tag): 26 | content = ghApiClient.readUrl('repos/swagger-api/validator-badge/releases/tags/' + tag) 27 | publishedAt = content["published_at"] 28 | return datetime.strptime(publishedAt, '%Y-%m-%dT%H:%M:%SZ') 29 | 30 | 31 | def addRelease(release_title, tag, content): 32 | payload = "{\"tag_name\":\"" + tag + "\", " 33 | payload += "\"name\":" + json.dumps(release_title) + ", " 34 | payload += "\"body\":" + json.dumps(content) + ", " 35 | payload += "\"draft\":" + "true" + ", " 36 | payload += "\"prerelease\":" + "false" + ", " 37 | payload += "\"target_commitish\":\"" + "master" + "\"}" 38 | content = ghApiClient.postUrl('repos/swagger-api/validator-badge/releases', payload) 39 | return content 40 | 41 | def getReleases(): 42 | content = ghApiClient.readUrl('repos/swagger-api/validator-badge/releases') 43 | return content 44 | 45 | # main 46 | def main(last_release, release_title, tag): 47 | result = allPulls(lastReleaseDate('v' + last_release)) 48 | addRelease (release_title, tag, result) 49 | 50 | # here start main 51 | main(sys.argv[1], sys.argv[2], sys.argv[3]) 52 | 53 | -------------------------------------------------------------------------------- /CI/version.sh: -------------------------------------------------------------------------------- 1 | grep version pom.xml | grep -v -e '//g' | awk '{print $1}' -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine 2 | 3 | WORKDIR /validator 4 | 5 | COPY target/lib/jetty-runner.jar /validator/jetty-runner.jar 6 | COPY target/*.war /validator/server.war 7 | COPY src/main/swagger/swagger.yaml /validator/ 8 | COPY inflector.yaml /validator/ 9 | 10 | ENV REJECT_REDIRECT "true" 11 | ENV REJECT_LOCAL "true" 12 | EXPOSE 8080 13 | 14 | CMD java -jar -DswaggerUrl=swagger.yaml -DrejectLocal=${REJECT_LOCAL} -DrejectRedirect=${REJECT_REDIRECT} /validator/jetty-runner.jar /validator/server.war 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright (c) 2015. SmartBear Software Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Swagger Validator - ${pom.name} 2 | Copyright (c) 2015. SmartBear Software Inc. 3 | Swagger Validator - ${pom.name} is licensed under Apache 2.0 license. 4 | Copy of the Apache 2.0 license can be found in `LICENSE` file. 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swagger Validator Badge 2 | 3 | [![Build Status](https://img.shields.io/jenkins/build.svg?jobUrl=https://jenkins.swagger.io/job/oss-swagger-validator-badge-master)](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-validator-badge-master) 4 | 5 | This project shows a "valid swagger" badge on your site, supporting Swagger/OpenAPI 2.0 and OpenAPI 3.x specifications. 6 | 7 | There is an online version hosted on http://validator.swagger.io. 8 | 9 | ### Using Docker 10 | 11 | You can also pull a docker image of the validator directly from [DockerHub](https://hub.docker.com/r/swaggerapi/swagger-validator-v2/), e.g.: 12 | 13 | ``` 14 | docker pull swaggerapi/swagger-validator-v2:v2.1.7 15 | docker run -it -p 8080:8080 --name swagger-validator-v2 swaggerapi/swagger-validator-v2:v2.1.7 16 | ``` 17 | 18 | Since version `2.0.2` local and non http/https urls are rejected by default, along with redirects; this is controllable with docker env variables / java system properties: 19 | 20 | ``` 21 | docker run -it -p 8080:8080 -e "REJECT_LOCAL=false" -e "REJECT_REDIRECT=false" --name swagger-validator-v2 swaggerapi/swagger-validator-v2:v2.1.7 22 | ``` 23 | 24 | In non docker environments, system properties `rejectLocal` and `rejectRedirect` can be used. 25 | 26 | 27 | 28 | Web UI is reachable at http://localhost:8080/index.html and OpenAPI spec at http://localhost:8080/validator/openapi.json 29 | 30 | 31 | 32 | You can validate OpenAPI specifications version 2.0 (Swagger), 3.0 and 3.1. [Swagger Parser](https://github.com/swagger-api/swagger-parser/blob/master/README.md) is used for semantic validation. 33 | Depending on `jsonSchemaValidation` query parameter value also JSON Schema validation can be executed (default to `true`) 34 | 35 | Additional parameters allow to customize parsing and validation mode. 36 | 37 | ``` 38 | 39 | ``` 40 | 41 | Of course the `YOUR_URL` needs to be addressable by the validator (i.e. won't find anything on localhost). If it validates, you'll get a nice green VALID logo. Failures will give an INVALID logo, and if there are errors parsing the specification or reaching it, an ugly red ERROR logo. 42 | 43 | For example, using [https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/petstore-expanded.json](https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/petstore-expanded.json) as a source, we get ... 44 | 45 | ![](https://validator.swagger.io/validator?url=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/petstore-expanded.json) 46 | 47 | If your specification fails to validate for some reason, or if there is an error, you can get more information on why by visiting ```https://validator.swagger.io/validator/debug?url={YOUR_URL}```. 48 | 49 | Since the validator uses a browserless back-end to fetch the contents and schema, it's not subject to the terrible world of CORS. 50 | 51 | ### Using cURL 52 | 53 | You can also post a spec up to the service with cURL: 54 | 55 | ```bash 56 | curl -X POST -d @swagger.json -H 'Content-Type:application/json' https://validator.swagger.io/validator/debug 57 | ``` 58 | 59 | In this example, `swagger.json` is the swagger definition in JSON format, in the CWD. 60 | 61 | If your swagger definition file is in YAML format, the command needs to be adapted like so: 62 | 63 | ```bash 64 | curl --data-binary @swagger.yaml -H 'Content-Type:application/yaml' https://validator.swagger.io/validator/debug 65 | ``` 66 | 67 | Note the use of `--data-binary` to avoid stripping newlines, along with a different `Content-Type` header. 68 | 69 | ### Note 70 | 71 | All of the above is also applicable to OpenAPI 3.x specifications; for example, using [https://petstore3.swagger.io/api/v3/openapi.json](https://petstore3.swagger.io/api/v3/openapi.json) as a source, we get ... 72 | 73 | ![](https://validator.swagger.io/validator?url=https://petstore3.swagger.io/api/v3/openapi.json) 74 | 75 | Since version 2.1.0 a `/parseByUrl` and `/parseByContent` are available, returning a serialized parsed specification, with parsing and result configurable by 76 | parameters, e.g. passing `resolve`, etc. See [Swagger Parser](https://github.com/swagger-api/swagger-parser/blob/master/README.md#options). 77 | 78 | ### Running locally 79 | 80 | You can build and run the validator locally: 81 | 82 | ```bash 83 | mvn package jetty:run 84 | ``` 85 | 86 | And access the validator like such: 87 | 88 | ``` 89 | http://localhost:8080/validator?url={URL} 90 | ``` 91 | 92 | or 93 | 94 | ``` 95 | http://localhost:8080/validator?url=http://petstore.swagger.io/v2/swagger.json 96 | ``` 97 | ``` 98 | http://localhost:8080/validator?url=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yaml 99 | ``` 100 | 101 | ## Security contact 102 | 103 | Please disclose any security-related issues or vulnerabilities by emailing [security@swagger.io](mailto:security@swagger.io), instead of using the public issue tracker. 104 | -------------------------------------------------------------------------------- /inflector.yaml: -------------------------------------------------------------------------------- 1 | controllerPackage: io.swagger.handler 2 | modelPackage: io.swagger.models 3 | swaggerUrl: ./src/main/swagger/swagger.yaml 4 | 5 | entityProcessors: 6 | - json 7 | - yaml 8 | 9 | rootPath: /validator 10 | 11 | exposedSpecOptions: 12 | useOriginalNotParsed: true 13 | 14 | environment: production 15 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | io.swagger.validator.v3 4 | swagger-validator 5 | war 6 | swagger-validator 7 | swagger-validator 8 | 2.1.8-SNAPSHOT 9 | https://github.com/swagger-api/validator-badge 10 | 11 | 12 | frantuma 13 | Francesco Tumanischvili 14 | frantuma@yahoo.com 15 | 16 | 17 | 18 | 2.2.0 19 | 20 | 21 | github 22 | https://github.com/swagger-api/validator-badge/issues 23 | 24 | 25 | 26 | Apache License, Version 2.0 27 | http://www.apache.org/licenses/LICENSE-2.0.txt 28 | repo 29 | 30 | 31 | 32 | scm:git:git@github.com:swagger-api/validator-badge.git 33 | scm:git:git@github.com:swagger-api/validator-badge.git 34 | https://github.com/swagger-api/validator-badge 35 | 36 | 37 | install 38 | target 39 | ${project.artifactId}-${project.version} 40 | 41 | 42 | src/main/resources 43 | 44 | 45 | META-INF 46 | ../.. 47 | true 48 | 49 | NOTICE 50 | LICENSE 51 | 52 | 53 | 54 | 55 | 56 | org.jvnet.wagon-svn 57 | wagon-svn 58 | 1.12 59 | 60 | 61 | org.apache.maven.wagon 62 | wagon-ssh-external 63 | 3.5.3 64 | 65 | 66 | org.apache.maven.wagon 67 | wagon-webdav 68 | 1.0-beta-2 69 | 70 | 71 | 72 | 73 | maven-compiler-plugin 74 | 3.13.0 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-source-plugin 79 | 3.3.0 80 | 81 | 82 | attach-sources 83 | verify 84 | 85 | jar-no-fork 86 | 87 | 88 | 89 | 90 | 91 | org.apache.maven.plugins 92 | maven-surefire-plugin 93 | 3.2.3 94 | 95 | 96 | maven-dependency-plugin 97 | 98 | 99 | package 100 | 101 | copy-dependencies 102 | copy 103 | 104 | 105 | ${project.build.directory}/lib 106 | 107 | 108 | org.eclipse.jetty 109 | jetty-runner 110 | ${jetty-version} 111 | jetty-runner.jar 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-jar-plugin 121 | 3.3.0 122 | 123 | 124 | **/logback.xml 125 | 126 | 127 | 128 | development 129 | ${project.url} 130 | ${project.version} 131 | io.swagger 132 | 133 | 134 | 135 | 136 | 137 | org.eclipse.jetty 138 | jetty-maven-plugin 139 | ${jetty-version} 140 | 141 | . 142 | 143 | inflector.yaml 144 | src/main/swagger/swagger.yaml 145 | 146 | 1 147 | 148 | / 149 | 150 | target/${project.artifactId}-${project.version} 151 | 152 | 8080 153 | 60000 154 | 155 | 156 | 157 | 158 | com.googlecode.maven-download-plugin 159 | download-maven-plugin 160 | 1.7.1 161 | 162 | 163 | swagger-ui 164 | validate 165 | 166 | wget 167 | 168 | 169 | true 170 | https://github.com/swagger-api/swagger-ui/archive/master.tar.gz 171 | true 172 | ${project.build.directory} 173 | 174 | 175 | 176 | 177 | 178 | maven-resources-plugin 179 | 3.3.1 180 | 181 | 182 | copy-resources 183 | prepare-package 184 | 185 | copy-resources 186 | 187 | 188 | target/${project.artifactId}-${project.version} 189 | 190 | 191 | ${project.build.directory}/swagger-ui-master/dist 192 | true 193 | 194 | index.html 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | org.apache.maven.plugins 204 | maven-javadoc-plugin 205 | 3.6.2 206 | 207 | true 208 | 1.8 209 | UTF-8 210 | 1g 211 | 212 | http://docs.oracle.com/javase/8/docs/api 213 | 214 | ${javadoc.package.exclude} 215 | 216 | 217 | 218 | attach-javadocs 219 | verify 220 | 221 | jar 222 | 223 | 224 | 225 | 226 | 227 | org.sonatype.central 228 | central-publishing-maven-plugin 229 | 0.7.0 230 | true 231 | 232 | central 233 | true 234 | published 235 | 3600 236 | 237 | 238 | 239 | 240 | 241 | 242 | org.apache.maven.plugins 243 | maven-gpg-plugin 244 | 1.6 245 | 246 | 247 | 248 | --pinentry-mode 249 | loopback 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | release 259 | 260 | 261 | 262 | org.apache.maven.plugins 263 | maven-gpg-plugin 264 | 1.6 265 | 266 | 267 | 268 | --pinentry-mode 269 | loopback 270 | 271 | 272 | 273 | 274 | sign-artifacts 275 | verify 276 | 277 | sign 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | io.swagger.parser.v3 289 | swagger-parser 290 | ${swagger-parser-version} 291 | 292 | 293 | org.slf4j 294 | slf4j-api 295 | 296 | 297 | 298 | 299 | 300 | io.swagger 301 | swagger-inflector 302 | ${swagger-inflector-version} 303 | 304 | 305 | org.slf4j 306 | slf4j-ext 307 | 308 | 309 | org.slf4j 310 | slf4j-api 311 | 312 | 313 | ch.qos.logback 314 | logback-classic 315 | 316 | 317 | 318 | 319 | 320 | com.github.java-json-tools 321 | json-schema-validator 322 | ${json-schema-validator-version} 323 | 324 | 325 | 326 | com.networknt 327 | json-schema-validator 328 | ${nt-json-schema-validator-version} 329 | 330 | 331 | org.slf4j 332 | slf4j-api 333 | 334 | 335 | 336 | 337 | 338 | com.fasterxml.jackson.core 339 | jackson-core 340 | ${jackson.version} 341 | 342 | 343 | 344 | com.fasterxml.jackson.core 345 | jackson-databind 346 | ${jackson-databind.version} 347 | 348 | 349 | 350 | com.fasterxml.jackson.jaxrs 351 | jackson-jaxrs-yaml-provider 352 | ${jackson.version} 353 | 354 | 355 | 356 | com.fasterxml.jackson.jaxrs 357 | jackson-jaxrs-json-provider 358 | ${jackson.version} 359 | 360 | 361 | 362 | org.yaml 363 | snakeyaml 364 | ${snakeyaml.version} 365 | 366 | 367 | 368 | org.apache.httpcomponents 369 | httpclient 370 | ${httpclient-version} 371 | 372 | 373 | junit 374 | junit 375 | ${junit-version} 376 | test 377 | 378 | 379 | org.slf4j 380 | slf4j-api 381 | 382 | 383 | 384 | 385 | org.assertj 386 | assertj-core 387 | ${assertj-version} 388 | test 389 | 390 | 391 | org.wiremock 392 | wiremock 393 | ${wiremock-version} 394 | test 395 | 396 | 397 | org.slf4j 398 | slf4j-api 399 | 400 | 401 | 402 | 403 | ch.qos.logback 404 | logback-classic 405 | ${logback-version} 406 | test 407 | 408 | 409 | ch.qos.logback 410 | logback-core 411 | ${logback-version} 412 | test 413 | 414 | 415 | org.slf4j 416 | slf4j-api 417 | ${slf4j-version} 418 | 419 | 420 | 421 | 8 422 | 2.19.0 423 | 2.19.0 424 | 2.4 425 | 4.5.14 426 | 1.0.0 427 | 2.1.28 428 | 2.0.13 429 | 9.4.56.v20240826 430 | 1.5.18 431 | 2.0.16 432 | 3.1.2 433 | 3.13.0 434 | 4.13.2 435 | 3.27.3 436 | 2.2.14 437 | 1.5.6 438 | UTF-8 439 | 440 | 441 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/Utils.java: -------------------------------------------------------------------------------- 1 | package io.swagger; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import io.swagger.v3.core.util.Json; 5 | import io.swagger.v3.core.util.Yaml; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.apache.http.HttpEntity; 8 | import org.apache.http.StatusLine; 9 | import org.apache.http.client.config.RequestConfig; 10 | import org.apache.http.client.methods.CloseableHttpResponse; 11 | import org.apache.http.client.methods.HttpGet; 12 | import org.apache.http.conn.ssl.NoopHostnameVerifier; 13 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 14 | import org.apache.http.impl.client.CloseableHttpClient; 15 | import org.apache.http.impl.client.HttpClientBuilder; 16 | import org.apache.http.impl.client.HttpClients; 17 | import org.apache.http.ssl.SSLContextBuilder; 18 | import org.apache.http.ssl.TrustStrategy; 19 | import org.apache.http.util.EntityUtils; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import java.io.BufferedReader; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.io.InputStreamReader; 27 | import java.net.InetAddress; 28 | import java.net.URL; 29 | import java.security.KeyManagementException; 30 | import java.security.KeyStoreException; 31 | import java.security.NoSuchAlgorithmException; 32 | import java.security.cert.CertificateException; 33 | import java.security.cert.X509Certificate; 34 | import java.util.stream.Collectors; 35 | 36 | public class Utils { 37 | 38 | public static enum VERSION { 39 | V1, 40 | V20, 41 | V30, 42 | V31, 43 | NONE 44 | } 45 | 46 | static Logger LOGGER = LoggerFactory.getLogger(Utils.class); 47 | public static String getVersionString(JsonNode node) { 48 | if (node == null) { 49 | return null; 50 | } 51 | 52 | JsonNode version = node.get("openapi"); 53 | if (version != null) { 54 | return version.toString(); 55 | } 56 | 57 | version = node.get("swagger"); 58 | if (version != null) { 59 | return version.toString(); 60 | } 61 | version = node.get("swaggerVersion"); 62 | if (version != null) { 63 | return version.toString(); 64 | } 65 | 66 | LOGGER.debug("version not found!"); 67 | return null; 68 | } 69 | 70 | public static VERSION getVersion(JsonNode node) { 71 | String version = getVersionString(node); 72 | if (StringUtils.isBlank(version)) { 73 | return VERSION.NONE; 74 | } 75 | if (version.startsWith("\"1") || version.startsWith("1")) { 76 | return VERSION.V1; 77 | } 78 | if (version.startsWith("\"2") || version.startsWith("2")) { 79 | return VERSION.V20; 80 | } 81 | if (version.startsWith("\"3.0") || version.startsWith("3.0")) { 82 | return VERSION.V30; 83 | } 84 | if (version.startsWith("\"3.1") || version.startsWith("3.1")) { 85 | return VERSION.V31; 86 | } 87 | return VERSION.NONE; 88 | 89 | } 90 | 91 | 92 | public static JsonNode readNode(String text) { 93 | try { 94 | if (text.trim().startsWith("{")) { 95 | return Json.mapper().readTree(text); 96 | } else { 97 | return Yaml.mapper().readTree(text); 98 | } 99 | } catch (IOException e) { 100 | return null; 101 | } 102 | } 103 | 104 | public static CloseableHttpClient getCarelessHttpClient(boolean disableRedirect) { 105 | CloseableHttpClient httpClient = null; 106 | 107 | try { 108 | SSLContextBuilder builder = new SSLContextBuilder(); 109 | builder.loadTrustMaterial(null, new TrustStrategy() { 110 | public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { 111 | return true; 112 | } 113 | }); 114 | SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE); 115 | HttpClientBuilder httpClientBuilder = HttpClients 116 | .custom() 117 | .setSSLSocketFactory(sslsf); 118 | if (disableRedirect) { 119 | httpClientBuilder.disableRedirectHandling(); 120 | } 121 | httpClientBuilder.setUserAgent("swagger-validator"); 122 | httpClient = httpClientBuilder.build(); 123 | } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { 124 | LOGGER.error("can't disable SSL verification", e); 125 | } 126 | 127 | return httpClient; 128 | } 129 | 130 | 131 | public static String getUrlContents(String urlString) throws IOException { 132 | return getUrlContents(urlString, false, false); 133 | } 134 | public static String getUrlContents(String urlString, boolean rejectLocal, boolean rejectRedirect) throws IOException { 135 | LOGGER.trace("fetching URL contents"); 136 | URL url = new URL(urlString); 137 | if(rejectLocal) { 138 | InetAddress inetAddress = InetAddress.getByName(url.getHost()); 139 | if(inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isLinkLocalAddress()) { 140 | throw new IOException("Only accepts http/https protocol"); 141 | } 142 | } 143 | final CloseableHttpClient httpClient = getCarelessHttpClient(rejectRedirect); 144 | 145 | RequestConfig.Builder requestBuilder = RequestConfig.custom(); 146 | requestBuilder = requestBuilder 147 | .setConnectTimeout(5000) 148 | .setSocketTimeout(5000); 149 | 150 | HttpGet getMethod = new HttpGet(urlString); 151 | getMethod.setConfig(requestBuilder.build()); 152 | getMethod.setHeader("Accept", "application/json, */*"); 153 | 154 | 155 | if (httpClient != null) { 156 | final CloseableHttpResponse response = httpClient.execute(getMethod); 157 | 158 | try { 159 | 160 | HttpEntity entity = response.getEntity(); 161 | StatusLine line = response.getStatusLine(); 162 | if(line.getStatusCode() > 299 || line.getStatusCode() < 200) { 163 | throw new IOException("failed to read swagger with code " + line.getStatusCode()); 164 | } 165 | return EntityUtils.toString(entity, "UTF-8"); 166 | } finally { 167 | response.close(); 168 | httpClient.close(); 169 | } 170 | } else { 171 | throw new IOException("CloseableHttpClient could not be initialized"); 172 | } 173 | } 174 | 175 | public static String getResourceFileAsString(String fileName) { 176 | InputStream is = Utils.class.getClassLoader().getResourceAsStream(fileName); 177 | if (is != null) { 178 | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 179 | return reader.lines().collect(Collectors.joining(System.lineSeparator())); 180 | } 181 | return null; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/jsonschema/FgeValidator.java: -------------------------------------------------------------------------------- 1 | package io.swagger.jsonschema; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.fasterxml.jackson.databind.node.ObjectNode; 5 | import com.github.fge.jsonschema.core.report.ListProcessingReport; 6 | import com.github.fge.jsonschema.core.report.ProcessingMessage; 7 | import com.github.fge.jsonschema.core.report.ProcessingReport; 8 | import com.github.fge.jsonschema.main.JsonSchema; 9 | import com.github.fge.jsonschema.main.JsonSchemaFactory; 10 | import io.swagger.Utils; 11 | import io.swagger.models.SchemaValidationError; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class FgeValidator extends Validator { 16 | 17 | static final String SCHEMA30_FILE_FGE = "schemas/30/schema3-fix-format-uri-reference.json"; 18 | static final String SCHEMA20_FILE_FGE = "schemas/20/schema.json"; 19 | 20 | public FgeValidator() { 21 | super(); 22 | schemaLocations.get(Utils.VERSION.V30).path = SCHEMA30_FILE_FGE; 23 | schemaLocations.get(Utils.VERSION.V20).path = SCHEMA20_FILE_FGE; 24 | schemaLocations.get(Utils.VERSION.V30).url = null; 25 | } 26 | 27 | public boolean supports(Utils.VERSION version) { 28 | switch(version) { 29 | case V20: 30 | case V30: 31 | return true; 32 | default: 33 | return false; 34 | } 35 | } 36 | public JsonSchema buildSchema(JsonNode schemaNode, Utils.VERSION version) throws Exception{ 37 | JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); 38 | return factory.getJsonSchema(schemaNode); 39 | } 40 | 41 | public JsonNode customizeSchema(JsonNode schemaNode, Utils.VERSION version) { 42 | ObjectNode oNode = (ObjectNode) schemaNode; 43 | if (Utils.VERSION.V30.equals(version)) { 44 | if (oNode.get("id") != null) { 45 | oNode.remove("id"); 46 | } 47 | if (oNode.get("$schema") != null) { 48 | oNode.remove("$schema"); 49 | } 50 | if (oNode.get("description") != null) { 51 | oNode.remove("description"); 52 | } 53 | } 54 | return oNode; 55 | } 56 | 57 | public List validate(JsonNode spec, Utils.VERSION version, String location){ 58 | List output = new ArrayList<>(); 59 | 60 | try { 61 | JsonSchema schema = (JsonSchema) loadSchema(version); 62 | ProcessingReport report = schema.validate(spec); 63 | ListProcessingReport lp = new ListProcessingReport(); 64 | lp.mergeWith(report); 65 | 66 | java.util.Iterator it = lp.iterator(); 67 | while (it.hasNext()) { 68 | ProcessingMessage pm = it.next(); 69 | output.add(new SchemaValidationError(pm.asJson())); 70 | } 71 | } catch (Exception e) { 72 | LOGGER.error("Error in FGE JSON Schema Validation", e); 73 | } 74 | return output; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/jsonschema/NetworkntValidator.java: -------------------------------------------------------------------------------- 1 | package io.swagger.jsonschema; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.networknt.schema.JsonSchema; 5 | import com.networknt.schema.JsonSchemaFactory; 6 | import com.networknt.schema.SpecVersion; 7 | import com.networknt.schema.SpecVersionDetector; 8 | import com.networknt.schema.ValidationMessage; 9 | import io.swagger.Utils; 10 | import io.swagger.models.SchemaValidationError; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Set; 14 | 15 | public class NetworkntValidator extends Validator{ 16 | 17 | 18 | public boolean supports(Utils.VERSION version) { 19 | switch(version) { 20 | case V20: 21 | case V30: 22 | return true; 23 | case V31: 24 | default: 25 | return false; 26 | } 27 | } 28 | public JsonSchema buildSchema(JsonNode schemaNode, Utils.VERSION version) throws Exception{ 29 | SpecVersion.VersionFlag v = SpecVersionDetector.detect(schemaNode); 30 | JsonSchemaFactory factory = JsonSchemaFactory.getInstance(v); 31 | return factory.getSchema(schemaNode); 32 | } 33 | 34 | public List validate(JsonNode spec, Utils.VERSION version, String location){ 35 | List output = new ArrayList<>(); 36 | 37 | try { 38 | JsonSchema schema = (JsonSchema) loadSchema(version); 39 | Set errors = schema.validate(spec); 40 | for (ValidationMessage m: errors) { 41 | output.add(new SchemaValidationError(m.getMessage(), "error")); 42 | } 43 | } catch (Exception e) { 44 | LOGGER.error("Error in NetworkNt JSON Schema Validation", e); 45 | } 46 | return output; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/jsonschema/Validator.java: -------------------------------------------------------------------------------- 1 | package io.swagger.jsonschema; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import io.swagger.Utils; 5 | import io.swagger.models.SchemaValidationError; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | public abstract class Validator { 14 | 15 | static final String SCHEMA20_FILE = "schemas/20/official.json"; 16 | static final String SCHEMA20_URL = "http://swagger.io/v2/schema.json"; 17 | 18 | 19 | static final String SCHEMA30_FILE = "schemas/30/official.json"; 20 | // static final String SCHEMA30_FILE = "schemas/30/schema3.json"; 21 | static final String SCHEMA30_URL = "https://spec.openapis.org/oas/3.0/schema/2021-09-28"; 22 | 23 | static final String SCHEMA31_FILE = "schemas/31/schema-base.json"; 24 | static final String SCHEMA31_URL = "https://spec.openapis.org/oas/3.1/schema-base/2022-10-07"; 25 | 26 | static Logger LOGGER = LoggerFactory.getLogger(Validator.class); 27 | 28 | static class SchemaLocation { 29 | public SchemaLocation(String path, String url) { 30 | this.path = path; 31 | this.url = url; 32 | } 33 | public String path; 34 | public String url; 35 | public String content; 36 | public JsonNode node; 37 | public Object schemaObject; 38 | public long lastFetch; 39 | } 40 | protected Map schemaLocations = new ConcurrentHashMap<>(); 41 | 42 | public Validator() { 43 | schemaLocations.put(Utils.VERSION.V20, new SchemaLocation(SCHEMA20_FILE, SCHEMA20_URL)); 44 | schemaLocations.put(Utils.VERSION.V30, new SchemaLocation(SCHEMA30_FILE, SCHEMA30_URL)); 45 | schemaLocations.put(Utils.VERSION.V31, new SchemaLocation(SCHEMA31_FILE, SCHEMA31_URL)); 46 | } 47 | 48 | public abstract boolean supports(Utils.VERSION version); 49 | public abstract List validate(JsonNode spec, Utils.VERSION version, String location); 50 | 51 | public abstract Object buildSchema(JsonNode schemaNode, Utils.VERSION version) throws Exception; 52 | 53 | public JsonNode customizeSchema(JsonNode schemaNode, Utils.VERSION version) { 54 | return schemaNode; 55 | } 56 | public Object loadSchema(Utils.VERSION version) { 57 | 58 | SchemaLocation loc = schemaLocations.get(version); 59 | 60 | if (loc != null && (System.currentTimeMillis() - loc.lastFetch) < 600000) { 61 | return loc.schemaObject; 62 | } 63 | 64 | try { 65 | return loadSchemaFromNetwork(loc, version); 66 | } catch (Exception e) { 67 | LOGGER.warn("error fetching schema from network, using local copy"); 68 | try { 69 | return loadSchemaFromFile(loc, version); 70 | } catch (Exception ex) { 71 | LOGGER.warn("error fetching schema from file, aborting"); 72 | return null; 73 | } 74 | } 75 | } 76 | public Object loadSchemaFromNetwork(SchemaLocation loc, Utils.VERSION version) throws Exception { 77 | if (StringUtils.isBlank(loc.url)) { 78 | throw new Exception("empty URL"); 79 | } 80 | LOGGER.debug("returning online schema"); 81 | loc.content = Utils.getUrlContents(loc.url); 82 | loc.node = customizeSchema(Utils.readNode(loc.content), version); 83 | loc.schemaObject = buildSchema(loc.node, version); 84 | loc.lastFetch = System.currentTimeMillis(); 85 | return loc.schemaObject; 86 | } 87 | public Object loadSchemaFromFile(SchemaLocation loc, Utils.VERSION version) throws Exception { 88 | LOGGER.debug("returning local schema"); 89 | loc.content = Utils.getResourceFileAsString(loc.path); 90 | loc.node = customizeSchema(Utils.readNode(loc.content), version); 91 | loc.schemaObject = buildSchema(loc.node, version); 92 | loc.lastFetch = System.currentTimeMillis(); 93 | return loc.schemaObject; 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/models/Instance.java: -------------------------------------------------------------------------------- 1 | package io.swagger.models; 2 | 3 | public class Instance { 4 | private String pointer; 5 | 6 | public String getPointer() { 7 | return pointer; 8 | } 9 | 10 | public void setPointer(String pointer) { 11 | this.pointer = pointer; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/models/Schema.java: -------------------------------------------------------------------------------- 1 | package io.swagger.models; 2 | 3 | public class Schema { 4 | private String loadingURI, pointer; 5 | 6 | public String getLoadingURI() { 7 | return loadingURI; 8 | } 9 | 10 | public void setLoadingURI(String loadingURI) { 11 | this.loadingURI = loadingURI; 12 | } 13 | 14 | public String getPointer() { 15 | return pointer; 16 | } 17 | 18 | public void setPointer(String pointer) { 19 | this.pointer = pointer; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/models/SchemaValidationError.java: -------------------------------------------------------------------------------- 1 | package io.swagger.models; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.fasterxml.jackson.databind.node.ArrayNode; 5 | 6 | import java.util.List; 7 | 8 | public class SchemaValidationError { 9 | private String level, domain, keyword, message; 10 | private Schema schema; 11 | private Instance instance; 12 | private List required; 13 | private List missing; 14 | 15 | public SchemaValidationError() { 16 | } 17 | 18 | public SchemaValidationError(String message, String level) { 19 | this.message = message; 20 | this.level = level; 21 | } 22 | public SchemaValidationError(JsonNode node) { 23 | JsonNode prop = node.get("level"); 24 | if (prop != null) { 25 | level = prop.asText(); 26 | } 27 | 28 | prop = node.get("domain"); 29 | if (prop != null) { 30 | domain = prop.asText(); 31 | } 32 | 33 | prop = node.get("keyword"); 34 | if (prop != null) { 35 | keyword = prop.asText(); 36 | } 37 | 38 | prop = node.get("message"); 39 | if (prop != null) { 40 | message = prop.asText(); 41 | } 42 | 43 | prop = node.get("schema"); 44 | if (prop != null) { 45 | schema = new Schema(); 46 | JsonNode s = prop; 47 | prop = s.get("loadingURI"); 48 | if (prop != null) { 49 | schema.setLoadingURI(prop.asText()); 50 | } 51 | prop = s.get("pointer"); 52 | if (prop != null) { 53 | schema.setPointer(prop.asText()); 54 | } 55 | } 56 | 57 | prop = node.get("instance"); 58 | if (prop != null) { 59 | instance = new Instance(); 60 | JsonNode s = prop; 61 | prop = s.get("pointer"); 62 | if (prop != null) { 63 | instance.setPointer(prop.asText()); 64 | } 65 | } 66 | 67 | prop = node.get("required"); 68 | if (prop != null && prop.isArray()) { 69 | ArrayNode an = (ArrayNode) prop; 70 | } 71 | } 72 | 73 | public String getLevel() { 74 | return level; 75 | } 76 | 77 | public void setLevel(String level) { 78 | this.level = level; 79 | } 80 | 81 | public String getDomain() { 82 | return domain; 83 | } 84 | 85 | public void setDomain(String domain) { 86 | this.domain = domain; 87 | } 88 | 89 | public String getKeyword() { 90 | return keyword; 91 | } 92 | 93 | public void setKeyword(String keyword) { 94 | this.keyword = keyword; 95 | } 96 | 97 | public String getMessage() { 98 | return message; 99 | } 100 | 101 | public void setMessage(String message) { 102 | this.message = message; 103 | } 104 | 105 | public List getRequired() { 106 | return required; 107 | } 108 | 109 | public void setRequired(List required) { 110 | this.required = required; 111 | } 112 | 113 | public List getMissing() { 114 | return missing; 115 | } 116 | 117 | public void setMissing(List missing) { 118 | this.missing = missing; 119 | } 120 | 121 | public Schema getSchema() { 122 | return schema; 123 | } 124 | 125 | public void setSchema(Schema schema) { 126 | this.schema = schema; 127 | } 128 | 129 | public Instance getInstance() { 130 | return instance; 131 | } 132 | 133 | public void setInstance(Instance instance) { 134 | this.instance = instance; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/io/swagger/models/ValidationResponse.java: -------------------------------------------------------------------------------- 1 | package io.swagger.models; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.List; 6 | 7 | public class ValidationResponse { 8 | private List messages; 9 | private List schemaValidationMessages = null; 10 | 11 | public void addValidationMessage(SchemaValidationError schemaValidationError) { 12 | if(schemaValidationMessages == null) { 13 | this.schemaValidationMessages = new ArrayList(); 14 | } 15 | this.schemaValidationMessages.add(schemaValidationError); 16 | } 17 | 18 | public void addValidationMessages(Collection schemaValidationError) { 19 | if(schemaValidationMessages == null) { 20 | this.schemaValidationMessages = new ArrayList<>(); 21 | } 22 | this.schemaValidationMessages.addAll(schemaValidationError); 23 | } 24 | 25 | public void addMessage(String message) { 26 | if(this.messages == null) { 27 | this.messages = new ArrayList(); 28 | } 29 | this.messages.add(message); 30 | } 31 | 32 | public List getMessages() { 33 | return messages; 34 | } 35 | 36 | public void setMessages(List messages) { 37 | this.messages = messages; 38 | } 39 | 40 | public List getSchemaValidationMessages() { 41 | return schemaValidationMessages; 42 | } 43 | 44 | public void setSchemaValidationMessages(List validationMessages) { 45 | this.schemaValidationMessages = validationMessages; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/resources/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swagger-api/validator-badge/27ff4ec9962a2a7cc7bd7723914264ad0204f1d3/src/main/resources/error.png -------------------------------------------------------------------------------- /src/main/resources/invalid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swagger-api/validator-badge/27ff4ec9962a2a7cc7bd7723914264ad0204f1d3/src/main/resources/invalid.png -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/schemas/31/dialect/base.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "https://spec.openapis.org/oas/3.1/dialect/base", 3 | "$schema": "https://json-schema.org/draft/2020-12/schema", 4 | 5 | "title": "OpenAPI 3.1 Schema Object Dialect", 6 | "description": "A JSON Schema dialect describing schemas found in OpenAPI documents", 7 | 8 | "$vocabulary": { 9 | "https://json-schema.org/draft/2020-12/vocab/core": true, 10 | "https://json-schema.org/draft/2020-12/vocab/applicator": true, 11 | "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, 12 | "https://json-schema.org/draft/2020-12/vocab/validation": true, 13 | "https://json-schema.org/draft/2020-12/vocab/meta-data": true, 14 | "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, 15 | "https://json-schema.org/draft/2020-12/vocab/content": true, 16 | "https://spec.openapis.org/oas/3.1/vocab/base": false 17 | }, 18 | 19 | "$dynamicAnchor": "meta", 20 | 21 | "allOf": [ 22 | { "$ref": "https://json-schema.org/draft/2020-12/schema" }, 23 | { "$ref": "https://spec.openapis.org/oas/3.1/meta/base" } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/schemas/31/dialect/base.schema.yaml: -------------------------------------------------------------------------------- 1 | $id: https://spec.openapis.org/oas/3.1/dialect/base 2 | $schema: https://json-schema.org/draft/2020-12/schema 3 | 4 | title: OpenAPI 3.1 Schema Object Dialect 5 | description: A JSON Schema dialect describing schemas found in OpenAPI documents 6 | 7 | $dynamicAnchor: meta 8 | 9 | $vocabulary: 10 | https://json-schema.org/draft/2020-12/vocab/applicator: true 11 | https://json-schema.org/draft/2020-12/vocab/content: true 12 | https://json-schema.org/draft/2020-12/vocab/core: true 13 | https://json-schema.org/draft/2020-12/vocab/format-annotation: true 14 | https://json-schema.org/draft/2020-12/vocab/meta-data: true 15 | https://json-schema.org/draft/2020-12/vocab/unevaluated: true 16 | https://json-schema.org/draft/2020-12/vocab/validation: true 17 | https://spec.openapis.org/oas/3.1/vocab/base: false 18 | 19 | allOf: 20 | - $ref: https://json-schema.org/draft/2020-12/schema 21 | - $ref: https://spec.openapis.org/oas/3.1/meta/base 22 | -------------------------------------------------------------------------------- /src/main/resources/schemas/31/meta/base.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "https://spec.openapis.org/oas/3.1/meta/base", 3 | "$schema": "https://json-schema.org/draft/2020-12/schema", 4 | 5 | "title": "OAS Base vocabulary", 6 | "description": "A JSON Schema Vocabulary used in the OpenAPI Schema Dialect", 7 | 8 | "$vocabulary": { 9 | "https://spec.openapis.org/oas/3.1/vocab/base": true 10 | }, 11 | 12 | "$dynamicAnchor": "meta", 13 | 14 | "type": ["object", "boolean"], 15 | "properties": { 16 | "example": true, 17 | "discriminator": { "$ref": "#/$defs/discriminator" }, 18 | "externalDocs": { "$ref": "#/$defs/external-docs" }, 19 | "xml": { "$ref": "#/$defs/xml" } 20 | }, 21 | 22 | "$defs": { 23 | "extensible": { 24 | "patternProperties": { 25 | "^x-": true 26 | } 27 | }, 28 | 29 | "discriminator": { 30 | "$ref": "#/$defs/extensible", 31 | "type": "object", 32 | "properties": { 33 | "propertyName": { 34 | "type": "string" 35 | }, 36 | "mapping": { 37 | "type": "object", 38 | "additionalProperties": { 39 | "type": "string" 40 | } 41 | } 42 | }, 43 | "required": ["propertyName"], 44 | "unevaluatedProperties": false 45 | }, 46 | 47 | "external-docs": { 48 | "$ref": "#/$defs/extensible", 49 | "type": "object", 50 | "properties": { 51 | "url": { 52 | "type": "string", 53 | "format": "uri-reference" 54 | }, 55 | "description": { 56 | "type": "string" 57 | } 58 | }, 59 | "required": ["url"], 60 | "unevaluatedProperties": false 61 | }, 62 | 63 | "xml": { 64 | "$ref": "#/$defs/extensible", 65 | "type": "object", 66 | "properties": { 67 | "name": { 68 | "type": "string" 69 | }, 70 | "namespace": { 71 | "type": "string", 72 | "format": "uri" 73 | }, 74 | "prefix": { 75 | "type": "string" 76 | }, 77 | "attribute": { 78 | "type": "boolean" 79 | }, 80 | "wrapped": { 81 | "type": "boolean" 82 | } 83 | }, 84 | "unevaluatedProperties": false 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/resources/schemas/31/meta/base.schema.yaml: -------------------------------------------------------------------------------- 1 | $id: https://spec.openapis.org/oas/3.1/meta/base 2 | $schema: https://json-schema.org/draft/2020-12/schema 3 | 4 | title: OAS Base vocabulary 5 | description: A JSON Schema Vocabulary used in the OpenAPI Schema Dialect 6 | 7 | $dynamicAnchor: meta 8 | 9 | $vocabulary: 10 | https://spec.openapis.org/oas/3.1/vocab/base: true 11 | 12 | type: 13 | - object 14 | - boolean 15 | properties: 16 | discriminator: 17 | $ref: '#/$defs/discriminator' 18 | example: true 19 | externalDocs: 20 | $ref: '#/$defs/external-docs' 21 | xml: 22 | $ref: '#/$defs/xml' 23 | 24 | $defs: 25 | discriminator: 26 | $ref: '#/$defs/extensible' 27 | properties: 28 | mapping: 29 | additionalProperties: 30 | type: string 31 | type: object 32 | propertyName: 33 | type: string 34 | required: 35 | - propertyName 36 | type: object 37 | unevaluatedProperties: false 38 | 39 | extensible: 40 | patternProperties: 41 | ^x-: true 42 | external-docs: 43 | $ref: '#/$defs/extensible' 44 | properties: 45 | description: 46 | type: string 47 | url: 48 | format: uri-reference 49 | type: string 50 | required: 51 | - url 52 | type: object 53 | unevaluatedProperties: false 54 | 55 | xml: 56 | $ref: '#/$defs/extensible' 57 | properties: 58 | attribute: 59 | type: boolean 60 | name: 61 | type: string 62 | namespace: 63 | format: uri 64 | type: string 65 | prefix: 66 | type: string 67 | wrapped: 68 | type: boolean 69 | type: object 70 | unevaluatedProperties: false 71 | -------------------------------------------------------------------------------- /src/main/resources/schemas/31/schema-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "https://spec.openapis.org/oas/3.1/schema-base/2022-10-07", 3 | "$schema": "https://json-schema.org/draft/2020-12/schema", 4 | 5 | "description": "The description of OpenAPI v3.1.x documents using the OpenAPI JSON Schema dialect, as defined by https://spec.openapis.org/oas/v3.1.0", 6 | 7 | "$ref": "https://spec.openapis.org/oas/3.1/schema/2022-10-07", 8 | "properties": { 9 | "jsonSchemaDialect": { "$ref": "#/$defs/dialect" } 10 | }, 11 | 12 | "$defs": { 13 | "dialect": { "const": "https://spec.openapis.org/oas/3.1/dialect/base" }, 14 | 15 | "schema": { 16 | "$dynamicAnchor": "meta", 17 | "$ref": "https://spec.openapis.org/oas/3.1/dialect/base", 18 | "properties": { 19 | "$schema": { "$ref": "#/$defs/dialect" } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/schemas/31/schema-base.yaml: -------------------------------------------------------------------------------- 1 | $id: 'https://spec.openapis.org/oas/3.1/schema-base/2022-10-07' 2 | $schema: 'https://json-schema.org/draft/2020-12/schema' 3 | 4 | description: The description of OpenAPI v3.1.x documents using the OpenAPI JSON Schema dialect, as defined by https://spec.openapis.org/oas/v3.1.0 5 | 6 | $ref: 'https://spec.openapis.org/oas/3.1/schema/2022-10-07' 7 | properties: 8 | jsonSchemaDialect: 9 | $ref: '#/$defs/dialect' 10 | 11 | $defs: 12 | dialect: 13 | const: 'https://spec.openapis.org/oas/3.1/dialect/base' 14 | 15 | schema: 16 | $dynamicAnchor: meta 17 | $ref: 'https://spec.openapis.org/oas/3.1/dialect/base' 18 | properties: 19 | $schema: 20 | $ref: '#/$defs/dialect' 21 | -------------------------------------------------------------------------------- /src/main/resources/schemas/31/schema.yaml: -------------------------------------------------------------------------------- 1 | $id: 'https://spec.openapis.org/oas/3.1/schema/2022-10-07' 2 | $schema: 'https://json-schema.org/draft/2020-12/schema' 3 | 4 | description: The description of OpenAPI v3.1.x documents without schema validation, as defined by https://spec.openapis.org/oas/v3.1.0 5 | 6 | type: object 7 | properties: 8 | openapi: 9 | type: string 10 | pattern: '^3\.1\.\d+(-.+)?$' 11 | info: 12 | $ref: '#/$defs/info' 13 | jsonSchemaDialect: 14 | type: string 15 | format: uri 16 | default: 'https://spec.openapis.org/oas/3.1/dialect/base' 17 | servers: 18 | type: array 19 | items: 20 | $ref: '#/$defs/server' 21 | default: 22 | - url: / 23 | paths: 24 | $ref: '#/$defs/paths' 25 | webhooks: 26 | type: object 27 | additionalProperties: 28 | $ref: '#/$defs/path-item-or-reference' 29 | components: 30 | $ref: '#/$defs/components' 31 | security: 32 | type: array 33 | items: 34 | $ref: '#/$defs/security-requirement' 35 | tags: 36 | type: array 37 | items: 38 | $ref: '#/$defs/tag' 39 | externalDocs: 40 | $ref: '#/$defs/external-documentation' 41 | required: 42 | - openapi 43 | - info 44 | anyOf: 45 | - required: 46 | - paths 47 | - required: 48 | - components 49 | - required: 50 | - webhooks 51 | $ref: '#/$defs/specification-extensions' 52 | unevaluatedProperties: false 53 | 54 | $defs: 55 | info: 56 | $comment: https://spec.openapis.org/oas/v3.1.0#info-object 57 | type: object 58 | properties: 59 | title: 60 | type: string 61 | summary: 62 | type: string 63 | description: 64 | type: string 65 | termsOfService: 66 | type: string 67 | format: uri 68 | contact: 69 | $ref: '#/$defs/contact' 70 | license: 71 | $ref: '#/$defs/license' 72 | version: 73 | type: string 74 | required: 75 | - title 76 | - version 77 | $ref: '#/$defs/specification-extensions' 78 | unevaluatedProperties: false 79 | 80 | contact: 81 | $comment: https://spec.openapis.org/oas/v3.1.0#contact-object 82 | type: object 83 | properties: 84 | name: 85 | type: string 86 | url: 87 | type: string 88 | format: uri 89 | email: 90 | type: string 91 | format: email 92 | $ref: '#/$defs/specification-extensions' 93 | unevaluatedProperties: false 94 | 95 | license: 96 | $comment: https://spec.openapis.org/oas/v3.1.0#license-object 97 | type: object 98 | properties: 99 | name: 100 | type: string 101 | identifier: 102 | type: string 103 | url: 104 | type: string 105 | format: uri 106 | required: 107 | - name 108 | dependentSchemas: 109 | identifier: 110 | not: 111 | required: 112 | - url 113 | $ref: '#/$defs/specification-extensions' 114 | unevaluatedProperties: false 115 | 116 | server: 117 | $comment: https://spec.openapis.org/oas/v3.1.0#server-object 118 | type: object 119 | properties: 120 | url: 121 | type: string 122 | format: uri-reference 123 | description: 124 | type: string 125 | variables: 126 | type: object 127 | additionalProperties: 128 | $ref: '#/$defs/server-variable' 129 | required: 130 | - url 131 | $ref: '#/$defs/specification-extensions' 132 | unevaluatedProperties: false 133 | 134 | server-variable: 135 | $comment: https://spec.openapis.org/oas/v3.1.0#server-variable-object 136 | type: object 137 | properties: 138 | enum: 139 | type: array 140 | items: 141 | type: string 142 | minItems: 1 143 | default: 144 | type: string 145 | description: 146 | type: string 147 | required: 148 | - default 149 | $ref: '#/$defs/specification-extensions' 150 | unevaluatedProperties: false 151 | 152 | components: 153 | $comment: https://spec.openapis.org/oas/v3.1.0#components-object 154 | type: object 155 | properties: 156 | schemas: 157 | type: object 158 | additionalProperties: 159 | $dynamicRef: '#meta' 160 | responses: 161 | type: object 162 | additionalProperties: 163 | $ref: '#/$defs/response-or-reference' 164 | parameters: 165 | type: object 166 | additionalProperties: 167 | $ref: '#/$defs/parameter-or-reference' 168 | examples: 169 | type: object 170 | additionalProperties: 171 | $ref: '#/$defs/example-or-reference' 172 | requestBodies: 173 | type: object 174 | additionalProperties: 175 | $ref: '#/$defs/request-body-or-reference' 176 | headers: 177 | type: object 178 | additionalProperties: 179 | $ref: '#/$defs/header-or-reference' 180 | securitySchemes: 181 | type: object 182 | additionalProperties: 183 | $ref: '#/$defs/security-scheme-or-reference' 184 | links: 185 | type: object 186 | additionalProperties: 187 | $ref: '#/$defs/link-or-reference' 188 | callbacks: 189 | type: object 190 | additionalProperties: 191 | $ref: '#/$defs/callbacks-or-reference' 192 | pathItems: 193 | type: object 194 | additionalProperties: 195 | $ref: '#/$defs/path-item-or-reference' 196 | patternProperties: 197 | '^(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)$': 198 | $comment: Enumerating all of the property names in the regex above is necessary for unevaluatedProperties to work as expected 199 | propertyNames: 200 | pattern: '^[a-zA-Z0-9._-]+$' 201 | $ref: '#/$defs/specification-extensions' 202 | unevaluatedProperties: false 203 | 204 | paths: 205 | $comment: https://spec.openapis.org/oas/v3.1.0#paths-object 206 | type: object 207 | patternProperties: 208 | '^/': 209 | $ref: '#/$defs/path-item' 210 | $ref: '#/$defs/specification-extensions' 211 | unevaluatedProperties: false 212 | 213 | path-item: 214 | $comment: https://spec.openapis.org/oas/v3.1.0#path-item-object 215 | type: object 216 | properties: 217 | summary: 218 | type: string 219 | description: 220 | type: string 221 | servers: 222 | type: array 223 | items: 224 | $ref: '#/$defs/server' 225 | parameters: 226 | type: array 227 | items: 228 | $ref: '#/$defs/parameter-or-reference' 229 | get: 230 | $ref: '#/$defs/operation' 231 | put: 232 | $ref: '#/$defs/operation' 233 | post: 234 | $ref: '#/$defs/operation' 235 | delete: 236 | $ref: '#/$defs/operation' 237 | options: 238 | $ref: '#/$defs/operation' 239 | head: 240 | $ref: '#/$defs/operation' 241 | patch: 242 | $ref: '#/$defs/operation' 243 | trace: 244 | $ref: '#/$defs/operation' 245 | $ref: '#/$defs/specification-extensions' 246 | unevaluatedProperties: false 247 | 248 | path-item-or-reference: 249 | if: 250 | type: object 251 | required: 252 | - $ref 253 | then: 254 | $ref: '#/$defs/reference' 255 | else: 256 | $ref: '#/$defs/path-item' 257 | 258 | operation: 259 | $comment: https://spec.openapis.org/oas/v3.1.0#operation-object 260 | type: object 261 | properties: 262 | tags: 263 | type: array 264 | items: 265 | type: string 266 | summary: 267 | type: string 268 | description: 269 | type: string 270 | externalDocs: 271 | $ref: '#/$defs/external-documentation' 272 | operationId: 273 | type: string 274 | parameters: 275 | type: array 276 | items: 277 | $ref: '#/$defs/parameter-or-reference' 278 | requestBody: 279 | $ref: '#/$defs/request-body-or-reference' 280 | responses: 281 | $ref: '#/$defs/responses' 282 | callbacks: 283 | type: object 284 | additionalProperties: 285 | $ref: '#/$defs/callbacks-or-reference' 286 | deprecated: 287 | default: false 288 | type: boolean 289 | security: 290 | type: array 291 | items: 292 | $ref: '#/$defs/security-requirement' 293 | servers: 294 | type: array 295 | items: 296 | $ref: '#/$defs/server' 297 | $ref: '#/$defs/specification-extensions' 298 | unevaluatedProperties: false 299 | 300 | external-documentation: 301 | $comment: https://spec.openapis.org/oas/v3.1.0#external-documentation-object 302 | type: object 303 | properties: 304 | description: 305 | type: string 306 | url: 307 | type: string 308 | format: uri 309 | required: 310 | - url 311 | $ref: '#/$defs/specification-extensions' 312 | unevaluatedProperties: false 313 | 314 | parameter: 315 | $comment: https://spec.openapis.org/oas/v3.1.0#parameter-object 316 | type: object 317 | properties: 318 | name: 319 | type: string 320 | in: 321 | enum: 322 | - query 323 | - header 324 | - path 325 | - cookie 326 | description: 327 | type: string 328 | required: 329 | default: false 330 | type: boolean 331 | deprecated: 332 | default: false 333 | type: boolean 334 | schema: 335 | $dynamicRef: '#meta' 336 | content: 337 | $ref: '#/$defs/content' 338 | minProperties: 1 339 | maxProperties: 1 340 | required: 341 | - name 342 | - in 343 | oneOf: 344 | - required: 345 | - schema 346 | - required: 347 | - content 348 | if: 349 | properties: 350 | in: 351 | const: query 352 | required: 353 | - in 354 | then: 355 | properties: 356 | allowEmptyValue: 357 | default: false 358 | type: boolean 359 | dependentSchemas: 360 | schema: 361 | properties: 362 | style: 363 | type: string 364 | explode: 365 | type: boolean 366 | allOf: 367 | - $ref: '#/$defs/examples' 368 | - $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-path' 369 | - $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-header' 370 | - $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-query' 371 | - $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-cookie' 372 | - $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-form' 373 | 374 | $defs: 375 | styles-for-path: 376 | if: 377 | properties: 378 | in: 379 | const: path 380 | required: 381 | - in 382 | then: 383 | properties: 384 | name: 385 | pattern: '[^/#?]+$' 386 | style: 387 | default: simple 388 | enum: 389 | - matrix 390 | - label 391 | - simple 392 | required: 393 | const: true 394 | required: 395 | - required 396 | 397 | styles-for-header: 398 | if: 399 | properties: 400 | in: 401 | const: header 402 | required: 403 | - in 404 | then: 405 | properties: 406 | style: 407 | default: simple 408 | const: simple 409 | 410 | styles-for-query: 411 | if: 412 | properties: 413 | in: 414 | const: query 415 | required: 416 | - in 417 | then: 418 | properties: 419 | style: 420 | default: form 421 | enum: 422 | - form 423 | - spaceDelimited 424 | - pipeDelimited 425 | - deepObject 426 | allowReserved: 427 | default: false 428 | type: boolean 429 | styles-for-cookie: 430 | if: 431 | properties: 432 | in: 433 | const: cookie 434 | required: 435 | - in 436 | then: 437 | properties: 438 | style: 439 | default: form 440 | const: form 441 | 442 | styles-for-form: 443 | if: 444 | properties: 445 | style: 446 | const: form 447 | required: 448 | - style 449 | then: 450 | properties: 451 | explode: 452 | default: true 453 | else: 454 | properties: 455 | explode: 456 | default: false 457 | 458 | $ref: '#/$defs/specification-extensions' 459 | unevaluatedProperties: false 460 | 461 | parameter-or-reference: 462 | if: 463 | type: object 464 | required: 465 | - $ref 466 | then: 467 | $ref: '#/$defs/reference' 468 | else: 469 | $ref: '#/$defs/parameter' 470 | 471 | request-body: 472 | $comment: https://spec.openapis.org/oas/v3.1.0#request-body-object 473 | type: object 474 | properties: 475 | description: 476 | type: string 477 | content: 478 | $ref: '#/$defs/content' 479 | required: 480 | default: false 481 | type: boolean 482 | required: 483 | - content 484 | $ref: '#/$defs/specification-extensions' 485 | unevaluatedProperties: false 486 | 487 | request-body-or-reference: 488 | if: 489 | type: object 490 | required: 491 | - $ref 492 | then: 493 | $ref: '#/$defs/reference' 494 | else: 495 | $ref: '#/$defs/request-body' 496 | 497 | content: 498 | $comment: https://spec.openapis.org/oas/v3.1.0#fixed-fields-10 499 | type: object 500 | additionalProperties: 501 | $ref: '#/$defs/media-type' 502 | propertyNames: 503 | format: media-range 504 | 505 | media-type: 506 | $comment: https://spec.openapis.org/oas/v3.1.0#media-type-object 507 | type: object 508 | properties: 509 | schema: 510 | $dynamicRef: '#meta' 511 | encoding: 512 | type: object 513 | additionalProperties: 514 | $ref: '#/$defs/encoding' 515 | allOf: 516 | - $ref: '#/$defs/specification-extensions' 517 | - $ref: '#/$defs/examples' 518 | unevaluatedProperties: false 519 | 520 | encoding: 521 | $comment: https://spec.openapis.org/oas/v3.1.0#encoding-object 522 | type: object 523 | properties: 524 | contentType: 525 | type: string 526 | format: media-range 527 | headers: 528 | type: object 529 | additionalProperties: 530 | $ref: '#/$defs/header-or-reference' 531 | style: 532 | default: form 533 | enum: 534 | - form 535 | - spaceDelimited 536 | - pipeDelimited 537 | - deepObject 538 | explode: 539 | type: boolean 540 | allowReserved: 541 | default: false 542 | type: boolean 543 | allOf: 544 | - $ref: '#/$defs/specification-extensions' 545 | - $ref: '#/$defs/encoding/$defs/explode-default' 546 | unevaluatedProperties: false 547 | 548 | $defs: 549 | explode-default: 550 | if: 551 | properties: 552 | style: 553 | const: form 554 | required: 555 | - style 556 | then: 557 | properties: 558 | explode: 559 | default: true 560 | else: 561 | properties: 562 | explode: 563 | default: false 564 | 565 | responses: 566 | $comment: https://spec.openapis.org/oas/v3.1.0#responses-object 567 | type: object 568 | properties: 569 | default: 570 | $ref: '#/$defs/response-or-reference' 571 | patternProperties: 572 | '^[1-5](?:[0-9]{2}|XX)$': 573 | $ref: '#/$defs/response-or-reference' 574 | minProperties: 1 575 | $ref: '#/$defs/specification-extensions' 576 | unevaluatedProperties: false 577 | 578 | response: 579 | $comment: https://spec.openapis.org/oas/v3.1.0#response-object 580 | type: object 581 | properties: 582 | description: 583 | type: string 584 | headers: 585 | type: object 586 | additionalProperties: 587 | $ref: '#/$defs/header-or-reference' 588 | content: 589 | $ref: '#/$defs/content' 590 | links: 591 | type: object 592 | additionalProperties: 593 | $ref: '#/$defs/link-or-reference' 594 | required: 595 | - description 596 | $ref: '#/$defs/specification-extensions' 597 | unevaluatedProperties: false 598 | 599 | response-or-reference: 600 | if: 601 | type: object 602 | required: 603 | - $ref 604 | then: 605 | $ref: '#/$defs/reference' 606 | else: 607 | $ref: '#/$defs/response' 608 | 609 | callbacks: 610 | $comment: https://spec.openapis.org/oas/v3.1.0#callback-object 611 | type: object 612 | $ref: '#/$defs/specification-extensions' 613 | additionalProperties: 614 | $ref: '#/$defs/path-item-or-reference' 615 | 616 | callbacks-or-reference: 617 | if: 618 | type: object 619 | required: 620 | - $ref 621 | then: 622 | $ref: '#/$defs/reference' 623 | else: 624 | $ref: '#/$defs/callbacks' 625 | 626 | example: 627 | $comment: https://spec.openapis.org/oas/v3.1.0#example-object 628 | type: object 629 | properties: 630 | summary: 631 | type: string 632 | description: 633 | type: string 634 | value: true 635 | externalValue: 636 | type: string 637 | format: uri 638 | not: 639 | required: 640 | - value 641 | - externalValue 642 | $ref: '#/$defs/specification-extensions' 643 | unevaluatedProperties: false 644 | 645 | example-or-reference: 646 | if: 647 | type: object 648 | required: 649 | - $ref 650 | then: 651 | $ref: '#/$defs/reference' 652 | else: 653 | $ref: '#/$defs/example' 654 | 655 | link: 656 | $comment: https://spec.openapis.org/oas/v3.1.0#link-object 657 | type: object 658 | properties: 659 | operationRef: 660 | type: string 661 | format: uri-reference 662 | operationId: 663 | type: string 664 | parameters: 665 | $ref: '#/$defs/map-of-strings' 666 | requestBody: true 667 | description: 668 | type: string 669 | body: 670 | $ref: '#/$defs/server' 671 | oneOf: 672 | - required: 673 | - operationRef 674 | - required: 675 | - operationId 676 | $ref: '#/$defs/specification-extensions' 677 | unevaluatedProperties: false 678 | 679 | link-or-reference: 680 | if: 681 | type: object 682 | required: 683 | - $ref 684 | then: 685 | $ref: '#/$defs/reference' 686 | else: 687 | $ref: '#/$defs/link' 688 | 689 | header: 690 | $comment: https://spec.openapis.org/oas/v3.1.0#header-object 691 | type: object 692 | properties: 693 | description: 694 | type: string 695 | required: 696 | default: false 697 | type: boolean 698 | deprecated: 699 | default: false 700 | type: boolean 701 | schema: 702 | $dynamicRef: '#meta' 703 | content: 704 | $ref: '#/$defs/content' 705 | minProperties: 1 706 | maxProperties: 1 707 | oneOf: 708 | - required: 709 | - schema 710 | - required: 711 | - content 712 | dependentSchemas: 713 | schema: 714 | properties: 715 | style: 716 | default: simple 717 | const: simple 718 | explode: 719 | default: false 720 | type: boolean 721 | $ref: '#/$defs/examples' 722 | $ref: '#/$defs/specification-extensions' 723 | unevaluatedProperties: false 724 | 725 | header-or-reference: 726 | if: 727 | type: object 728 | required: 729 | - $ref 730 | then: 731 | $ref: '#/$defs/reference' 732 | else: 733 | $ref: '#/$defs/header' 734 | 735 | tag: 736 | $comment: https://spec.openapis.org/oas/v3.1.0#tag-object 737 | type: object 738 | properties: 739 | name: 740 | type: string 741 | description: 742 | type: string 743 | externalDocs: 744 | $ref: '#/$defs/external-documentation' 745 | required: 746 | - name 747 | $ref: '#/$defs/specification-extensions' 748 | unevaluatedProperties: false 749 | 750 | reference: 751 | $comment: https://spec.openapis.org/oas/v3.1.0#reference-object 752 | type: object 753 | properties: 754 | $ref: 755 | type: string 756 | format: uri-reference 757 | summary: 758 | type: string 759 | description: 760 | type: string 761 | unevaluatedProperties: false 762 | 763 | schema: 764 | $comment: https://spec.openapis.org/oas/v3.1.0#schema-object 765 | $dynamicAnchor: meta 766 | type: 767 | - object 768 | - boolean 769 | 770 | security-scheme: 771 | $comment: https://spec.openapis.org/oas/v3.1.0#security-scheme-object 772 | type: object 773 | properties: 774 | type: 775 | enum: 776 | - apiKey 777 | - http 778 | - mutualTLS 779 | - oauth2 780 | - openIdConnect 781 | description: 782 | type: string 783 | required: 784 | - type 785 | allOf: 786 | - $ref: '#/$defs/specification-extensions' 787 | - $ref: '#/$defs/security-scheme/$defs/type-apikey' 788 | - $ref: '#/$defs/security-scheme/$defs/type-http' 789 | - $ref: '#/$defs/security-scheme/$defs/type-http-bearer' 790 | - $ref: '#/$defs/security-scheme/$defs/type-oauth2' 791 | - $ref: '#/$defs/security-scheme/$defs/type-oidc' 792 | unevaluatedProperties: false 793 | 794 | $defs: 795 | type-apikey: 796 | if: 797 | properties: 798 | type: 799 | const: apiKey 800 | required: 801 | - type 802 | then: 803 | properties: 804 | name: 805 | type: string 806 | in: 807 | enum: 808 | - query 809 | - header 810 | - cookie 811 | required: 812 | - name 813 | - in 814 | 815 | type-http: 816 | if: 817 | properties: 818 | type: 819 | const: http 820 | required: 821 | - type 822 | then: 823 | properties: 824 | scheme: 825 | type: string 826 | required: 827 | - scheme 828 | 829 | type-http-bearer: 830 | if: 831 | properties: 832 | type: 833 | const: http 834 | scheme: 835 | type: string 836 | pattern: ^[Bb][Ee][Aa][Rr][Ee][Rr]$ 837 | required: 838 | - type 839 | - scheme 840 | then: 841 | properties: 842 | bearerFormat: 843 | type: string 844 | 845 | type-oauth2: 846 | if: 847 | properties: 848 | type: 849 | const: oauth2 850 | required: 851 | - type 852 | then: 853 | properties: 854 | flows: 855 | $ref: '#/$defs/oauth-flows' 856 | required: 857 | - flows 858 | 859 | type-oidc: 860 | if: 861 | properties: 862 | type: 863 | const: openIdConnect 864 | required: 865 | - type 866 | then: 867 | properties: 868 | openIdConnectUrl: 869 | type: string 870 | format: uri 871 | required: 872 | - openIdConnectUrl 873 | 874 | security-scheme-or-reference: 875 | if: 876 | type: object 877 | required: 878 | - $ref 879 | then: 880 | $ref: '#/$defs/reference' 881 | else: 882 | $ref: '#/$defs/security-scheme' 883 | 884 | oauth-flows: 885 | type: object 886 | properties: 887 | implicit: 888 | $ref: '#/$defs/oauth-flows/$defs/implicit' 889 | password: 890 | $ref: '#/$defs/oauth-flows/$defs/password' 891 | clientCredentials: 892 | $ref: '#/$defs/oauth-flows/$defs/client-credentials' 893 | authorizationCode: 894 | $ref: '#/$defs/oauth-flows/$defs/authorization-code' 895 | $ref: '#/$defs/specification-extensions' 896 | unevaluatedProperties: false 897 | 898 | $defs: 899 | implicit: 900 | type: object 901 | properties: 902 | authorizationUrl: 903 | type: string 904 | format: uri 905 | refreshUrl: 906 | type: string 907 | format: uri 908 | scopes: 909 | $ref: '#/$defs/map-of-strings' 910 | required: 911 | - authorizationUrl 912 | - scopes 913 | $ref: '#/$defs/specification-extensions' 914 | unevaluatedProperties: false 915 | 916 | password: 917 | type: object 918 | properties: 919 | tokenUrl: 920 | type: string 921 | format: uri 922 | refreshUrl: 923 | type: string 924 | format: uri 925 | scopes: 926 | $ref: '#/$defs/map-of-strings' 927 | required: 928 | - tokenUrl 929 | - scopes 930 | $ref: '#/$defs/specification-extensions' 931 | unevaluatedProperties: false 932 | 933 | client-credentials: 934 | type: object 935 | properties: 936 | tokenUrl: 937 | type: string 938 | format: uri 939 | refreshUrl: 940 | type: string 941 | format: uri 942 | scopes: 943 | $ref: '#/$defs/map-of-strings' 944 | required: 945 | - tokenUrl 946 | - scopes 947 | $ref: '#/$defs/specification-extensions' 948 | unevaluatedProperties: false 949 | 950 | authorization-code: 951 | type: object 952 | properties: 953 | authorizationUrl: 954 | type: string 955 | format: uri 956 | tokenUrl: 957 | type: string 958 | format: uri 959 | refreshUrl: 960 | type: string 961 | format: uri 962 | scopes: 963 | $ref: '#/$defs/map-of-strings' 964 | required: 965 | - authorizationUrl 966 | - tokenUrl 967 | - scopes 968 | $ref: '#/$defs/specification-extensions' 969 | unevaluatedProperties: false 970 | 971 | security-requirement: 972 | $comment: https://spec.openapis.org/oas/v3.1.0#security-requirement-object 973 | type: object 974 | additionalProperties: 975 | type: array 976 | items: 977 | type: string 978 | 979 | specification-extensions: 980 | $comment: https://spec.openapis.org/oas/v3.1.0#specification-extensions 981 | patternProperties: 982 | '^x-': true 983 | 984 | examples: 985 | properties: 986 | example: true 987 | examples: 988 | type: object 989 | additionalProperties: 990 | $ref: '#/$defs/example-or-reference' 991 | 992 | map-of-strings: 993 | type: object 994 | additionalProperties: 995 | type: string 996 | -------------------------------------------------------------------------------- /src/main/resources/upgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swagger-api/validator-badge/27ff4ec9962a2a7cc7bd7723914264ad0204f1d3/src/main/resources/upgrade.png -------------------------------------------------------------------------------- /src/main/resources/valid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swagger-api/validator-badge/27ff4ec9962a2a7cc7bd7723914264ad0204f1d3/src/main/resources/valid.png -------------------------------------------------------------------------------- /src/main/swagger/swagger.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | openapi: 3.0.0 3 | info: 4 | title: Swagger Validator Badge 5 | description: Parses and validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition 6 | version: 2.1.8-SNAPSHOT 7 | servers: 8 | - url: "/" 9 | paths: 10 | "/": 11 | get: 12 | tags: 13 | - Validator 14 | summary: Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition returning a valid/invalid badge 15 | description: | 16 | Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition provided via `url` parameter 17 | returning a valid/invalid badge 18 | operationId: validateByUrl 19 | parameters: 20 | - $ref: '#/components/parameters/url' 21 | - $ref: '#/components/parameters/resolve' 22 | - $ref: '#/components/parameters/resolveFully' 23 | - $ref: '#/components/parameters/validateInternalRefs' 24 | - $ref: '#/components/parameters/validateExternalRefs' 25 | - $ref: '#/components/parameters/resolveRequestBody' 26 | - $ref: '#/components/parameters/resolveCombinators' 27 | - $ref: '#/components/parameters/allowEmptyStrings' 28 | - $ref: '#/components/parameters/legacyYamlDeserialization' 29 | - $ref: '#/components/parameters/inferSchemaType' 30 | - $ref: '#/components/parameters/jsonSchemaValidation' 31 | - $ref: '#/components/parameters/legacyJsonSchemaValidation' 32 | responses: 33 | '200': 34 | $ref: '#/components/responses/validationBadge' 35 | post: 36 | tags: 37 | - Validator 38 | summary: Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition returning a valid/invalid badge 39 | description: | 40 | Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition provided in request body 41 | returning a valid/invalid badge 42 | operationId: validateByContent 43 | parameters: 44 | - $ref: '#/components/parameters/resolve' 45 | - $ref: '#/components/parameters/resolveFully' 46 | - $ref: '#/components/parameters/validateInternalRefs' 47 | - $ref: '#/components/parameters/validateExternalRefs' 48 | - $ref: '#/components/parameters/resolveRequestBody' 49 | - $ref: '#/components/parameters/resolveCombinators' 50 | - $ref: '#/components/parameters/allowEmptyStrings' 51 | - $ref: '#/components/parameters/legacyYamlDeserialization' 52 | - $ref: '#/components/parameters/inferSchemaType' 53 | - $ref: '#/components/parameters/jsonSchemaValidation' 54 | - $ref: '#/components/parameters/legacyJsonSchemaValidation' 55 | requestBody: 56 | $ref: '#/components/requestBodies/specification' 57 | responses: 58 | '200': 59 | $ref: '#/components/responses/validationBadge' 60 | "/debug": 61 | get: 62 | tags: 63 | - Validator 64 | summary: Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition returning a validation response 65 | description: | 66 | Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition provided via `url` parameter 67 | returning a validation response containing any found validation errors 68 | operationId: reviewByUrl 69 | parameters: 70 | - $ref: '#/components/parameters/url' 71 | - $ref: '#/components/parameters/resolve' 72 | - $ref: '#/components/parameters/resolveFully' 73 | - $ref: '#/components/parameters/validateInternalRefs' 74 | - $ref: '#/components/parameters/validateExternalRefs' 75 | - $ref: '#/components/parameters/resolveRequestBody' 76 | - $ref: '#/components/parameters/resolveCombinators' 77 | - $ref: '#/components/parameters/allowEmptyStrings' 78 | - $ref: '#/components/parameters/legacyYamlDeserialization' 79 | - $ref: '#/components/parameters/inferSchemaType' 80 | - $ref: '#/components/parameters/jsonSchemaValidation' 81 | - $ref: '#/components/parameters/legacyJsonSchemaValidation' 82 | responses: 83 | '200': 84 | $ref: '#/components/responses/validationResponse' 85 | post: 86 | tags: 87 | - Validator 88 | summary: Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition returning a validation response 89 | description: | 90 | Validates a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition provided via request body 91 | returning a validation response containing any found validation errors 92 | operationId: reviewByContent 93 | parameters: 94 | - $ref: '#/components/parameters/resolve' 95 | - $ref: '#/components/parameters/resolveFully' 96 | - $ref: '#/components/parameters/validateInternalRefs' 97 | - $ref: '#/components/parameters/validateExternalRefs' 98 | - $ref: '#/components/parameters/resolveRequestBody' 99 | - $ref: '#/components/parameters/resolveCombinators' 100 | - $ref: '#/components/parameters/allowEmptyStrings' 101 | - $ref: '#/components/parameters/legacyYamlDeserialization' 102 | - $ref: '#/components/parameters/inferSchemaType' 103 | - $ref: '#/components/parameters/jsonSchemaValidation' 104 | - $ref: '#/components/parameters/legacyJsonSchemaValidation' 105 | requestBody: 106 | $ref: '#/components/requestBodies/specification' 107 | responses: 108 | '200': 109 | $ref: '#/components/responses/validationResponse' 110 | "/parse": 111 | get: 112 | tags: 113 | - Validator 114 | summary: Resolves / Dereferences a Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition returning the resolved file 115 | operationId: parseByUrl 116 | parameters: 117 | - $ref: '#/components/parameters/url' 118 | - $ref: '#/components/parameters/resolve' 119 | - $ref: '#/components/parameters/resolveFully' 120 | - $ref: '#/components/parameters/flatten' 121 | - $ref: '#/components/parameters/validateInternalRefs' 122 | - $ref: '#/components/parameters/validateExternalRefs' 123 | - $ref: '#/components/parameters/resolveRequestBody' 124 | - $ref: '#/components/parameters/resolveCombinators' 125 | - $ref: '#/components/parameters/allowEmptyStrings' 126 | - $ref: '#/components/parameters/legacyYamlDeserialization' 127 | - $ref: '#/components/parameters/inferSchemaType' 128 | - $ref: '#/components/parameters/jsonSchemaValidation' 129 | - $ref: '#/components/parameters/legacyJsonSchemaValidation' 130 | - $ref: '#/components/parameters/returnFullParseResult' 131 | 132 | responses: 133 | '200': 134 | $ref: '#/components/responses/parseResponse' 135 | post: 136 | tags: 137 | - Validator 138 | summary: Resolves / Dereferences Swagger/OpenAPI 2.0 or an OpenAPI 3.x definition returning the resolved file 139 | operationId: parseByContent 140 | parameters: 141 | - $ref: '#/components/parameters/resolve' 142 | - $ref: '#/components/parameters/resolveFully' 143 | - $ref: '#/components/parameters/flatten' 144 | - $ref: '#/components/parameters/validateInternalRefs' 145 | - $ref: '#/components/parameters/validateExternalRefs' 146 | - $ref: '#/components/parameters/resolveRequestBody' 147 | - $ref: '#/components/parameters/resolveCombinators' 148 | - $ref: '#/components/parameters/allowEmptyStrings' 149 | - $ref: '#/components/parameters/legacyYamlDeserialization' 150 | - $ref: '#/components/parameters/inferSchemaType' 151 | - $ref: '#/components/parameters/jsonSchemaValidation' 152 | - $ref: '#/components/parameters/legacyJsonSchemaValidation' 153 | - $ref: '#/components/parameters/returnFullParseResult' 154 | requestBody: 155 | $ref: '#/components/requestBodies/specification' 156 | responses: 157 | '200': 158 | $ref: '#/components/responses/parseResponse' 159 | components: 160 | requestBodies: 161 | specification: 162 | description: the specification to validate 163 | content: 164 | "application/yaml": 165 | schema: 166 | type: object 167 | "application/json": 168 | schema: 169 | type: object 170 | required: true 171 | responses: 172 | validationResponse: 173 | description: result of validation as a validation response 174 | content: 175 | "application/yaml": 176 | schema: 177 | $ref: '#/components/schemas/ValidationResponse' 178 | "application/json": 179 | schema: 180 | $ref: '#/components/schemas/ValidationResponse' 181 | validationBadge: 182 | description: result of validation as valid/invalid badge 183 | content: 184 | "image/png": 185 | schema: 186 | type: string 187 | format: binary 188 | parseResponse: 189 | description: the parsed / resolved specification 190 | content: 191 | "application/yaml": 192 | schema: 193 | type: string 194 | "application/json": 195 | schema: 196 | type: string 197 | "text/plain": 198 | schema: 199 | type: string 200 | application/octet-stream: 201 | schema: 202 | type: string 203 | format: binary 204 | parameters: 205 | url: 206 | name: url 207 | in: query 208 | description: A URL to the definition 209 | required: true 210 | schema: 211 | type: string 212 | resolve: 213 | name: resolve 214 | in: query 215 | description: | 216 | resolves the definition 217 | See https://github.com/swagger-api/swagger-parser/blob/master/README.md#options 218 | required: false 219 | schema: 220 | type: boolean 221 | resolveFully: 222 | name: resolveFully 223 | in: query 224 | description: | 225 | fully resolves the definition 226 | See https://github.com/swagger-api/swagger-parser/blob/master/README.md#options' 227 | required: false 228 | schema: 229 | type: boolean 230 | flatten: 231 | name: flatten 232 | in: query 233 | description: | 234 | flatten the definition 235 | See https://github.com/swagger-api/swagger-parser/blob/master/README.md#options 236 | required: false 237 | schema: 238 | type: boolean 239 | validateInternalRefs: 240 | name: validateInternalRefs 241 | in: query 242 | description: validate internal references 243 | required: false 244 | schema: 245 | type: boolean 246 | validateExternalRefs: 247 | name: validateExternalRefs 248 | in: query 249 | description: validate external references while resolving 250 | required: false 251 | schema: 252 | type: boolean 253 | resolveRequestBody: 254 | name: resolveRequestBody 255 | in: query 256 | description: bundle requestBody inline during resolving also with resolveFully set to false 257 | required: false 258 | schema: 259 | type: boolean 260 | resolveCombinators: 261 | name: resolveCombinators 262 | in: query 263 | description: | 264 | customizes behaviour related to `allOf/anyOf/oneOf` with resolveFully set to true. 265 | See https://github.com/swagger-api/swagger-parser/blob/master/README.md#options' 266 | required: false 267 | schema: 268 | type: boolean 269 | allowEmptyStrings: 270 | name: allowEmptyStrings 271 | in: query 272 | description: when set to true parses empty values as empty strings 273 | required: false 274 | schema: 275 | type: boolean 276 | legacyYamlDeserialization: 277 | name: legacyYamlDeserialization 278 | in: query 279 | description: legacyYamlDeserialization 280 | required: false 281 | schema: 282 | type: boolean 283 | inferSchemaType: 284 | name: inferSchemaType 285 | in: query 286 | description: infer schema type for item, default and schemas with additionalProperties 287 | required: false 288 | schema: 289 | type: boolean 290 | jsonSchemaValidation: 291 | name: jsonSchemaValidation 292 | in: query 293 | description: performs JSON Schema validation 294 | required: false 295 | schema: 296 | type: boolean 297 | legacyJsonSchemaValidation: 298 | name: legacyJsonSchemaValidation 299 | in: query 300 | description: performs JSON Schema validation using legacy engine (fge) 301 | required: false 302 | schema: 303 | type: boolean 304 | returnFullParseResult: 305 | name: returnFullParseResult 306 | in: query 307 | description: if set to true returns the full parse result including validation messages 308 | required: false 309 | schema: 310 | type: boolean 311 | schemas: 312 | Instance: 313 | type: object 314 | properties: 315 | pointer: 316 | type: string 317 | Schema: 318 | type: object 319 | properties: 320 | loadingURI: 321 | type: string 322 | pointer: 323 | type: string 324 | SchemaValidationError: 325 | type: object 326 | properties: 327 | level: 328 | type: string 329 | domain: 330 | type: string 331 | keyword: 332 | type: string 333 | message: 334 | type: string 335 | schema: 336 | $ref: '#/components/schemas/Schema' 337 | instance: 338 | $ref: '#/components/schemas/Instance' 339 | required: 340 | type: array 341 | items: 342 | type: string 343 | missing: 344 | type: array 345 | items: 346 | type: string 347 | ValidationResponse: 348 | type: object 349 | properties: 350 | messages: 351 | type: array 352 | items: 353 | type: string 354 | schemaValidationMessages: 355 | type: array 356 | items: 357 | $ref: '#/components/schemas/SchemaValidationError' 358 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | swagger-inflector 5 | org.glassfish.jersey.servlet.ServletContainer 6 | 7 | javax.ws.rs.Application 8 | io.swagger.oas.inflector.OpenAPIInflector 9 | 10 | 11 | jersey.config.server.provider.packages 12 | 13 | com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider 14 | 15 | 16 | 1 17 | 18 | 19 | swagger-inflector 20 | /validator/* 21 | 22 | 23 | CORSFilter 24 | io.swagger.oas.inflector.utils.CORSFilter 25 | 26 | 27 | CORSFilter 28 | /* 29 | 30 | -------------------------------------------------------------------------------- /src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Swagger UI 7 | 8 | 9 | 10 | 11 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 | 70 | 71 | 72 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/test/resources/invalid_oas3.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | servers: [] 3 | 4 | paths: 5 | /users: 6 | get: 7 | responses: 8 | '200': 9 | description: hello world 10 | components: 11 | schemas: 12 | NewsArticle: 13 | title: NewsArticle 14 | type: object 15 | nullable: true 16 | properties: 17 | id: 18 | type: integer 19 | format: int32 20 | x-mysql-type: int(11) 21 | allOfNewsArticle: 22 | title: allOfNewsArticle 23 | type: object 24 | allOf: 25 | - $ref: '#/components/schemas/NewsArticle' 26 | - properties: 27 | articleBody: 28 | type: string 29 | anyOfNewsArticle: 30 | title: anyOfNewsArticle 31 | type: object 32 | anyOf: 33 | - $ref: '#/components/schemas/NewsArticle' 34 | - properties: 35 | articleBody: 36 | type: string 37 | oneOfNewsArticle: 38 | title: oneOfNewsArticle 39 | type: object 40 | oneOf: 41 | - $ref: '#/components/schemas/NewsArticle' 42 | - properties: 43 | articleBody: 44 | type: string 45 | notNewsArticle: 46 | title: notNewsArticle 47 | type: object 48 | allOf: 49 | - $ref: '#/components/schemas/NewsArticle' 50 | - not: 51 | type: string 52 | responses: {} 53 | parameters: {} 54 | examples: {} 55 | requestBodies: {} 56 | securitySchemes: {} 57 | headers: {} -------------------------------------------------------------------------------- /src/test/resources/invalid_oas31.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | servers: [] 3 | 4 | paths: 5 | /users: 6 | get: 7 | responses: 8 | '200': 9 | description: hello world 10 | components: 11 | schemas: 12 | NewsArticle: 13 | title: NewsArticle 14 | type: 15 | - object 16 | - string 17 | properties: 18 | id: 19 | type: integer 20 | format: int32 21 | x-mysql-type: int(11) 22 | allOfNewsArticle: 23 | title: allOfNewsArticle 24 | type: object 25 | allOf: 26 | - $ref: '#/components/schemas/NewsArticle' 27 | - properties: 28 | articleBody: 29 | type: string 30 | anyOfNewsArticle: 31 | title: anyOfNewsArticle 32 | type: object 33 | anyOf: 34 | - $ref: '#/components/schemas/NewsArticle' 35 | - properties: 36 | articleBody: 37 | type: string 38 | oneOfNewsArticle: 39 | title: oneOfNewsArticle 40 | type: object 41 | oneOf: 42 | - $ref: '#/components/schemas/NewsArticle' 43 | - properties: 44 | articleBody: 45 | type: string 46 | notNewsArticle: 47 | title: notNewsArticle 48 | type: object 49 | allOf: 50 | - $ref: '#/components/schemas/NewsArticle' 51 | - not: 52 | type: string 53 | responses: {} 54 | parameters: {} 55 | examples: {} 56 | requestBodies: {} 57 | securitySchemes: {} 58 | headers: {} 59 | -------------------------------------------------------------------------------- /src/test/resources/invalid_oas31_simple.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | paths: 3 | /users: 4 | get: 5 | responses: 6 | '200': 7 | description: hello world 8 | components: 9 | schemas: 10 | foo: 11 | type: object 12 | -------------------------------------------------------------------------------- /src/test/resources/invalid_swagger2.yaml: -------------------------------------------------------------------------------- 1 | swagger: "2.0" 2 | basePath: /v2 3 | tags: 4 | - name: pet 5 | description: Everything about your Pets 6 | externalDocs: 7 | description: Find out more 8 | url: "http://swagger.io" 9 | - name: store 10 | description: Operations about user 11 | - name: user 12 | description: Access to Petstore orders 13 | externalDocs: 14 | description: Find out more about our store 15 | url: "http://swagger.io" 16 | schemes: 17 | - http 18 | paths: 19 | /pet: 20 | post: 21 | tags: 22 | - pet 23 | summary: Add a new pet to the store 24 | x-swagger-router-controller: SampleController 25 | description: "" 26 | operationId: addPet 27 | consumes: 28 | - application/json 29 | - application/xml 30 | produces: 31 | - application/xml 32 | - application/json 33 | parameters: 34 | - in: body 35 | name: body 36 | description: Pet object that needs to be added to the store 37 | required: false 38 | schema: 39 | $ref: "#/definitions/Pet" 40 | responses: 41 | "405": 42 | description: Invalid input 43 | security: 44 | - petstore_auth: 45 | - "write:pets" 46 | - "read:pets" 47 | put: 48 | tags: 49 | - pet 50 | summary: Update an existing pet 51 | description: "" 52 | operationId: updatePet 53 | consumes: 54 | - application/json 55 | - application/xml 56 | produces: 57 | - application/xml 58 | - application/json 59 | parameters: 60 | - in: body 61 | name: body 62 | description: Pet object that needs to be added to the store 63 | required: false 64 | schema: 65 | $ref: "#/definitions/Pet" 66 | responses: 67 | "400": 68 | description: Invalid ID supplied 69 | "404": 70 | description: Pet not found 71 | "405": 72 | description: Validation exception 73 | security: 74 | - petstore_auth: 75 | - "write:pets" 76 | - "read:pets" 77 | /pet/findByStatus: 78 | get: 79 | tags: 80 | - pet 81 | summary: Finds Pets by status 82 | description: Multiple status values can be provided with comma separated strings 83 | operationId: findPetsByStatus 84 | consumes: 85 | - application/xml 86 | - application/json 87 | - multipart/form-data 88 | - application/x-www-form-urlencoded 89 | produces: 90 | - application/xml 91 | - application/json 92 | parameters: 93 | - name: status 94 | in: query 95 | description: Status values that need to be considered for filter 96 | required: false 97 | type: array 98 | items: 99 | type: string 100 | collectionFormat: multi 101 | default: available 102 | enum: 103 | - available 104 | - pending 105 | - sold 106 | responses: 107 | "200": 108 | description: successful operation 109 | schema: 110 | type: array 111 | items: 112 | $ref: "#/definitions/Pet" 113 | "400": 114 | description: Invalid status value 115 | security: 116 | - petstore_auth: 117 | - "write:pets" 118 | - "read:pets" 119 | /pet/findByTags: 120 | get: 121 | tags: 122 | - pet 123 | summary: Finds Pets by tags 124 | description: "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing." 125 | operationId: findPetsByTags 126 | produces: 127 | - application/xml 128 | - application/json 129 | parameters: 130 | - name: tags 131 | in: query 132 | description: Tags to filter by 133 | required: false 134 | type: array 135 | items: 136 | type: string 137 | collectionFormat: multi 138 | responses: 139 | "200": 140 | description: successful operation 141 | schema: 142 | type: array 143 | items: 144 | $ref: "#/definitions/Pet" 145 | "400": 146 | description: Invalid tag value 147 | security: 148 | - petstore_auth: 149 | - "write:pets" 150 | - "read:pets" 151 | "/pet/{petId}": 152 | get: 153 | tags: 154 | - pet 155 | summary: Find pet by ID 156 | description: Returns a single pet 157 | operationId: getPetById 158 | consumes: 159 | - application/x-www-form-urlencoded 160 | produces: 161 | - application/xml 162 | - application/json 163 | parameters: 164 | - name: petId 165 | in: path 166 | description: ID of pet to return 167 | required: true 168 | type: integer 169 | format: int64 170 | responses: 171 | "200": 172 | description: successful operation 173 | schema: 174 | $ref: "#/definitions/Pet" 175 | "400": 176 | description: Invalid ID supplied 177 | "404": 178 | description: Pet not found 179 | security: 180 | - api_key: [] 181 | - petstore_auth: 182 | - "write:pets" 183 | - "read:pets" 184 | post: 185 | tags: 186 | - pet 187 | summary: Updates a pet in the store with form data 188 | description: "" 189 | operationId: updatePetWithForm 190 | consumes: 191 | - application/x-www-form-urlencoded 192 | produces: 193 | - application/xml 194 | - application/json 195 | parameters: 196 | - name: petId 197 | in: path 198 | description: ID of pet that needs to be updated 199 | required: true 200 | type: string 201 | - name: name 202 | in: formData 203 | description: Updated name of the pet 204 | required: false 205 | type: string 206 | - name: status 207 | in: formData 208 | description: Updated status of the pet 209 | required: false 210 | type: string 211 | responses: 212 | "405": 213 | description: Invalid input 214 | security: 215 | - petstore_auth: 216 | - "write:pets" 217 | - "read:pets" 218 | delete: 219 | tags: 220 | - pet 221 | summary: Deletes a pet 222 | description: "" 223 | operationId: deletePet 224 | consumes: 225 | - multipart/form-data 226 | - application/x-www-form-urlencoded 227 | produces: 228 | - application/xml 229 | - application/json 230 | parameters: 231 | - name: api_key 232 | in: header 233 | description: "" 234 | required: false 235 | type: string 236 | - name: petId 237 | in: path 238 | description: Pet id to delete 239 | required: true 240 | type: integer 241 | format: int64 242 | responses: 243 | "400": 244 | description: Invalid pet value 245 | security: 246 | - petstore_auth: 247 | - "write:pets" 248 | - "read:pets" 249 | "/pet/{petId}/uploadImage": 250 | post: 251 | tags: 252 | - pet 253 | summary: uploads an image 254 | x-swagger-router-controller: SampleController 255 | description: "" 256 | operationId: uploadFile 257 | consumes: 258 | - multipart/form-data 259 | produces: 260 | - application/json 261 | parameters: 262 | - name: petId 263 | in: path 264 | description: ID of pet to update 265 | required: true 266 | type: integer 267 | format: int64 268 | - name: additionalMetadata 269 | in: formData 270 | description: Additional data to pass to server 271 | required: false 272 | type: string 273 | - name: file 274 | in: formData 275 | description: file to upload 276 | required: false 277 | type: file 278 | responses: 279 | "200": 280 | description: successful operation 281 | schema: 282 | $ref: "#/definitions/ApiResponse" 283 | security: 284 | - petstore_auth: 285 | - "write:pets" 286 | - "read:pets" 287 | /store/inventory: 288 | get: 289 | tags: 290 | - store 291 | summary: Returns pet inventories by status 292 | description: Returns a map of status codes to quantities 293 | operationId: getInventory 294 | produces: 295 | - application/json 296 | parameters: [] 297 | responses: 298 | "200": 299 | description: successful operation 300 | schema: 301 | type: object 302 | additionalProperties: 303 | type: integer 304 | format: int32 305 | security: 306 | - api_key: [] 307 | /store/order: 308 | post: 309 | tags: 310 | - store 311 | summary: Place an order for a pet 312 | description: "" 313 | operationId: placeOrder 314 | produces: 315 | - application/xml 316 | - application/json 317 | parameters: 318 | - in: body 319 | name: body 320 | description: order placed for purchasing the pet 321 | required: false 322 | schema: 323 | $ref: "#/definitions/Order" 324 | responses: 325 | "200": 326 | description: successful operation 327 | schema: 328 | $ref: "#/definitions/Order" 329 | "400": 330 | description: Invalid Order 331 | "/store/order/{orderId}": 332 | get: 333 | tags: 334 | - store 335 | summary: Find purchase order by ID 336 | description: "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions" 337 | operationId: getOrderById 338 | produces: 339 | - application/xml 340 | - application/json 341 | parameters: 342 | - name: orderId 343 | in: path 344 | description: ID of pet that needs to be fetched 345 | required: true 346 | type: string 347 | responses: 348 | "200": 349 | description: successful operation 350 | schema: 351 | $ref: "#/definitions/Order" 352 | "400": 353 | description: Invalid ID supplied 354 | "404": 355 | description: Order not found 356 | delete: 357 | tags: 358 | - store 359 | summary: Delete purchase order by ID 360 | description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors 361 | operationId: deleteOrder 362 | produces: 363 | - application/xml 364 | - application/json 365 | parameters: 366 | - name: orderId 367 | in: path 368 | description: ID of the order that needs to be deleted 369 | required: true 370 | type: string 371 | responses: 372 | "400": 373 | description: Invalid ID supplied 374 | "404": 375 | description: Order not found 376 | /user: 377 | post: 378 | tags: 379 | - user 380 | summary: Create user 381 | description: This can only be done by the logged in user. 382 | operationId: createUser 383 | produces: 384 | - application/xml 385 | - application/json 386 | parameters: 387 | - in: body 388 | name: body 389 | description: Created user object 390 | required: false 391 | schema: 392 | $ref: "#/definitions/User" 393 | responses: 394 | default: 395 | description: successful operation 396 | /user/createWithArray: 397 | post: 398 | tags: 399 | - user 400 | summary: Creates list of users with given input array 401 | description: "" 402 | operationId: createUsersWithArrayInput 403 | produces: 404 | - application/xml 405 | - application/json 406 | parameters: 407 | - in: body 408 | name: body 409 | description: List of user object 410 | required: false 411 | schema: 412 | type: array 413 | items: 414 | $ref: "#/definitions/User" 415 | responses: 416 | default: 417 | description: successful operation 418 | /user/createWithList: 419 | post: 420 | tags: 421 | - user 422 | summary: Creates list of users with given input array 423 | description: "" 424 | operationId: createUsersWithListInput 425 | produces: 426 | - application/xml 427 | - application/json 428 | parameters: 429 | - in: body 430 | name: body 431 | description: List of user object 432 | required: false 433 | schema: 434 | type: array 435 | items: 436 | $ref: "#/definitions/User" 437 | responses: 438 | default: 439 | description: successful operation 440 | /user/login: 441 | get: 442 | tags: 443 | - user 444 | summary: Logs user into the system 445 | description: "" 446 | operationId: loginUser 447 | produces: 448 | - application/xml 449 | - application/json 450 | parameters: 451 | - name: username 452 | in: query 453 | description: The user name for login 454 | required: false 455 | type: string 456 | - name: password 457 | in: query 458 | description: The password for login in clear text 459 | required: false 460 | type: string 461 | responses: 462 | "200": 463 | description: successful operation 464 | schema: 465 | type: string 466 | headers: 467 | X-Rate-Limit: 468 | type: integer 469 | format: int32 470 | description: calls per hour allowed by the user 471 | X-Expires-After: 472 | type: string 473 | format: date-time 474 | description: date in UTC when toekn expires 475 | "400": 476 | description: Invalid username/password supplied 477 | /user/logout: 478 | get: 479 | tags: 480 | - user 481 | summary: Logs out current logged in user session 482 | description: "" 483 | operationId: logoutUser 484 | produces: 485 | - application/xml 486 | - application/json 487 | parameters: [] 488 | responses: 489 | default: 490 | description: successful operation 491 | "/user/{username}": 492 | get: 493 | tags: 494 | - user 495 | summary: Get user by user name 496 | description: "" 497 | operationId: getUserByName 498 | produces: 499 | - application/xml 500 | - application/json 501 | parameters: 502 | - name: username 503 | in: path 504 | description: "The name that needs to be fetched. Use user1 for testing. " 505 | required: true 506 | type: string 507 | responses: 508 | "200": 509 | description: successful operation 510 | schema: 511 | $ref: "#/definitions/User" 512 | "400": 513 | description: Invalid username supplied 514 | "404": 515 | description: User not found 516 | put: 517 | tags: 518 | - user 519 | summary: Updated user 520 | description: This can only be done by the logged in user. 521 | operationId: updateUser 522 | produces: 523 | - application/xml 524 | - application/json 525 | parameters: 526 | - name: username 527 | in: path 528 | description: name that need to be deleted 529 | required: true 530 | type: string 531 | - in: body 532 | name: body 533 | description: Updated user object 534 | required: false 535 | schema: 536 | $ref: "#/definitions/User" 537 | responses: 538 | "400": 539 | description: Invalid user supplied 540 | "404": 541 | description: User not found 542 | delete: 543 | tags: 544 | - user 545 | summary: Delete user 546 | description: This can only be done by the logged in user. 547 | operationId: deleteUser 548 | produces: 549 | - application/xml 550 | - application/json 551 | parameters: 552 | - name: username 553 | in: path 554 | description: The name that needs to be deleted 555 | required: true 556 | type: string 557 | responses: 558 | "400": 559 | description: Invalid username supplied 560 | "404": 561 | description: User not found 562 | securityDefinitions: 563 | petstore_auth: 564 | type: oauth2 565 | authorizationUrl: "http://petstore.swagger.io/api/oauth/dialog" 566 | flow: implicit 567 | scopes: 568 | "write:pets": modify pets in your account 569 | "read:pets": read your pets 570 | api_key: 571 | type: apiKey 572 | name: api_key 573 | in: header 574 | definitions: 575 | Order: 576 | properties: 577 | id: 578 | type: integer 579 | format: int64 580 | petId: 581 | type: integer 582 | format: int64 583 | quantity: 584 | type: integer 585 | format: int32 586 | shipDate: 587 | type: string 588 | format: date-time 589 | status: 590 | type: string 591 | description: Order Status 592 | enum: 593 | - placed 594 | - approved 595 | - delivered 596 | complete: 597 | type: boolean 598 | xml: 599 | name: Order 600 | Category: 601 | properties: 602 | id: 603 | type: integer 604 | format: int64 605 | name: 606 | type: string 607 | xml: 608 | name: Category 609 | User: 610 | properties: 611 | id: 612 | type: integer 613 | format: int64 614 | username: 615 | type: string 616 | firstName: 617 | type: string 618 | lastName: 619 | type: string 620 | email: 621 | type: string 622 | password: 623 | type: string 624 | phone: 625 | type: string 626 | userStatus: 627 | type: integer 628 | format: int32 629 | description: User Status 630 | xml: 631 | name: User 632 | Tag: 633 | properties: 634 | id: 635 | type: integer 636 | format: int64 637 | name: 638 | type: string 639 | xml: 640 | name: Tag 641 | Pet: 642 | required: 643 | - name 644 | - photoUrls 645 | properties: 646 | id: 647 | type: integer 648 | format: int64 649 | category: 650 | $ref: "#/definitions/Category" 651 | name: 652 | type: string 653 | example: doggie 654 | photoUrls: 655 | type: array 656 | xml: 657 | name: photoUrl 658 | wrapped: true 659 | items: 660 | type: string 661 | tags: 662 | type: array 663 | xml: 664 | name: tag 665 | wrapped: true 666 | items: 667 | $ref: "#/definitions/Tag" 668 | status: 669 | type: string 670 | description: pet status in the store 671 | enum: 672 | - available 673 | - pending 674 | - sold 675 | xml: 676 | name: Pet 677 | ApiResponse: 678 | properties: 679 | code: 680 | type: integer 681 | format: int32 682 | type: 683 | type: string 684 | message: 685 | type: string 686 | xml: 687 | name: "##default" 688 | externalDocs: 689 | description: Find out more about Swagger 690 | url: "http://swagger.io" -------------------------------------------------------------------------------- /src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/test/resources/oas30local/petstore30.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.0" 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | identifier: test 8 | webhooks: 9 | # Each webhook needs a name 10 | newPet: 11 | # This is a Path Item Object, the only difference is that the request is initiated by the API provider 12 | post: 13 | requestBody: 14 | description: Information about a new pet in the system 15 | content: 16 | application/json: 17 | schema: 18 | $ref: "#/components/schemas/Pet" 19 | responses: 20 | "200": 21 | description: Return a 200 status to indicate that the data was received successfully 22 | newUser: 23 | # This is a Path Item Object, the only difference is that the request is initiated by the API provider 24 | post: 25 | requestBody: 26 | description: Information about a new user in the system 27 | content: 28 | application/json: 29 | schema: 30 | $ref: 'http://localhost:1337/petstore30ext1.yaml#/components/schemas/User' 31 | responses: 32 | "200": 33 | description: Return a 200 status to indicate that the data was received successfully 34 | paths: 35 | /pets: 36 | get: 37 | summary: List all pets 38 | operationId: listPets 39 | tags: 40 | - pets 41 | parameters: 42 | - name: limit 43 | in: query 44 | description: How many items to return at one time (max 100) 45 | required: false 46 | schema: 47 | type: integer 48 | format: int32 49 | responses: 50 | "200": 51 | description: An paged array of pets 52 | headers: 53 | x-next: 54 | description: A link to the next page of responses 55 | schema: 56 | type: string 57 | content: 58 | application/json: 59 | schema: 60 | $ref: "#/components/schemas/Pets" 61 | default: 62 | description: unexpected error 63 | content: 64 | application/json: 65 | schema: 66 | $ref: 'http://localhost:1337/petstore30ext2.yaml#/components/schemas/Error' 67 | post: 68 | summary: Create a pet 69 | operationId: createPets 70 | tags: 71 | - pets 72 | responses: 73 | "201": 74 | description: Null response 75 | default: 76 | description: unexpected error 77 | content: 78 | application/json: 79 | schema: 80 | $ref: 'http://localhost:1337/petstore30ext2.yaml#/components/schemas/Error' 81 | /pets/{petId}: 82 | get: 83 | summary: Info for a specific pet 84 | operationId: showPetById 85 | tags: 86 | - pets 87 | parameters: 88 | - name: petId 89 | in: path 90 | required: true 91 | description: The id of the pet to retrieve 92 | schema: 93 | type: string 94 | responses: 95 | "200": 96 | description: Expected response to a valid request 97 | content: 98 | application/json: 99 | schema: 100 | $ref: "#/components/schemas/Pets" 101 | default: 102 | description: unexpected error 103 | content: 104 | application/json: 105 | schema: 106 | $ref: './petstore30ext2.yaml#/components/schemas/Error' 107 | /users: 108 | post: 109 | tags: 110 | - user 111 | summary: Create user 112 | description: This can only be done by the logged in user. 113 | operationId: createUser 114 | requestBody: 115 | description: Created user object 116 | content: 117 | application/custom: 118 | schema: 119 | $ref: 'http://localhost:1337/petstore30ext1.yaml#/components/schemas/User' 120 | application/json: 121 | schema: 122 | $ref: 'http://localhost:1337/petstore30ext1.yaml#/components/schemas/User' 123 | application/xml: 124 | schema: 125 | $ref: 'http://localhost:1337/petstore30ext1.yaml#/components/schemas/User' 126 | responses: 127 | default: 128 | description: successful operation 129 | content: 130 | application/json: 131 | schema: 132 | $ref: './petstore30ext1.yaml#/components/schemas/User' 133 | application/xml: 134 | schema: 135 | $ref: './petstore30ext1.yaml#/components/schemas/User' 136 | /user/{username}: 137 | $ref: 'http://localhost:1337/petstore30ext1.yaml#/components/pathItems/getUserByName' 138 | components: 139 | schemas: 140 | Pet: 141 | type: object 142 | required: 143 | - id 144 | - name 145 | properties: 146 | id: 147 | type: integer 148 | format: int64 149 | name: 150 | type: string 151 | tag: 152 | type: string 153 | Pets: 154 | type: array 155 | items: 156 | $ref: "#/components/schemas/Pet" 157 | description: desc 158 | format: int32 159 | -------------------------------------------------------------------------------- /src/test/resources/oas30local/petstore30ext1.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | components: 3 | pathItems: 4 | getUserByName: 5 | get: 6 | tags: 7 | - user 8 | summary: Get user by user name 9 | description: "" 10 | operationId: getUserByName 11 | parameters: 12 | - name: username 13 | in: path 14 | description: 'The name that needs to be fetched. Use user1 for testing. ' 15 | required: true 16 | schema: 17 | type: string 18 | responses: 19 | "200": 20 | description: successful operation 21 | wrongField: WRONG 22 | content: 23 | application/xml: 24 | schema: 25 | $ref: '#/components/schemas/User' 26 | application/json: 27 | schema: 28 | $ref: '#/components/schemas/User' 29 | "400": 30 | description: Invalid username supplied 31 | "404": 32 | description: User not found 33 | "500": 34 | description: unexpected error 35 | content: 36 | application/json: 37 | schema: 38 | $ref: 'http://localhost:1337/petstore30ext2.yaml#/components/schemas/Error' 39 | "501": 40 | description: unexpected error 41 | content: 42 | application/json: 43 | schema: 44 | $ref: './petstore30ext2.yaml#/components/schemas/Error' 45 | 46 | schemas: 47 | User: 48 | type: object 49 | properties: 50 | id: 51 | type: integer 52 | format: int64 53 | example: 10 54 | username: 55 | type: string 56 | example: theUser 57 | firstName: 58 | type: string 59 | example: John 60 | lastName: 61 | type: string 62 | example: James 63 | email: 64 | type: string 65 | example: john@email.com 66 | password: 67 | type: string 68 | example: "12345" 69 | phone: 70 | type: string 71 | example: "12345" 72 | userStatus: 73 | type: integer 74 | description: User Status 75 | format: int32 76 | example: 1 77 | -------------------------------------------------------------------------------- /src/test/resources/oas30local/petstore30ext2.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | components: 3 | schemas: 4 | Error: 5 | required: 6 | - code 7 | - message 8 | properties: 9 | code: 10 | type: integer 11 | format: int32 12 | message: 13 | type: string 14 | -------------------------------------------------------------------------------- /src/test/resources/oas31local/petstore31.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.1.0" 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | identifier: test 8 | webhooks: 9 | # Each webhook needs a name 10 | newPet: 11 | # This is a Path Item Object, the only difference is that the request is initiated by the API provider 12 | post: 13 | requestBody: 14 | description: Information about a new pet in the system 15 | content: 16 | application/json: 17 | schema: 18 | $ref: "#/components/schemas/Pet" 19 | responses: 20 | "200": 21 | description: Return a 200 status to indicate that the data was received successfully 22 | newUser: 23 | # This is a Path Item Object, the only difference is that the request is initiated by the API provider 24 | post: 25 | requestBody: 26 | description: Information about a new user in the system 27 | content: 28 | application/json: 29 | schema: 30 | $ref: 'http://localhost:1337/petstore31ext1.yaml#/components/schemas/User' 31 | responses: 32 | "200": 33 | description: Return a 200 status to indicate that the data was received successfully 34 | paths: 35 | /pets: 36 | get: 37 | summary: List all pets 38 | operationId: listPets 39 | tags: 40 | - pets 41 | parameters: 42 | - name: limit 43 | in: query 44 | description: How many items to return at one time (max 100) 45 | required: false 46 | schema: 47 | type: integer 48 | format: int32 49 | responses: 50 | "200": 51 | description: An paged array of pets 52 | headers: 53 | x-next: 54 | description: A link to the next page of responses 55 | schema: 56 | type: string 57 | content: 58 | application/json: 59 | schema: 60 | $ref: "#/components/schemas/Pets" 61 | default: 62 | description: unexpected error 63 | content: 64 | application/json: 65 | schema: 66 | $ref: 'http://localhost:1337/petstore31ext2.yaml#/components/schemas/Error' 67 | post: 68 | summary: Create a pet 69 | operationId: createPets 70 | tags: 71 | - pets 72 | responses: 73 | "201": 74 | description: Null response 75 | default: 76 | description: unexpected error 77 | content: 78 | application/json: 79 | schema: 80 | $ref: 'http://localhost:1337/petstore31ext2.yaml#/components/schemas/Error' 81 | /pets/{petId}: 82 | get: 83 | summary: Info for a specific pet 84 | operationId: showPetById 85 | tags: 86 | - pets 87 | parameters: 88 | - name: petId 89 | in: path 90 | required: true 91 | description: The id of the pet to retrieve 92 | schema: 93 | type: string 94 | responses: 95 | "200": 96 | description: Expected response to a valid request 97 | content: 98 | application/json: 99 | schema: 100 | $ref: "#/components/schemas/Pets" 101 | default: 102 | description: unexpected error 103 | content: 104 | application/json: 105 | schema: 106 | $ref: './petstore31ext2.yaml#/components/schemas/Error' 107 | /users: 108 | post: 109 | tags: 110 | - user 111 | summary: Create user 112 | description: This can only be done by the logged in user. 113 | operationId: createUser 114 | requestBody: 115 | description: Created user object 116 | content: 117 | application/custom: 118 | schema: 119 | $ref: 'http://localhost:1337/petstore31ext1.yaml#/components/schemas/User' 120 | application/json: 121 | schema: 122 | $ref: 'http://localhost:1337/petstore31ext1.yaml#/components/schemas/User' 123 | application/xml: 124 | schema: 125 | $ref: 'http://localhost:1337/petstore31ext1.yaml#/components/schemas/User' 126 | responses: 127 | default: 128 | description: successful operation 129 | content: 130 | application/json: 131 | schema: 132 | $ref: './petstore31ext1.yaml#/components/schemas/User' 133 | application/xml: 134 | schema: 135 | $ref: './petstore31ext1.yaml#/components/schemas/User' 136 | /user/{username}: 137 | $ref: 'http://localhost:1337/petstore31ext1.yaml#/components/pathItems/getUserByName' 138 | components: 139 | schemas: 140 | Pet: 141 | type: 142 | - object 143 | - string 144 | required: 145 | - id 146 | - name 147 | properties: 148 | id: 149 | type: integer 150 | format: int64 151 | name: 152 | type: 153 | - string 154 | - integer 155 | tag: 156 | type: string 157 | Pets: 158 | type: array 159 | items: 160 | $ref: "#/components/schemas/Pet" 161 | description: desc 162 | format: int32 163 | -------------------------------------------------------------------------------- /src/test/resources/oas31local/petstore31ext1.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | components: 3 | pathItems: 4 | getUserByName: 5 | get: 6 | tags: 7 | - user 8 | summary: Get user by user name 9 | description: "" 10 | operationId: getUserByName 11 | parameters: 12 | - name: username 13 | in: path 14 | description: 'The name that needs to be fetched. Use user1 for testing. ' 15 | required: true 16 | schema: 17 | type: string 18 | responses: 19 | "200": 20 | description: successful operation 21 | wrongField: WRONG 22 | content: 23 | application/xml: 24 | schema: 25 | $ref: '#/components/schemas/User' 26 | application/json: 27 | schema: 28 | $ref: '#/components/schemas/User' 29 | "400": 30 | description: Invalid username supplied 31 | "404": 32 | description: User not found 33 | "500": 34 | description: unexpected error 35 | content: 36 | application/json: 37 | schema: 38 | $ref: 'http://localhost:1337/petstore31ext2.yaml#/components/schemas/Error' 39 | "501": 40 | description: unexpected error 41 | content: 42 | application/json: 43 | schema: 44 | $ref: './petstore31ext2.yaml#/components/schemas/Error' 45 | 46 | schemas: 47 | User: 48 | type: object 49 | properties: 50 | id: 51 | type: integer 52 | format: int64 53 | example: 10 54 | username: 55 | type: string 56 | example: theUser 57 | firstName: 58 | type: string 59 | example: John 60 | lastName: 61 | type: string 62 | example: James 63 | email: 64 | type: string 65 | example: john@email.com 66 | password: 67 | type: string 68 | example: "12345" 69 | phone: 70 | type: string 71 | example: "12345" 72 | userStatus: 73 | type: integer 74 | description: User Status 75 | format: int32 76 | example: 1 77 | -------------------------------------------------------------------------------- /src/test/resources/oas31local/petstore31ext2.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | components: 3 | schemas: 4 | Error: 5 | required: 6 | - code 7 | - message 8 | properties: 9 | code: 10 | type: integer 11 | format: int32 12 | message: 13 | type: string 14 | -------------------------------------------------------------------------------- /src/test/resources/valid_oas3.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | servers: [] 3 | info: 4 | version: 1.0.0 5 | title: minimal 6 | description: News Articles ftw 7 | paths: 8 | /users: 9 | get: 10 | responses: 11 | '200': 12 | description: hello world 13 | components: 14 | schemas: 15 | NewsArticle: 16 | title: NewsArticle 17 | type: object 18 | nullable: true 19 | properties: 20 | id: 21 | type: integer 22 | format: int32 23 | x-mysql-type: int(11) 24 | allOfNewsArticle: 25 | title: allOfNewsArticle 26 | type: object 27 | allOf: 28 | - $ref: '#/components/schemas/NewsArticle' 29 | - properties: 30 | articleBody: 31 | type: string 32 | anyOfNewsArticle: 33 | title: anyOfNewsArticle 34 | type: object 35 | anyOf: 36 | - $ref: '#/components/schemas/NewsArticle' 37 | - properties: 38 | articleBody: 39 | type: string 40 | oneOfNewsArticle: 41 | title: oneOfNewsArticle 42 | type: object 43 | oneOf: 44 | - $ref: '#/components/schemas/NewsArticle' 45 | - properties: 46 | articleBody: 47 | type: string 48 | notNewsArticle: 49 | title: notNewsArticle 50 | type: object 51 | allOf: 52 | - $ref: '#/components/schemas/NewsArticle' 53 | - not: 54 | type: string 55 | responses: {} 56 | parameters: {} 57 | examples: {} 58 | requestBodies: {} 59 | securitySchemes: {} 60 | headers: {} -------------------------------------------------------------------------------- /src/test/resources/valid_oas31.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | servers: [] 3 | info: 4 | version: 1.0.0 5 | title: minimal 6 | description: News Articles ftw 7 | paths: 8 | /users: 9 | get: 10 | responses: 11 | '200': 12 | description: hello world 13 | components: 14 | schemas: 15 | NewsArticle: 16 | title: NewsArticle 17 | type: 18 | - object 19 | - string 20 | properties: 21 | id: 22 | type: integer 23 | format: int32 24 | x-mysql-type: int(11) 25 | allOfNewsArticle: 26 | title: allOfNewsArticle 27 | type: object 28 | allOf: 29 | - $ref: '#/components/schemas/NewsArticle' 30 | - properties: 31 | articleBody: 32 | type: string 33 | anyOfNewsArticle: 34 | title: anyOfNewsArticle 35 | type: object 36 | anyOf: 37 | - $ref: '#/components/schemas/NewsArticle' 38 | - properties: 39 | articleBody: 40 | type: string 41 | oneOfNewsArticle: 42 | title: oneOfNewsArticle 43 | type: object 44 | oneOf: 45 | - $ref: '#/components/schemas/NewsArticle' 46 | - properties: 47 | articleBody: 48 | type: string 49 | notNewsArticle: 50 | title: notNewsArticle 51 | type: object 52 | allOf: 53 | - $ref: '#/components/schemas/NewsArticle' 54 | - not: 55 | type: string 56 | responses: {} 57 | parameters: {} 58 | examples: {} 59 | requestBodies: {} 60 | securitySchemes: {} 61 | headers: {} 62 | -------------------------------------------------------------------------------- /src/test/resources/valid_oas31_simple.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | info: 3 | version: "foo" 4 | title: "foo" 5 | paths: 6 | /users: 7 | get: 8 | responses: 9 | '200': 10 | description: hello world 11 | components: 12 | schemas: 13 | foo: 14 | type: object 15 | -------------------------------------------------------------------------------- /src/test/resources/valid_swagger2.yaml: -------------------------------------------------------------------------------- 1 | swagger: "2.0" 2 | info: 3 | description: "This is a sample server Petstore server. You can find out more about Swagger at http://swagger.io or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters" 4 | version: 1.0.0 5 | title: Swagger Petstore YAML 6 | termsOfService: "http://swagger.io/terms/" 7 | contact: 8 | email: "apiteam@swagger.io" 9 | license: 10 | name: Apache 2.0 11 | url: "http://www.apache.org/licenses/LICENSE-2.0.html" 12 | basePath: /v2 13 | tags: 14 | - name: pet 15 | description: Everything about your Pets 16 | externalDocs: 17 | description: Find out more 18 | url: "http://swagger.io" 19 | - name: store 20 | description: Operations about user 21 | - name: user 22 | description: Access to Petstore orders 23 | externalDocs: 24 | description: Find out more about our store 25 | url: "http://swagger.io" 26 | schemes: 27 | - http 28 | paths: 29 | /pet: 30 | post: 31 | tags: 32 | - pet 33 | summary: Add a new pet to the store 34 | x-swagger-router-controller: SampleController 35 | description: "" 36 | operationId: addPet 37 | consumes: 38 | - application/json 39 | - application/xml 40 | produces: 41 | - application/xml 42 | - application/json 43 | parameters: 44 | - in: body 45 | name: body 46 | description: Pet object that needs to be added to the store 47 | required: false 48 | schema: 49 | $ref: "#/definitions/Pet" 50 | responses: 51 | "405": 52 | description: Invalid input 53 | security: 54 | - petstore_auth: 55 | - "write:pets" 56 | - "read:pets" 57 | put: 58 | tags: 59 | - pet 60 | summary: Update an existing pet 61 | description: "" 62 | operationId: updatePet 63 | consumes: 64 | - application/json 65 | - application/xml 66 | produces: 67 | - application/xml 68 | - application/json 69 | parameters: 70 | - in: body 71 | name: body 72 | description: Pet object that needs to be added to the store 73 | required: false 74 | schema: 75 | $ref: "#/definitions/Pet" 76 | responses: 77 | "400": 78 | description: Invalid ID supplied 79 | "404": 80 | description: Pet not found 81 | "405": 82 | description: Validation exception 83 | security: 84 | - petstore_auth: 85 | - "write:pets" 86 | - "read:pets" 87 | /pet/findByStatus: 88 | get: 89 | tags: 90 | - pet 91 | summary: Finds Pets by status 92 | description: Multiple status values can be provided with comma separated strings 93 | operationId: findPetsByStatus 94 | consumes: 95 | - application/xml 96 | - application/json 97 | - multipart/form-data 98 | - application/x-www-form-urlencoded 99 | produces: 100 | - application/xml 101 | - application/json 102 | parameters: 103 | - name: status 104 | in: query 105 | description: Status values that need to be considered for filter 106 | required: false 107 | type: array 108 | items: 109 | type: string 110 | collectionFormat: multi 111 | default: [available] 112 | enum: 113 | - available 114 | - pending 115 | - sold 116 | responses: 117 | "200": 118 | description: successful operation 119 | schema: 120 | type: array 121 | items: 122 | $ref: "#/definitions/Pet" 123 | "400": 124 | description: Invalid status value 125 | security: 126 | - petstore_auth: 127 | - "write:pets" 128 | - "read:pets" 129 | /pet/findByTags: 130 | get: 131 | tags: 132 | - pet 133 | summary: Finds Pets by tags 134 | description: "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing." 135 | operationId: findPetsByTags 136 | produces: 137 | - application/xml 138 | - application/json 139 | parameters: 140 | - name: tags 141 | in: query 142 | description: Tags to filter by 143 | required: false 144 | type: array 145 | items: 146 | type: string 147 | collectionFormat: multi 148 | responses: 149 | "200": 150 | description: successful operation 151 | schema: 152 | type: array 153 | items: 154 | $ref: "#/definitions/Pet" 155 | "400": 156 | description: Invalid tag value 157 | security: 158 | - petstore_auth: 159 | - "write:pets" 160 | - "read:pets" 161 | "/pet/{petId}": 162 | get: 163 | tags: 164 | - pet 165 | summary: Find pet by ID 166 | description: Returns a single pet 167 | operationId: getPetById 168 | consumes: 169 | - application/x-www-form-urlencoded 170 | produces: 171 | - application/xml 172 | - application/json 173 | parameters: 174 | - name: petId 175 | in: path 176 | description: ID of pet to return 177 | required: true 178 | type: integer 179 | format: int64 180 | responses: 181 | "200": 182 | description: successful operation 183 | schema: 184 | $ref: "#/definitions/Pet" 185 | "400": 186 | description: Invalid ID supplied 187 | "404": 188 | description: Pet not found 189 | security: 190 | - api_key: [] 191 | - petstore_auth: 192 | - "write:pets" 193 | - "read:pets" 194 | post: 195 | tags: 196 | - pet 197 | summary: Updates a pet in the store with form data 198 | description: "" 199 | operationId: updatePetWithForm 200 | consumes: 201 | - application/x-www-form-urlencoded 202 | produces: 203 | - application/xml 204 | - application/json 205 | parameters: 206 | - name: petId 207 | in: path 208 | description: ID of pet that needs to be updated 209 | required: true 210 | type: string 211 | - name: name 212 | in: formData 213 | description: Updated name of the pet 214 | required: false 215 | type: string 216 | - name: status 217 | in: formData 218 | description: Updated status of the pet 219 | required: false 220 | type: string 221 | responses: 222 | "405": 223 | description: Invalid input 224 | security: 225 | - petstore_auth: 226 | - "write:pets" 227 | - "read:pets" 228 | delete: 229 | tags: 230 | - pet 231 | summary: Deletes a pet 232 | description: "" 233 | operationId: deletePet 234 | consumes: 235 | - multipart/form-data 236 | - application/x-www-form-urlencoded 237 | produces: 238 | - application/xml 239 | - application/json 240 | parameters: 241 | - name: api_key 242 | in: header 243 | description: "" 244 | required: false 245 | type: string 246 | - name: petId 247 | in: path 248 | description: Pet id to delete 249 | required: true 250 | type: integer 251 | format: int64 252 | responses: 253 | "400": 254 | description: Invalid pet value 255 | security: 256 | - petstore_auth: 257 | - "write:pets" 258 | - "read:pets" 259 | "/pet/{petId}/uploadImage": 260 | post: 261 | tags: 262 | - pet 263 | summary: uploads an image 264 | x-swagger-router-controller: SampleController 265 | description: "" 266 | operationId: uploadFile 267 | consumes: 268 | - multipart/form-data 269 | produces: 270 | - application/json 271 | parameters: 272 | - name: petId 273 | in: path 274 | description: ID of pet to update 275 | required: true 276 | type: integer 277 | format: int64 278 | - name: additionalMetadata 279 | in: formData 280 | description: Additional data to pass to server 281 | required: false 282 | type: string 283 | - name: file 284 | in: formData 285 | description: file to upload 286 | required: false 287 | type: file 288 | responses: 289 | "200": 290 | description: successful operation 291 | schema: 292 | $ref: "#/definitions/ApiResponse" 293 | security: 294 | - petstore_auth: 295 | - "write:pets" 296 | - "read:pets" 297 | /store/inventory: 298 | get: 299 | tags: 300 | - store 301 | summary: Returns pet inventories by status 302 | description: Returns a map of status codes to quantities 303 | operationId: getInventory 304 | produces: 305 | - application/json 306 | parameters: [] 307 | responses: 308 | "200": 309 | description: successful operation 310 | schema: 311 | type: object 312 | additionalProperties: 313 | type: integer 314 | format: int32 315 | security: 316 | - api_key: [] 317 | /store/order: 318 | post: 319 | tags: 320 | - store 321 | summary: Place an order for a pet 322 | description: "" 323 | operationId: placeOrder 324 | produces: 325 | - application/xml 326 | - application/json 327 | parameters: 328 | - in: body 329 | name: body 330 | description: order placed for purchasing the pet 331 | required: false 332 | schema: 333 | $ref: "#/definitions/Order" 334 | responses: 335 | "200": 336 | description: successful operation 337 | schema: 338 | $ref: "#/definitions/Order" 339 | "400": 340 | description: Invalid Order 341 | "/store/order/{orderId}": 342 | get: 343 | tags: 344 | - store 345 | summary: Find purchase order by ID 346 | description: "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions" 347 | operationId: getOrderById 348 | produces: 349 | - application/xml 350 | - application/json 351 | parameters: 352 | - name: orderId 353 | in: path 354 | description: ID of pet that needs to be fetched 355 | required: true 356 | type: string 357 | responses: 358 | "200": 359 | description: successful operation 360 | schema: 361 | $ref: "#/definitions/Order" 362 | "400": 363 | description: Invalid ID supplied 364 | "404": 365 | description: Order not found 366 | delete: 367 | tags: 368 | - store 369 | summary: Delete purchase order by ID 370 | description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors 371 | operationId: deleteOrder 372 | produces: 373 | - application/xml 374 | - application/json 375 | parameters: 376 | - name: orderId 377 | in: path 378 | description: ID of the order that needs to be deleted 379 | required: true 380 | type: string 381 | responses: 382 | "400": 383 | description: Invalid ID supplied 384 | "404": 385 | description: Order not found 386 | /user: 387 | post: 388 | tags: 389 | - user 390 | summary: Create user 391 | description: This can only be done by the logged in user. 392 | operationId: createUser 393 | produces: 394 | - application/xml 395 | - application/json 396 | parameters: 397 | - in: body 398 | name: body 399 | description: Created user object 400 | required: false 401 | schema: 402 | $ref: "#/definitions/User" 403 | responses: 404 | default: 405 | description: successful operation 406 | /user/createWithArray: 407 | post: 408 | tags: 409 | - user 410 | summary: Creates list of users with given input array 411 | description: "" 412 | operationId: createUsersWithArrayInput 413 | produces: 414 | - application/xml 415 | - application/json 416 | parameters: 417 | - in: body 418 | name: body 419 | description: List of user object 420 | required: false 421 | schema: 422 | type: array 423 | items: 424 | $ref: "#/definitions/User" 425 | responses: 426 | default: 427 | description: successful operation 428 | /user/createWithList: 429 | post: 430 | tags: 431 | - user 432 | summary: Creates list of users with given input array 433 | description: "" 434 | operationId: createUsersWithListInput 435 | produces: 436 | - application/xml 437 | - application/json 438 | parameters: 439 | - in: body 440 | name: body 441 | description: List of user object 442 | required: false 443 | schema: 444 | type: array 445 | items: 446 | $ref: "#/definitions/User" 447 | responses: 448 | default: 449 | description: successful operation 450 | /user/login: 451 | get: 452 | tags: 453 | - user 454 | summary: Logs user into the system 455 | description: "" 456 | operationId: loginUser 457 | produces: 458 | - application/xml 459 | - application/json 460 | parameters: 461 | - name: username 462 | in: query 463 | description: The user name for login 464 | required: false 465 | type: string 466 | - name: password 467 | in: query 468 | description: The password for login in clear text 469 | required: false 470 | type: string 471 | responses: 472 | "200": 473 | description: successful operation 474 | schema: 475 | type: string 476 | headers: 477 | X-Rate-Limit: 478 | type: integer 479 | format: int32 480 | description: calls per hour allowed by the user 481 | X-Expires-After: 482 | type: string 483 | format: date-time 484 | description: date in UTC when toekn expires 485 | "400": 486 | description: Invalid username/password supplied 487 | /user/logout: 488 | get: 489 | tags: 490 | - user 491 | summary: Logs out current logged in user session 492 | description: "" 493 | operationId: logoutUser 494 | produces: 495 | - application/xml 496 | - application/json 497 | parameters: [] 498 | responses: 499 | default: 500 | description: successful operation 501 | "/user/{username}": 502 | get: 503 | tags: 504 | - user 505 | summary: Get user by user name 506 | description: "" 507 | operationId: getUserByName 508 | produces: 509 | - application/xml 510 | - application/json 511 | parameters: 512 | - name: username 513 | in: path 514 | description: "The name that needs to be fetched. Use user1 for testing. " 515 | required: true 516 | type: string 517 | responses: 518 | "200": 519 | description: successful operation 520 | schema: 521 | $ref: "#/definitions/User" 522 | "400": 523 | description: Invalid username supplied 524 | "404": 525 | description: User not found 526 | put: 527 | tags: 528 | - user 529 | summary: Updated user 530 | description: This can only be done by the logged in user. 531 | operationId: updateUser 532 | produces: 533 | - application/xml 534 | - application/json 535 | parameters: 536 | - name: username 537 | in: path 538 | description: name that need to be deleted 539 | required: true 540 | type: string 541 | - in: body 542 | name: body 543 | description: Updated user object 544 | required: false 545 | schema: 546 | $ref: "#/definitions/User" 547 | responses: 548 | "400": 549 | description: Invalid user supplied 550 | "404": 551 | description: User not found 552 | delete: 553 | tags: 554 | - user 555 | summary: Delete user 556 | description: This can only be done by the logged in user. 557 | operationId: deleteUser 558 | produces: 559 | - application/xml 560 | - application/json 561 | parameters: 562 | - name: username 563 | in: path 564 | description: The name that needs to be deleted 565 | required: true 566 | type: string 567 | responses: 568 | "400": 569 | description: Invalid username supplied 570 | "404": 571 | description: User not found 572 | securityDefinitions: 573 | petstore_auth: 574 | type: oauth2 575 | authorizationUrl: "http://petstore.swagger.io/api/oauth/dialog" 576 | flow: implicit 577 | scopes: 578 | "write:pets": modify pets in your account 579 | "read:pets": read your pets 580 | api_key: 581 | type: apiKey 582 | name: api_key 583 | in: header 584 | definitions: 585 | Order: 586 | properties: 587 | id: 588 | type: integer 589 | format: int64 590 | petId: 591 | type: integer 592 | format: int64 593 | quantity: 594 | type: integer 595 | format: int32 596 | shipDate: 597 | type: string 598 | format: date-time 599 | status: 600 | type: string 601 | description: Order Status 602 | enum: 603 | - placed 604 | - approved 605 | - delivered 606 | complete: 607 | type: boolean 608 | xml: 609 | name: Order 610 | Category: 611 | properties: 612 | id: 613 | type: integer 614 | format: int64 615 | name: 616 | type: string 617 | xml: 618 | name: Category 619 | User: 620 | properties: 621 | id: 622 | type: integer 623 | format: int64 624 | username: 625 | type: string 626 | firstName: 627 | type: string 628 | lastName: 629 | type: string 630 | email: 631 | type: string 632 | password: 633 | type: string 634 | phone: 635 | type: string 636 | userStatus: 637 | type: integer 638 | format: int32 639 | description: User Status 640 | xml: 641 | name: User 642 | Tag: 643 | properties: 644 | id: 645 | type: integer 646 | format: int64 647 | name: 648 | type: string 649 | xml: 650 | name: Tag 651 | Pet: 652 | required: 653 | - name 654 | - photoUrls 655 | properties: 656 | id: 657 | type: integer 658 | format: int64 659 | category: 660 | $ref: "#/definitions/Category" 661 | name: 662 | type: string 663 | example: doggie 664 | photoUrls: 665 | type: array 666 | xml: 667 | name: photoUrl 668 | wrapped: true 669 | items: 670 | type: string 671 | tags: 672 | type: array 673 | xml: 674 | name: tag 675 | wrapped: true 676 | items: 677 | $ref: "#/definitions/Tag" 678 | status: 679 | type: string 680 | description: pet status in the store 681 | enum: 682 | - available 683 | - pending 684 | - sold 685 | xml: 686 | name: Pet 687 | ApiResponse: 688 | properties: 689 | code: 690 | type: integer 691 | format: int32 692 | type: 693 | type: string 694 | message: 695 | type: string 696 | xml: 697 | name: "##default" 698 | externalDocs: 699 | description: Find out more about Swagger 700 | url: "http://swagger.io" --------------------------------------------------------------------------------