Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .claude/docs/architectural_patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Request → Middleware → APIRouter → Endpoint function → Service layer →

### Endpoint modules: single file or package

A module under `sparkth/api/v1/` takes one of two shapes. `sparkth/api/v1/api.py` mounts
A module under `sparkth/api/v1/` takes one of two shapes. `sparkth/api/v1/__init__.py` mounts
each one the same way — `include_router(<module>.router, prefix=...)` — so the shape is
an internal organisation choice and changing it never moves a URL.

Expand All @@ -103,9 +103,9 @@ sparkth/api/v1/<name>/
schemas.py # request/response models owned by this module
```

- `__init__.py` re-exports `router` and carries `__all__ = ["router"]`. This is a
deliberate exception to the "avoid re-exports" rule: it keeps `api.py`'s mounting
uniform across both shapes.
- The endpoint package's own `__init__.py` re-exports `router` and carries
`__all__ = ["router"]`. This is a deliberate exception to the "avoid re-exports" rule:
it keeps the mounting in `sparkth/api/v1/__init__.py` uniform across both shapes.
- It is also where `register_exception_handler(ExcClass, status_code)` calls live, so a
domain's exception → status mapping sits beside the routes that raise it (see section
8, and `permissions/__init__.py` / `whitelist/__init__.py`). A package with no domain
Expand All @@ -118,9 +118,9 @@ sparkth/api/v1/<name>/
into a package makes every other domain import that package, and importing any module
from it executes its `__init__.py` and therefore its `routes.py`, which turns a later
import in the other direction into a circular one.
- Route paths come from the prefix in `api.py`, never from the package name, so
converting a file to a package is a pure refactor: the OpenAPI document, the generated
frontend client, and every URL stay byte-identical.
- Route paths come from the prefix in `sparkth/api/v1/__init__.py`, never from the package
name, so converting a file to a package is a pure refactor: the OpenAPI document, the
generated frontend client, and every URL stay byte-identical.

---

Expand Down
28 changes: 28 additions & 0 deletions sparkth/api/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Version 1 of the REST API.

Assembles ``api_router`` from every endpoint module in this package. Each module
exposes a ``router`` — whether it is a single file (``auth.py``) or a package with
its own ``routes.py`` and ``schemas.py`` (``user/``) — and is mounted here under
its URL prefix and OpenAPI tag. ``sparkth.main.assemble_app`` mounts the result at
``/api/v1``, so every path in this file is relative to that.

Prefixes are the public URL contract: changing one here moves an endpoint for every
client, independently of how the module behind it is laid out on disk.
"""

from fastapi import APIRouter

from sparkth.api.v1 import analytics, auth, file_parser, language, llm, permissions, user, user_plugins, whitelist

api_router = APIRouter()
api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
api_router.include_router(user.router, prefix="/user", tags=["user"])
api_router.include_router(language.router, prefix="/languages", tags=["Languages"])
api_router.include_router(user_plugins.router, prefix="/user-plugins", tags=["User Plugins"])
api_router.include_router(file_parser.router, prefix="/parser", tags=["File Parser"])
api_router.include_router(whitelist.router, prefix="/whitelist", tags=["Whitelist"])
api_router.include_router(llm.router, prefix="/llm", tags=["LLM Configuration"])
api_router.include_router(permissions.router, prefix="/permissions", tags=["Permissions"])
api_router.include_router(analytics.router, prefix="/analytics", tags=["Analytics"])

__all__ = ["api_router"]
14 changes: 0 additions & 14 deletions sparkth/api/v1/api.py

This file was deleted.

2 changes: 1 addition & 1 deletion sparkth/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from starlette.types import Lifespan

import sparkth.lib.audit.callbacks # noqa: F401 # registers the process-global LangChain audit callback on import
from sparkth.api.v1.api import api_router
from sparkth.api.v1 import api_router
from sparkth.core.audit.middleware import AuditContextMiddleware
from sparkth.core.config import MCP_MOUNT_PATH, get_settings
from sparkth.core.exceptions.handlers import EXCEPTION_HANDLERS
Expand Down
Loading