Summary
Our demo Card application deployed as here in has OpenAPI yaml and is published here: https://deck-api.api.kambur.ie/shuffledDeck.yaml. Requests should be validated, on API Gateway (in our case APISIX) before hitting application servers for performance (as then bad requests never hit application servers to be validated) and security reasons (bad requests get caught sooner and away from application servers reducing potentail attack footprint). Note that APISIX needs to be >= 3.17.
Implementation
yaml version of OpenAPI
APISIX’s oas-validate plugin can’t consume yaml - needs json instead. The following change to pipeline will take yaml file and
convert as json and use existing sidecar to make available.
- name: Deploy to Kubernetes
run: |
export IMAGE_TAG IMAGE_NAME
# 1. Convert OpenAPI YAML to JSON
yq eval -o=json src/main/resources/swagger/api-docs/shuffledDeck.yaml > src/main/resources/swagger/api-docs/shuffledDeck.json
# 2. Generate ConfigMap with the JSON file instead of YAML
kubectl create configmap api-docs \
--from-file=shuffledDeck.json=src/main/resources/swagger/api-docs/shuffledDeck.json \
--from-file=swagger-ui.html=src/main/resources/swagger/api-docs/swagger-ui.html \
--from-file=health=src/main/resources/swagger/health \
-n ramblings \
--dry-run=client -o yaml | kubectl apply -f -
# 3. Apply deployment with envsubst
envsubst < kubernetes/k8s-deployment.yaml | kubectl apply -f -
Modify the route to validate
Simply, add plugins/oas-validator to the route in question and point to the generated json. Job done.
Ah, don’t forget to fix all kinds of hidden mistakes in your API spec.
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $APISIX_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-X PUT \
-i \
-d '{
"name": "1",
"status": 1,
"id": "1",
"enable_websocket": false,
"priority": 0,
"uri": "/deck-api/*",
"methods": [
"GET",
"POST",
"PUT",
"DELETE",
"PATCH"
],
"plugins": {
"oas-validator": {
"spec_url": "http://ramblings-app.ramblings.svc.cluster.local:80/shuffledDeck.json",
"timeout": 5000,
"verbose_errors": true
}
},
"upstream_id": "1"
}'