Skip to main content

oas-validator

The oas-validator plugin validates incoming HTTP requests against an OpenAPI 3 specification before forwarding them upstream. It does not validate upstream responses.

OpenAPI 3.1 support was introduced in API7 Enterprise 3.9.8 and APISIX 3.17.0.

Examples​

The examples use version 1.0.27 of the official Swagger Petstore image. The fixture serves both the OpenAPI document and the API. Its manifest digest is pinned so the validation results remain reproducible.

Start Petstore​

Start the fixture for the deployment type used by the gateway:

Set GATEWAY_CONTAINER to the running APISIX or API7 Gateway container, then place the gateway and Petstore on a dedicated network:

export GATEWAY_CONTAINER=replace-with-gateway-container-name

docker network inspect gateway-petstore-net > /dev/null 2>&1 || \
docker network create gateway-petstore-net

if ! docker inspect "$GATEWAY_CONTAINER" \
--format '{{json .NetworkSettings.Networks}}' \
| grep -q '"gateway-petstore-net"'; then
docker network connect gateway-petstore-net "$GATEWAY_CONTAINER"
fi

Create a Compose file for the pinned Petstore fixture on the shared network:

docker-compose.petstore.yaml
services:
petstore:
image: swaggerapi/petstore3:1.0.27@sha256:749432676c31cd05256f0d9e878302164debb94daa1c1223e193747e1b34e7d1
platform: linux/amd64
networks:
- gateway-petstore-net
ports:
- "18080:8080"

networks:
gateway-petstore-net:
external: true

Start or reconcile the fixture with a fixed Compose project name so the command can be rerun across these guides:

docker compose -p api7-docs-petstore \
-f docker-compose.petstore.yaml up -d

Once the container has started, confirm that the OpenAPI document is available:

curl -fsS "http://127.0.0.1:18080/api/v3/openapi.json" > /dev/null

The Admin API examples load the OpenAPI document inline. If Petstore runs on Kubernetes, make the document available locally in another terminal:

kubectl port-forward -n aic service/petstore 18080:8080

For the Admin API tabs, fetch and escape the document for the JSON request body:

export OPEN_API_SPEC="$(curl -fsS "http://127.0.0.1:18080/api/v3/openapi.json" | jq -Rs .)"

The ADC and Ingress Controller examples use spec_url so the gateway retrieves the same document directly from the fixture.

Validate Request Body​

The following example demonstrates how to validate a request body against an OpenAPI specification.

Create the following route with the OAS validator plugin:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"id": "body_validation",
"uri": "/*",
"plugins": {
"oas-validator": {
"spec": ${OPEN_API_SPEC}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"petstore:8080": 1
},
"scheme": "http",
"pass_host": "node"
}
}
EOF

Failed Validation​

Send a request to the route with a body that does not satisfy the OpenAPI specification:

curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"name": "doggie"}'

You should see an HTTP/1.1 400 Bad Request response with the response body similar to the following:

{"message":"failed to validate request."}

Successful Validation​

Send a request to the route with a valid request body:

curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": 1,
"name": "doggie",
"category": { "id": 1, "name": "Dogs" },
"photoUrls": ["string"],
"tags": [{ "id": 1, "name": "tag1" }],
"status": "available"
}'

You should see an HTTP/1.1 200 OK response with the response body similar to the following:

{
"id": 1,
"category": { "id": 1, "name": "Dogs" },
"name": "doggie",
"photoUrls": ["string"],
"tags": [{ "id": 1, "name": "tag1" }],
"status": "available"
}

Get Verbose Error Response​

The following example demonstrates how to return a verbose error response when validation fails.

Create a route with the OAS Validator plugin:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"id": "body_validation",
"uri": "/*",
"plugins": {
"oas-validator": {
"spec": ${OPEN_API_SPEC},
"verbose_errors": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"petstore:8080": 1
},
"scheme": "http",
"pass_host": "node"
}
}
EOF

Send a request to the route created above with an invalid request body:

curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"name": "doggie"}'

You should see an HTTP/1.1 400 Bad Request response with the response body similar to the following:

{
"message": "failed to validate request. body: property \"photoUrls\" is required"
}

Allow Non-Compliant Requests to Pass​

By default, requests that fail OpenAPI validation are rejected. Set reject_if_not_match to false to log the validation error and forward the request to the upstream instead. This option was introduced in API7 Enterprise 3.9.6 and APISIX 3.17.0.

Update the route to set reject_if_not_match to false:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"id": "body_validation",
"uri": "/*",
"plugins": {
"oas-validator": {
"spec": ${OPEN_API_SPEC},
"reject_if_not_match": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"petstore:8080": 1
},
"scheme": "http",
"pass_host": "node"
}
}
EOF

Send a request with an invalid body:

curl -i "http://127.0.0.1:9080/api/v3/pet" -X POST \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"id": 101, "photoUrls": []}'

The OpenAPI document requires name, but Petstore accepts the deserialized object without it. You should receive an HTTP/1.1 200 OK response with a body similar to:

{"id":101,"photoUrls":[],"tags":[]}

This confirms that the plugin forwarded the non-compliant request instead of rejecting it.

You should also see an error log capturing the method, URI, and validation error similar to this:

[error] error occurred while validating request [POST /api/v3/pet], err: ...

This lets you audit non-compliant traffic while leaving the upstream to decide whether to accept or reject it.

Validate Using Remote Spec URL​

The following example demonstrates how to load an OpenAPI specification from a remote URL. Remote specification support was introduced in API7 Enterprise 3.9.12 and APISIX 3.17.0.

Use spec_url when an OpenAPI specification is too large to embed inline or should refresh automatically. The inline spec field has a 2 MB size limit.

The plugin caches the compiled specification. After the cache expires, the stale entry continues serving requests while APISIX refreshes it in the background.

If the initial fetch or compilation fails and no cached specification is available, the plugin returns 500 Internal Server Error.

TLS certificate verification for spec_url is disabled by default for compatibility. Set ssl_verify to true and configure a trusted certificate chain in production.

Create a route that fetches the spec from a URL:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "url_validation",
"uri": "/*",
"plugins": {
"oas-validator": {
"spec_url": "http://petstore:8080/api/v3/openapi.json",
"timeout": 5000
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"petstore:8080": 1
},
"scheme": "http",
"pass_host": "node"
}
}'

If the spec endpoint requires authentication, use the same configuration shape and replace the placeholder URL, backend, and token with values from your environment:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "url_validation",
"uri": "/*",
"plugins": {
"oas-validator": {
"spec_url": "https://internal-api.example.com/openapi.json",
"spec_url_request_headers": { "Authorization": "Bearer <token>" },
"timeout": 5000
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"internal-api.example.com:443": 1
},
"scheme": "https",
"pass_host": "node"
}
}'

To configure the cache TTL for the fetched spec (default is 3600 seconds), set plugin metadata:

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/oas-validator" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"spec_url_ttl": 1800
}'