
Phoenix Rest Api
- 11 installs
- 10.9k repo stars
- Updated August 4, 2026
- arize-ai/phoenix
phoenix-rest-api is a Claude skill for adding, modifying, and reviewing REST endpoints in the Phoenix server's v1 API router.
About
This skill guides REST API development for the Phoenix server. A developer uses it when adding, modifying, or reviewing endpoints in src/phoenix/server/api/routers/v1/. It provides a pre-commit checklist that regenerates the OpenAPI schema and client types, registers the endpoint in the correct integration-test coverage list by method, and runs the Python linter.
- Pre-commit checklist for any endpoint change (make openapi, coverage, lint)
- Maps endpoints to the correct integration test coverage list by HTTP method
- References for endpoint patterns, OpenAPI codegen, and testing
Phoenix Rest Api by the numbers
- 11 all-time installs (skills.sh)
- +5 installs in the week ending Jul 12, 2026 (Skillselion tracking)
- Ranked #3,574 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
phoenix-rest-api capabilities & compatibility
- Capabilities
- api development · rest api · openapi codegen
- Use cases
- api development · testing
What phoenix-rest-api says it does
REST API development for Phoenix. Use when adding, modifying, or reviewing endpoints in src/phoenix/server/api/routers/v1/.
`make openapi` — regenerate schema + client types, commit all generated files
npx skills add https://github.com/arize-ai/phoenix --skill phoenix-rest-apiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 11 |
|---|---|
| repo stars | ★ 10.9k |
| Last updated | August 4, 2026 |
| Repository | arize-ai/phoenix ↗ |
What it does
Add, modify, or review REST endpoints in the Phoenix server with an OpenAPI regeneration and test-coverage checklist.
Who is it for?
Endpoint changes in src/phoenix/server/api/routers/v1/ that must stay OpenAPI-consistent and test-covered
Skip if: GraphQL mutations or frontend code (covered by other Phoenix skills)
When should I use this skill?
Adding, modifying, or reviewing endpoints in src/phoenix/server/api/routers/v1/
What you get
Every endpoint change regenerates the schema, registers test coverage, and passes lint before commit
- a REST endpoint change
- regenerated OpenAPI schema and client types
- integration test coverage entry
By the numbers
- 3-item pre-commit checklist
- 3 reference files (endpoint-patterns, openapi-codegen, testing-patterns)
Files
Phoenix REST API
Endpoints: src/phoenix/server/api/routers/v1/. Read the relevant reference.
Checklist — run before committing any endpoint change
1. make openapi — regenerate schema + client types, commit all generated files 2. Add endpoint to the correct list in tests/integration/_helpers.py:
- GET →
_COMMON_RESOURCE_ENDPOINTS - Admin-only →
_ADMIN_ONLY_ENDPOINTS - POST/PUT/DELETE →
_VIEWER_BLOCKED_WRITE_OPERATIONS - Path format: use
fake-id-{}for path params,test-tagfor tag/name params (these are normalized by_ensure_endpoint_coverage_is_exhaustive)
3. make lint-python — fix any lint errors before committing
| Reference | When |
|---|---|
references/endpoint-patterns.md | Adding or modifying an endpoint |
references/openapi-codegen.md | Regenerating schema or client types |
references/testing-patterns.md | Writing integration tests |
Endpoint Patterns
Keywords per RFC 2119 / RFC 8174.
Design Rules
- JSON by default. Alternative formats (csv, jsonl) via URL only.
- Versioned under
/v1/. Breaking changes MUST go under a new prefix. - HTTP methods per RFC 9110: GET=read, POST=create, PUT=replace, PATCH=partial update, DELETE=remove.
- Status codes per RFC 9110 §15. 2xx=success, 4xx=client error, 5xx=server error. MUST NOT mix.
- Plural noun paths:
/datasets/:dataset_id/examples. No verbs. - Identifiers MAY be a GraphQL GlobalID or a natural key (e.g. name). SHOULD accept both when multiple exist.
- Query params for filtering/sorting/pagination. snake_case names.
- Cursor-based pagination only. Response:
{"data": [...], "next_cursor": "..."}. - All responses wrap payload in
"data"key. snake_case field names.
Implementation
Code lives in src/phoenix/server/api/routers/v1/. See users.py for a complete example.
Models — extend V1RoutesBaseModel. Wrap with ResponseBody[T], PaginatedResponseBody[T], or RequestBody[T]. Use UNDEFINED from phoenix.db.types.db_helper_types for excludable optional fields. Use Annotated[Union[...], Field(..., discriminator="field")] for unions.
Route decorator — always include: operation_id (camelCase), response_model_by_alias=True, response_model_exclude_unset=True, response_model_exclude_defaults=True.
Registration — import router in __init__.py, call router.include_router(...) inside create_v1_router().
Auth — admin-only: dependencies=[Depends(require_admin)]. Auth-aware: check request.app.state.authentication_enabled then isinstance(request.user, PhoenixUser). Read-only and viewer restrictions are automatic at the router level.
`is_not_locked` — guards insert/update operations under storage pressure (returns 507). Only apply to endpoints that write data (POST, PUT, PATCH). Do NOT apply to DELETE endpoints — they free space rather than consume it.
DB — async with request.app.state.db() as session: with joinedload for relationships.
IDs — GlobalID("Type", str(db_id)) to create, from_global_id_with_expected_type(GlobalID.from_id(input), "Type") to parse.
OpenAPI & Codegen
Run make openapi after any endpoint change. Generates:
schemas/openapi.jsonpackages/phoenix-client/src/phoenix/client/__generated__/v1/__init__.py(Python TypedDict)js/packages/phoenix-client/src/__generated__/api/v1.ts(TypeScript, phoenix-client)app/src/api/__generated__/v1.ts(TypeScript, frontend)
Commit all four with your endpoint changes. CI fails on drift if any of them is stale.
CI runs openapi-diff on PRs modifying the schema. Incompatible = removed endpoints/fields, changed types, renamed operationIds. Compatible = new endpoints, new optional fields, new schemas/enum values.
Testing
Unit vs Integration
- Unit tests (
tests/unit/): Pydantic validation, OpenAPI schema assertions, pure logic. These run in-process withauthentication_enabled=False. - Integration tests (
tests/integration/): CRUD, auth, encryption roundtrips, cross-API verification. These spawn a real Phoenix subprocess with auth enabled.
If a test hits an HTTP endpoint to create/read/update/delete data, it belongs in integration.
Integration Test Pattern
Tests live in tests/integration/<feature>/ packages. See tests/integration/secrets/ or tests/integration/client/ for examples. Each package has a conftest.py with package-scoped _env and _app fixtures.
Key helpers from tests/integration/_helpers.py:
_httpx_client(app, auth)— HTTP client._Userobjects auto-login._gql(app, auth, query=, variables=)— GraphQL requests._get_user(app, role)— create users with_ADMIN,_MEMBER,_VIEWERroles.
Use token_hex(4) in keys/names for test isolation since the server is shared. Clean up in try/finally.
What to Cover
- CRUD through the HTTP stack
- E2E data verification — prefer writing via one API and reading back via another over asserting on raw DB state
- Authorization — admin access, non-admin rejection, unauthenticated rejection
- Validation — invalid inputs return 422
Every endpoint should be added to _COMMON_RESOURCE_ENDPOINTS, _ADMIN_ONLY_ENDPOINTS, or _VIEWER_BLOCKED_WRITE_OPERATIONS in tests/integration/_helpers.py.
Path normalization: The _ensure_endpoint_coverage_is_exhaustive() function normalizes paths to match against the router. Use fake-id-{} for ID path params and test-tag for non-ID path params like tag names. These get normalized to {id} for comparison. Using other placeholder values (e.g. fake-tag) will cause a mismatch.
Related skills
FAQ
What must run before committing an endpoint change?
Run make openapi to regenerate the schema and client types, add the endpoint to the correct test coverage list, then run make lint-python and fix any errors.
Which test list does a new GET endpoint go in?
A GET endpoint goes in _COMMON_RESOURCE_ENDPOINTS, admin-only in _ADMIN_ONLY_ENDPOINTS, and write operations in _VIEWER_BLOCKED_WRITE_OPERATIONS.