docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

docs(admin): expand OpenAPI document to cover every mounted route - #96

Merged
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness
May 7, 2026
Merged

docs(admin): expand OpenAPI document to cover every mounted route#96
moonming merged 1 commit into
mainfrom
chore/admin-openapi-completeness

Conversation

@moonming

@moonmingmoonming commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

The hand-written OpenAPI document at /admin/openapi.json was stuck at the original two resources (Models + ApiKeys). After PR #95 added ProviderKey, several routes that exist in build_router weren't reflected in the spec — meaning Scalar UI users had no way to discover them.

What's documented now

Every route mounted in crate::build_router (lib.rs lines 47–96):

  • /health — process health + snapshot counts
  • /metrics — Prometheus
  • /admin/openapi.json + /admin/openapi-scalar — self-references
  • /admin/v1/models — CRUD
  • /admin/v1/apikeys — CRUD + POST .../rotate
  • /admin/v1/provider_keys — CRUD
  • /admin/v1/health — per-Model upstream health
  • /playground/chat/completions — proxy in-process

Reusable schemas added

Model (new shape: display_name + provider + model_name + provider_key_id), ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError, plus ModelEntry / ApiKeyEntry wrappers for the {id, value, revision} response envelope.

Public-route security

/health, /metrics, /admin/openapi.json, /admin/openapi-scalar are marked with security: [] so Scalar's "Try it" doesn't prompt for an admin key on them. Mirrors the design comment in lib.rs ("OpenAPI scalar UI is unauthenticated like /metrics").

Drive-by: README correction

The previous README overpromised /admin/v1/guardrails, /admin/v1/cache_policies, /admin/v1/observability_exporters, and /admin/v1/spend as if those were live admin routes. They aren't — those resources exist as core types and are honoured at runtime, but standalone CRUD goes through direct etcd writes today. Listed accurately with a one-line "handlers will follow" note.

Test plan

  • cargo fmt --all --check clean
  • cargo clippy --workspace --tests -- -D warnings clean
  • cargo test -p aisix-admin green (46 passed; includes two new openapi assertions: path coverage + public-route security)
  • New unit test walks every documented path + every reusable schema and fails on first missing entry, so future route adds get a forcing function

Summary by CodeRabbit

  • Documentation

    • Clarified Admin API availability in standalone mode, focusing on routing-related resource operations
    • Expanded OpenAPI specification with comprehensive endpoint documentation, including parameters, request schemas, and detailed response definitions
    • Enhanced API descriptions and summaries for improved clarity
  • Tests

    • Strengthened API specification validation tests to verify endpoint documentation completeness and schema integrity

The hand-written OpenAPI document was stuck at the original two
resources (Models + ApiKeys) — provider_keys, the apikey rotate sub-
resource, /admin/v1/health, /playground/chat/completions, and the
unauthenticated /health, /metrics, /admin/openapi.json,
/admin/openapi-scalar were all missing. Scalar UI loaders look at this
JSON to populate the left-hand sidebar, so anyone opening
/admin/openapi-scalar in the browser had no way to discover those
routes.
This commit:
- Documents every route mounted in `build_router` (lib.rs line 47-96)
- Adds reusable component schemas: Model (with the new
display_name/provider/model_name/provider_key_id shape from #95),
ApiKey, ProviderKey, RateLimit, Routing, ModelCost, AdminError,
plus *Entry wrappers for the response shape `{id, value, revision}`
- Marks the four public routes (/health, /metrics, /admin/openapi.*)
with `security: []` so Scalar's "Try it" doesn't prompt for an
admin key on them
- Pins coverage with a unit test that walks every documented path +
every reusable schema and fails on first missing entry
Bumps the raw-string delimiter from `r#"..."#` to `r##"..."##` because
the embedded JSON `$ref` pointers (`"#/components/schemas/Foo"`)
collide with the `#` in the closing delimiter.
Drive-by README correction: the previous entry overpromised
`/admin/v1/guardrails`, `/admin/v1/cache_policies`,
`/admin/v1/observability_exporters`, and `/admin/v1/spend` as if they
were live admin routes. They aren't — those resources exist as core
types and are honoured at runtime, but standalone CRUD over them is
direct-etcd-write today. Listed honestly with a one-line "handlers
will follow" note.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (46 passed, includes the two new
openapi assertions covering path coverage + public-route security)
CopilotAI review requested due to automatic review settings May 7, 2026 03:01
@coderabbitai

coderabbitaiBot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 51310632-13af-4302-9597-dfc049707434

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1bac9 and f3140ab.

📒 Files selected for processing (2)
  • README.md
  • crates/aisix-admin/src/openapi.rs

📝 Walkthrough

Walkthrough

This PR expands the OpenAPI specification for the admin API with comprehensive endpoint definitions, schemas, and security schemes. Tests are strengthened to validate spec structure and security properties. README documentation is clarified to distinguish between runtime-honored resource types and standalone mode CRUD availability.

Changes

Admin API Documentation and OpenAPI Spec Update

