refactor(backend): move the API-key routes into their own feature module - #14456
refactor(backend): move the API-key routes into their own feature module#14456Pwuts wants to merge 2 commits into
Conversation
…n feature module v1.py is the 3,016-line residue of the pre-feature-module API layout. Its own banner comments already mark eight sections; this moves the last of them — the six /api/api-keys routes and the three request/response models they own — into backend/api/features/api_keys/, alongside the other feature packages. The published API is unchanged: the exported OpenAPI schema is byte-identical before and after, and every one of the app's 357 operations still resolves to the same handler. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (8)
💤 Files with no reviewable changes (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review. 📜 Recent review details🧰 Additional context used📓 Path-based instructions (1)Format Python code with `poetry run format`📄 CodeRabbit inference engine (AGENTS.md) Files:
🔇 Additional comments (5)
WalkthroughChangesAPI key route extraction
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to API-key management endpoints are reorganized into a dedicated module while preserving their published paths, authentication behavior, schemas, and client contract. No merge-blocking production impact is identified. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 EvidenceThe scripts below live outside the repo ( 1. OpenAPI schema: byte-identicalAnd through the real pre-commit path, against the committed spec: 2. Route resolution: all 357 operations, before vs afterFor each The complete diff: - "DELETE /api/api-keys/{key_id}": "backend.api.features.v1.delete_api_key",
+ "DELETE /api/api-keys/{key_id}": "backend.api.features.api_keys.routes.delete_api_key",
- "GET /api/api-keys": "backend.api.features.v1.get_api_keys",
+ "GET /api/api-keys": "backend.api.features.api_keys.routes.get_api_keys",
- "GET /api/api-keys/{key_id}": "backend.api.features.v1.get_api_key",
+ "GET /api/api-keys/{key_id}": "backend.api.features.api_keys.routes.get_api_key",
- "POST /api/api-keys": "backend.api.features.v1.create_api_key",
+ "POST /api/api-keys": "backend.api.features.api_keys.routes.create_api_key",
- "POST /api/api-keys/{key_id}/suspend": "backend.api.features.v1.suspend_key",
+ "POST /api/api-keys/{key_id}/suspend": "backend.api.features.api_keys.routes.suspend_key",
- "PUT /api/api-keys/{key_id}/permissions": "backend.api.features.v1.update_permissions",
+ "PUT /api/api-keys/{key_id}/permissions": "backend.api.features.api_keys.routes.update_permissions",Nothing else changed handler, so nothing shadows or is shadowed by the moved set. Registration order is byte-identical too ( On shadowing specifically: the only paths under 3. Route table, per routeDumped - "endpoint": "backend.api.features.v1.delete_api_key",
+ "endpoint": "backend.api.features.api_keys.routes.delete_api_key",
- "endpoint": "backend.api.features.v1.get_api_keys",
+ "endpoint": "backend.api.features.api_keys.routes.get_api_keys",
- "endpoint": "backend.api.features.v1.get_api_key",
+ "endpoint": "backend.api.features.api_keys.routes.get_api_key",
- "endpoint": "backend.api.features.v1.create_api_key",
+ "endpoint": "backend.api.features.api_keys.routes.create_api_key",
- "response_model": "<class 'backend.api.model.CreateAPIKeyResponse'>",
+ "response_model": "<class 'backend.api.features.api_keys.model.CreateAPIKeyResponse'>",
- "endpoint": "backend.api.features.v1.suspend_key",
+ "endpoint": "backend.api.features.api_keys.routes.suspend_key",
- "endpoint": "backend.api.features.v1.update_permissions",
+ "endpoint": "backend.api.features.api_keys.routes.update_permissions",
4. The new test can fail
The first is the one worth having: 5. Test runs
The two non-passes in the
6. Reference sweepGreps across
The one real reference was |
…sence backend/AGENTS.md bans getattr-based type dispatch; APIRoute is what the assertion means, and it gives the type checker the narrowing for .endpoint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #14456 +/- ##
========================================
Coverage 81.48% 81.49%
========================================
Files 3553 3556 +3
Lines 265706 265731 +25
Branches 24618 24618
========================================
+ Hits 216514 216555 +41
+ Misses 43830 43727 -103
- Partials 5362 5449 +87
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Moves the six
/api/api-keysroutes out ofbackend/api/features/v1.pyinto their own feature module,backend/api/features/api_keys/, with no change to the published API.Why / What / How
Why.
v1.pyis a 3,022-line router module (2,902 after this PR) — the residue of the API layout that predates feature modules. Every one of its neighbours inbackend/api/features/(library/,store/,orgs/,search/,chat/, …) is already a package with its own routes module and router;v1.pyis the part that was never split. It has eight distinct reasons to change, and the API-key routes are one of them.What. The API KEY section —
create_api_key,get_api_keys,get_api_key,delete_api_key,suspend_key,update_permissions— moves tobackend/api/features/api_keys/routes.py. The three models it owns (CreateAPIKeyRequest,CreateAPIKeyResponse,UpdatePermissionsRequest) move from the sharedbackend/api/model.pytobackend/api/features/api_keys/model.py; nothing else referenced them, and theirAPIKeyInfo/APIKeyPermissionimport goes with them.How. The new router is mounted at
prefix="/api/api-keys"withtags=["v1", "api-keys"], which is exactly the tag list the routes had before (mount-level["v1"]plus route-level["api-keys"]). That matters:custom_generate_unique_idbuilds eachoperationIdfrom the first tag and the route summary, so both are load-bearing on the generated frontend client. The per-routedependencies=[Security(requires_user)]— identical on all six — is hoisted to the router; the dependency tree that FastAPI builds is unchanged, which the route-table diff below confirms.The route docstrings stay, because FastAPI publishes them as each operation's
description.Changes 🏗️
backend/api/features/api_keys/package:routes.py(6 routes),model.py(3 models),routes_test.py.backend/api/features/v1.py: −120 lines (the section plus its now-unused imports).backend/api/model.py: −16 lines (the three models and their import).backend/api/rest_api.py: +6 (import and mount).backend/api/features/orgs/regression_test.py:test_create_api_key_sets_org_contextreads the route's source withinspect.getsource, so its import moves to the new module. This was the only reference to a moved symbol anywhere in the repo.Verified
The exported OpenAPI schema is byte-identical before and after —
json.dumps(before, sort_keys=True) == json.dumps(after, sort_keys=True)isTrue, and the committedfrontend/src/app/api/openapi.jsonhas an empty diff after running theexport-api-schemahook.pnpm generate:apithen produces no change to the generated client, andtsc --noEmitpasses.All 357 operations still resolve to the same handler. I dumped, for every path+method in the spec, which route Starlette's first-match-wins matcher actually picks, before and after. The only differences are the six API-key operations' module paths (
backend.api.features.v1.*→backend.api.features.api_keys.routes.*). Nothing else moved, and nothing became unresolvable — so no route shadows or is shadowed by the moved set. Registration order is also unchanged, because the API-key routes were last inv1_routerand the new mount immediately follows it; the spec's four/api/api-keys*paths are the only ones that could collide, and there is no/api/{param}route anywhere.Per-route, the app's route table is identical apart from those module names: tags,
operationId,unique_id, summary, description, status code, response class, route dependencies and the full flattened dependency tree all match.The new
routes_test.pypins that surface for the seven splits still to come. I checked it can fail, with three mutations: renaming one summary (1 failed), hiding one route from the schema (2 failed), and changing the mount prefix to/api/apikeys(11 failed). All reverted, baseline green again.Executed:
backend/apiin full (2333 passed),backend/util/architecture_test.py(3 passed),backend/blocks/test/test_block.py(1647 passed, 84 skipped),backend/api/features/orgs/regression_test.py(95 passed, 12 xfailed),backend/api/utils/api_key_auth_test.py+ the two onboarding tests that importv1_router(50 passed). Two failures in thebackend/apirun are pre-existing and not from this change:ws_api_test.py::test_health_endpoint_returns_okpasses when run alone (suite interference), andsearch/content_handlers_integration_test.py::test_ensure_content_embedding_blocksfails identically on cleandevat4ac3646361with this commit absent. Not executed: anything outsidebackend/api,backend/utilandbackend/blocks.Full evidence in a comment below.
Next in the sequence
Bottom-up through
v1.py's own banner comments, so each PR is small and the API-surface check above is the acceptance test each time. Next is COPILOT SKILLS (4 routes + 3 models), then Schedules (5 routes + 1 model), then Graphs, Credits, Blocks, Onboarding, Auth. Bottom-up because the sections at the bottom are the smallest and the least entangled — Graphs, in the middle, is the onerest_api.pystill imports five symbols from directly, so it wants the pattern to be settled first.Agents and large language models used
Claude Code with Claude Opus 5
Checklist 📋
For code changes:
pnpm generate:api) — no diff — and rantsc --noEmitbackend/api,architecture_test.py,test_block.py, and the org regression suite🤖 Generated with Claude Code