refactor(admin): merge resource JSON Schemas into served OpenAPI doc - #310
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (3)
Note 🎁 Summarized by CodeRabbit FreeYour organization has reached its limit of developer seats under the Pro Plan. For new users, CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please add seats to your subscription by visiting https://app.coderabbit.ai/login.If you believe this is a mistake and have available seats, please assign one to the pull request author through the subscription management page using the link above. Comment |
`merged_openapi` previously parsed and merged the embedded resource schemas on the first `/admin/openapi.json` request. That delayed any panic from a corrupt schema fragment until well after boot — a worse ops failure mode than crashing immediately on startup, especially since the panic is captured by axum's error handling and surfaces as a 500 to whoever happens to hit Scalar first. Move the init call up: `build_router` now calls `openapi::merged_openapi()` once at construction time, before any request can land. The result is cached in the same `OnceLock` so the handler still does a free lookup. Visibility on `merged_openapi` flips from private to `pub(crate)` to make the pre-warm callable from `lib.rs`; no other surface change. Surfaced by independent audit of #310. Refs #304 (#1).
The hand-written OpenAPI 3.1 document in `crates/aisix-admin/src/openapi.rs` previously inlined its own copy of every resource schema (`Model`, `ApiKey`, `ProviderKey`, `Guardrail`, `CachePolicy`, `ObservabilityExporter`, `RateLimit`, `Routing`, plus the nested `ModelCost` / `BackgroundModelCheck`). That left three places to keep in sync whenever a resource field changed: the Rust struct, the inline OpenAPI schema, and the cp-api / dashboard side. This PR cuts the duplication. The Rust struct is now the single source of truth; `dump-schema` (PR #308) writes canonical draft-07 JSON Schemas into `schemas/resources/*.schema.json`; CI (PR #309) enforces those files match the structs. This commit: 1. Removes the ten inlined resource schemas from `OPENAPI_JSON_BASE` (the const formerly named `OPENAPI_JSON`). 2. Embeds the eight canonical schema files at compile time via `include_str!` into a new `RESOURCE_SCHEMAS` const. 3. Adds `merged_openapi()` — runs once on first request, parses the base spec, parses each embedded schema, hoists `definitions/*` into top-level `components.schemas`, rewrites `$ref: #/definitions/X` to `$ref: #/components/schemas/X` (JSON Schema draft-07 → OpenAPI 3.1), and caches the result in an `OnceLock<String>`. 4. Changes `openapi_json()` to serve the merged doc instead of the raw `OPENAPI_JSON_BASE`. 5. Updates the three openapi unit tests to parse `merged_openapi()`. ## What this means for `/admin/openapi.json` The served document keeps the same wrapper schemas (`ModelEntry`, `ApiKeyEntry`, `ModelStatusView`, `ModelKind`, `RuntimeStatus`, `SystemTime`, `AdminError`) and gains 16 new top-level component schemas hoisted from the resource definitions (`Adapter`, `BedrockConfig`, `CacheBackend`, `CooldownConfig`, `GuardrailHookPoint`, `KeywordPattern`, `OnAllFilteredPolicy`, `ParamConstraints`, `Provider`, `RequestOverrides`, `ResponseOverrides`, `RoutingStrategy`, `RoutingTarget`, `StreamDoneMarker`, `TelemetryTags`, etc.). The resource schemas themselves are now precise reflections of the Rust types — e.g. `Guardrail` uses a proper `oneOf` discriminator on `kind` instead of the previous flat `additionalProperties: true` hand-wave; `Provider` lists its 6 variants from the actual enum; `Adapter` lists the 5 wire-shape kebab-case values from #302 Phase A. ## Verification - `cargo check -p aisix-admin` clean - `cargo clippy --workspace --all-targets -- -D warnings` clean - `cargo fmt --all -- --check` clean - `cargo test -p aisix-admin --lib` — all 7 openapi tests pass, including the regression test `openapi_apikey_schema_excludes_max_budget_usd` - External validation: parsed the merged doc, collected 43 `$ref` references across 32 distinct targets, all resolve inside `#/components/schemas/*` (0 unresolved) ## Why nested `if let` instead of let-chains Workspace is on `edition = "2021"`. The merge logic uses one level of nesting in two spots; not pretty, but `edition = "2024"` is a separate decision not in this PR's scope. ## Stack Builds on: - #307 (JsonSchema derives on resource structs) - #308 (dump-schema binary + initial schema files) - #309 (CI drift enforcement) Merge order: 307 → 308 → 309 → this PR. Base will switch to `main` once #308 merges. Refs #304 (#1).
`merged_openapi` previously parsed and merged the embedded resource schemas on the first `/admin/openapi.json` request. That delayed any panic from a corrupt schema fragment until well after boot — a worse ops failure mode than crashing immediately on startup, especially since the panic is captured by axum's error handling and surfaces as a 500 to whoever happens to hit Scalar first. Move the init call up: `build_router` now calls `openapi::merged_openapi()` once at construction time, before any request can land. The result is cached in the same `OnceLock` so the handler still does a free lookup. Visibility on `merged_openapi` flips from private to `pub(crate)` to make the pre-warm callable from `lib.rs`; no other surface change. Surfaced by independent audit of #310. Refs #304 (#1).
54d0f47 to
a6505f7
Compare
`crates/aisix-admin/src/openapi.rs` uses `include_str!` to embed
every `schemas/resources/*.schema.json` at compile time. The Docker
release stage previously copied only `Cargo.{toml,lock}`,
`rust-toolchain.toml`, `rustfmt.toml`, and `crates/` — `cargo build`
inside the container therefore failed with eight
"couldn't read .../schemas/resources/*.schema.json" errors.
Adds a `COPY schemas ./schemas` line and an inline comment pinning
the dependency between `include_str!` and the docker context.
Surfaced by CI on PR #310 (build job).
Refs #304 (#1).
Summary
Cuts the schema-duplication tail in
crates/aisix-admin/src/openapi.rs. Resource shapes (Model,ApiKey,ProviderKey,Guardrail,CachePolicy,ObservabilityExporter,RateLimit,Routing) are no longer hand-written inside the OpenAPI document — they are pulled at compile time from the canonical filesschemas/resources/*.schema.json(generated bydump-schemain #308, drift-guarded by CI in #309) and merged into the served spec at first request.Before / After
kinddiscriminationadditionalProperties: true+ commentoneOfwith proper sub-schemasProviderenumAdapterenum (#302 Phase A)ParamConstraints,TelemetryTags, etc.)components.schemasImplementation sketch
Full diff: +148 / −141 across the one file.
Verification
cargo check -p aisix-admincleancargo clippy --workspace --all-targets -- -D warningscleancargo fmt --all -- --checkcleancargo test -p aisix-admin --lib— all 7 openapi tests pass, includingopenapi_apikey_schema_excludes_max_budget_usd(regression test against managed-mode field leak)$refreferences across 32 distinct targets, 0 unresolved. Every reference inside the served spec is locally resolvable — Scalar UI never needs to fetch anything external.Behavior change
The served
/admin/openapi.jsonbody is materially different (more precise types, more nested definitions surfaced). Wire path / status codes / auth / error envelope are unchanged. Scalar UI keeps working at/admin/openapi-scalarunchanged.What this does NOT do
schemars0.8 → 1.x. Output stays draft-07; OpenAPI 3.1 tolerates this for inline schemas, but a future upgrade is worth tracking (separate issue)./admin/v1/*). Those are still hand-maintained inOPENAPI_JSON_BASE(formerlyOPENAPI_JSON)./v1/chat/completionssurface — out of scope per existing module-level comment ("operators refer to OpenAI's published spec").Stack
Builds on:
chore(core): derive JsonSchema on resource types)chore(core): add dump-schema binary and commit canonical schemas)ci: add schema drift check for resource JSON Schemas)Merge order: #307 → #308 → #309 → this PR.
Refs #304 (#1).