Layer / File(s)Summary
OpenAPI Specification Contract
crates/aisix-admin/src/openapi.rs
OpenAPI 3.1 spec expanded from minimal stub to comprehensive definition with /admin/* and /playground/chat/completions endpoints, detailed schemas (ProviderKey, Routing, ModelCost, AdminError), security schemes for admin and proxy keys, and extended info.description.
OpenAPI Validation Tests
crates/aisix-admin/src/openapi.rs
Well-formedness test extended to verify all expected paths exist and all referenced schemas are defined. New test validates that designated unauthenticated routes correctly declare security: [] on GET operations.
README Documentation
README.md
Admin API section updated to list only routing-related resources. New clarification paragraph explains that guardrails, cache policies, and observability exporters are aisix-core resource types honored at runtime; standalone CRUD for these is not yet implemented.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Note

🎁 Summarized by CodeRabbit Free

Your 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 @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the aisix-admin hand-written OpenAPI 3.1 document so the Scalar UI reflects all routes mounted by crates/aisix-admin::build_router, and updates the README to accurately describe which admin resources are actually CRUD-backed today.

Changes:

  • Documented all mounted admin/playground/health/metrics routes in /admin/openapi.json and exposed them in Scalar UI.
  • Added reusable component schemas (Model/ApiKey/ProviderKey/etc.) and OpenAPI unit tests to enforce path/security coverage.
  • Corrected README claims about non-existent standalone admin CRUD resources.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

FileDescription
README.mdUpdates “What’s shipped today” to remove unsupported admin CRUD routes and add a clarification note.
crates/aisix-admin/src/openapi.rsExpands the OpenAPI JSON to cover all mounted routes; adds component schemas and tests for path + public-route security coverage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +175 to +186
"required": ["display_name"],
"properties": {
"display_name": {"type": "string", "example": "my-gpt4"},
"provider": {"type": "string", "enum": ["openai","anthropic","gemini","deepseek"]},
"model_name": {"type": "string", "example": "gpt-4o"},
"provider_key_id": {"type": "string", "example": "11111111-1111-1111-1111-111111111111"},
"timeout": {"type": "integer", "minimum": 0, "description": "Request timeout in milliseconds. Absent or 0 = no timeout."},
"rate_limit": {"$ref": "#/components/schemas/RateLimit"},
"routing": {"$ref": "#/components/schemas/Routing"},
"cost": {"$ref": "#/components/schemas/ModelCost"}
},
"description": "A direct model ships `provider` + `model_name` + `provider_key_id`; a routing model ships `routing` and omits the upstream triple."
Comment on lines +69 to +75
"summary": "create model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {
"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelEntry"}}}},
"400": {"description": "schema validation failed"},
"409": {"description": "duplicate display_name"}
}
Comment on lines +81 to +85
"put": {
"summary": "update model",
"requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Model"}}}},
"responses": {"200": {"description": "OK"}, "400": {"description": "schema validation failed"}, "404": {"description": "not found"}, "409": {"description": "duplicate display_name"}}
},
"required": ["key_hash", "allowed_models"],
"properties": {
"key_hash": {"type": "string", "description": "SHA-256 hex of the plaintext bearer. Lowercase.", "example": "91ed2dbc407561556f3e7be98ba0bd2a57986d6a868c482d867d19c6d40d201c"},
"allowed_models": {"type": "array", "items": {"type": "string"}, "description": "Allowed Model display_names. `[\"*\"]` for all; `[]` denies everything."},
"type": "object",
"required": ["model"],
"properties": {
"model": {"type": "string", "description": "Target Model.display_name"},
@moonming
moonming merged commit cca5b6f into mainMay 7, 2026
11 checks passed
@moonming
moonming deleted the chore/admin-openapi-completeness branch May 7, 2026 03:13
moonming added a commit that referenced this pull request May 7, 2026
…ility_exporters (#97)
Brings the standalone Admin API up to parity with the resource types
that aisix-core already understands and the gateway already honours
at runtime. Before this PR, those three resources existed as snapshot
tables and runtime hooks but had no admin endpoint — operators had
to hand-write etcd keys to configure them, which is exactly the
sharp edge an admin layer is supposed to file off.
Adds
- `guardrails_handlers.rs`, `cache_policies_handlers.rs`,
`observability_exporters_handlers.rs` — same template as
`provider_keys_handlers.rs`: validate JSON, reject duplicate name,
uuid v4 on POST, bump revision on PUT.
- 12 new `ConfigStore` trait methods (4 per resource), implemented
on both `InMemoryStore` and `EtcdConfigStore`.
- 6 new routes wired into `build_router`:
`/admin/v1/guardrails[/:id]`
`/admin/v1/cache_policies[/:id]`
`/admin/v1/observability_exporters[/:id]`
- 3 new etcd subkey constants (`guardrails`, `cache_policies`,
`observability_exporters`) — match the kind segments
`aisix-etcd::loader` already dispatches on, so writes from the
admin path land in the same prefix the watch supervisor reads.
- OpenAPI document expanded to include the new paths AND component
schemas (`Guardrail`, `CachePolicy`, `ObservabilityExporter`); the
forcing-function test from #96 walks the new entries.
- Five integration tests covering the happy path + duplicate-name
409 + bad-payload 400 + the loopback-only http endpoint guard on
observability exporters.
Re-exports `CachePolicy`, `ObservabilityExporter`, `ExporterKind`,
`validate_cache_policy`, `validate_observability_exporter` at the
`aisix_core` crate root so handlers can name them without reaching
into `aisix_core::models::*`.
Drive-by: README's "Admin handlers will follow" caveat is gone — the
list is now accurate.
Verified
- `cargo fmt --all --check` clean
- `cargo clippy --workspace --tests -- -D warnings` clean
- `cargo test -p aisix-admin` green (51 passed; +5 new)
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@moonming