--- date: "2026-03-04T22:27:37.933286+00:00" git_commit: 91e566efea0cbf53ba06a29b63317b7435609bd8 branch: master topic: "Automatic OpenAPI Validation Pipelines for Backpressure Hooks" tags: [research, openapi, validation, hooks, backpressure, linting] status: complete --- # Research: Automatic OpenAPI Validation Pipelines ## Research Question What automatic validation pipelines exist for OpenAPI specs that can be integrated into the current Claude Code backpressure hook setup, running after the OpenAPI spec has been modified? ## Summary The project already has a PostToolUse hook system that runs backend compile checks and frontend lint/type-checks after Edit/Write operations. Adding OpenAPI spec validation requires a new hook script that triggers specifically when `api.yaml` is modified. Several CLI tools support OpenAPI 3.1.0 validation — **Redocly CLI** is the strongest fit given the existing Node.js toolchain, MIT license, active maintenance, and zero-config baseline. ## Current Backpressure Setup ### Hook Architecture (`.claude/settings.json`) The project uses Claude Code hooks for automated quality gates: | Hook Event | Trigger | Scripts | |---|---|---| | `PostToolUse` | `Edit\|Write` tool calls | `backend-compile-check.sh`, `frontend-check.sh` | | `Stop` | Agent attempts to stop | `run-tests.sh` | ### How Hooks Work Each hook script: 1. Reads JSON from stdin containing `tool_input.file_path` 2. Pattern-matches the file path to decide if it should run 3. Executes validation (compile, lint, type-check, test) 4. Returns JSON with either success message or failure details 5. On failure: outputs `hookSpecificOutput` with error context (PostToolUse) or `{"decision":"block"}` (Stop) ### Existing Pattern for File Matching ```bash # backend-compile-check.sh — matches Java files case "$FILE_PATH" in */backend/src/*.java|backend/src/*.java) ;; *) exit 0 ;; esac # frontend-check.sh — matches TS/Vue files case "$FILE_PATH" in */frontend/src/*.ts|*/frontend/src/*.vue|frontend/src/*.ts|frontend/src/*.vue) ;; *) exit 0 ;; esac ``` An OpenAPI validation hook would use the same pattern: ```bash case "$FILE_PATH" in */openapi/api.yaml|*/openapi/*.yaml) ;; *) exit 0 ;; esac ``` ### Existing OpenAPI Tooling in the Project - **Backend:** `openapi-generator-maven-plugin` v7.20.0 generates Spring interfaces from `api.yaml` (`pom.xml:149-178`) - **Frontend:** `openapi-typescript` v7.13.0 generates TypeScript types; `openapi-fetch` v0.17.0 provides type-safe client - **No validation/linting tools** currently installed — no Redocly, Spectral, or other linter config exists ## Tool Evaluation ### Redocly CLI (`@redocly/cli`) | Attribute | Value | |---|---| | OpenAPI 3.1 | Full support | | Install | `npm install -g @redocly/cli` or `npx @redocly/cli@latest` | | CLI | `redocly lint api.yaml` | | License | MIT | | Maintenance | Very active — latest v2.20.3 (2026-03-03), daily/weekly releases | | GitHub | ~1.4k stars (Redocly ecosystem: 24k+ combined) | **Checks:** Structural validity against OAS schema, configurable linting rules (naming, descriptions, operation IDs, security), style/consistency enforcement. Built-in rulesets: `minimal`, `recommended`, `recommended-strict`. Zero-config baseline works immediately. Custom rules via `redocly.yaml`. **Fit for this project:** Node.js already in the toolchain (frontend). `npx` form requires no permanent install. MIT license compatible with GPL-3.0. The `@redocly/openapi-core` package is already present as a transitive dependency of `openapi-typescript` in `node_modules`. ### Spectral (`@stoplight/spectral-cli`) | Attribute | Value | |---|---| | OpenAPI 3.1 | Full support (since v6.x) | | Install | `npm install -g @stoplight/spectral-cli` | | CLI | `spectral lint api.yaml` | | License | Apache 2.0 | | Maintenance | Active — latest v6.15.0 (2025-04-22), slower cadence | | GitHub | ~3k stars | **Checks:** Schema compliance, missing descriptions/tags/operationIds, contact/license metadata. Highly extensible custom rulesets via YAML/JS. Configurable severity levels. **Fit for this project:** Well-established industry standard. Apache 2.0 compatible with GPL. Less actively maintained than Redocly (10 months since last release). Heavier custom ruleset system may be over-engineered for current needs. ### Vacuum (`daveshanley/vacuum`) | Attribute | Value | |---|---| | OpenAPI 3.1 | Full support (via libopenapi) | | Install | `brew install daveshanley/vacuum/vacuum` or Go binary | | CLI | `vacuum lint api.yaml` | | License | MIT | | Maintenance | Active — latest release 2025-12-22 | | GitHub | ~1k stars | **Checks:** Structural validation, Spectral-compatible rulesets, OWASP security checks, naming conventions, descriptions/examples/tags. Single Go binary — no runtime dependencies. **Fit for this project:** Zero-dependency binary is appealing for CI. However, adds a non-Node.js tool dependency when the project already has Node.js. Spectral ruleset compatibility is a plus for portability. ### oasdiff (`oasdiff/oasdiff`) | Attribute | Value | |---|---| | OpenAPI 3.1 | Beta | | Install | `brew install oasdiff` or Go binary | | CLI | `oasdiff breaking base.yaml revision.yaml` | | License | Apache 2.0 | | Maintenance | Active — latest v1.11.10 (2026-02-05) | | GitHub | ~1.1k stars | **Checks:** 300+ breaking change detection rules (paths, parameters, schemas, security, headers, enums). Requires two spec versions to compare — not a standalone validator. **Fit for this project:** Different category — detects breaking changes between spec versions, not structural validity. Useful as a CI-only check comparing `HEAD~1` vs `HEAD`. OAS 3.1 support is still beta. ### Not Recommended - **swagger-cli:** Abandoned, no OAS 3.1 support - **IBM OpenAPI Validator:** Active but opinionated IBM-specific rules add configuration overhead for no benefit ## Tool Comparison Matrix | Tool | OAS 3.1 | License | Last Release | Stars | Runtime | Category | |---|---|---|---|---|---|---| | **Redocly CLI** | Full | MIT | 2026-03-03 | ~1.4k | Node.js | Lint + validate | | **Spectral** | Full | Apache 2.0 | 2025-04-22 | ~3k | Node.js | Lint | | **Vacuum** | Full | MIT | 2025-12-22 | ~1k | Go binary | Lint + validate | | **oasdiff** | Beta | Apache 2.0 | 2026-02-05 | ~1.1k | Go binary | Breaking changes | ## Integration Pattern ### Hook Script Structure An OpenAPI validation hook would follow the existing pattern in `.claude/hooks/`: ```bash #!/usr/bin/env bash set -euo pipefail INPUT=$(cat) FILE_PATH=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('file_path',''))" 2>/dev/null || echo "") # Only run for OpenAPI spec files case "$FILE_PATH" in */openapi/*.yaml|*/openapi/*.yml) ;; *) exit 0 ;; esac cd "$CLAUDE_PROJECT_DIR/backend" # Run validation if OUTPUT=$(npx @redocly/cli@latest lint src/main/resources/openapi/api.yaml --format=stylish 2>&1); then echo '{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"✓ OpenAPI spec validation passed."}}' else ESCAPED=$(echo "$OUTPUT" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))") echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":$ESCAPED}}" fi ``` ### Registration in `.claude/settings.json` The hook would be added to the existing `PostToolUse` array alongside the compile and lint hooks: ```json { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/openapi-validate.sh\"", "timeout": 120 } ``` ### Configuration (Optional) A `redocly.yaml` in the project root or `backend/` directory can customize rules: ```yaml extends: - recommended rules: operation-operationId: error tag-description: warn no-ambiguous-paths: error ``` ## Code References - `.claude/settings.json:1-32` — Hook configuration (PostToolUse + Stop events) - `.claude/hooks/backend-compile-check.sh` — Java file detection pattern + compile check - `.claude/hooks/frontend-check.sh` — TS/Vue file detection pattern + type-check + lint - `.claude/hooks/run-tests.sh` — Stop hook with test execution and block/approve logic - `backend/pom.xml:149-178` — openapi-generator-maven-plugin configuration - `backend/src/main/resources/openapi/api.yaml` — The OpenAPI 3.1.0 spec to validate ## Open Questions - Should the validation use a pinned version (`npx @redocly/cli@1.x.x`) or latest? Pinned is more reproducible; latest gets rule updates automatically. - Should a `redocly.yaml` config be added immediately with the `recommended` ruleset, or start with zero-config (structural validation only) and add rules incrementally? - Is breaking change detection (oasdiff) desirable as a separate CI check, or is structural validation sufficient for now?