loom.rest.compiler

RestInterface compiler.

Validates and compiles RestInterface declarations into CompiledRoute records at startup. No reflection or validation occurs after compilation.

Compilation steps per interface:

  1. Validate structural constraints (prefix, routes non-empty if auto=False).

  2. For each RestRoute: - Verify use_case has a compiled ExecutionPlan. - Resolve effective pagination mode (route → interface → global). - Resolve effective profile policy (route → interface → global).

  3. Detect and resolve (method, path) conflicts: custom routes win over duplicates. Raise InterfaceCompilationError on ambiguous conflicts within the same routes tuple.

  4. Validate expose_profile requires a non-empty allowed_profiles.

Functions

_apply_disablement(routes, disabled)

Drop every Python-declared route named by disabled.

_collision_message(key, existing, ...)

Build a collision error, advising to disable-and-redeclare only when it applies.

_format_candidates(routes)

Render the (method, full_path) of every routes entry, capped.

Classes

CompiledRoute(interface_name, route, ...[, ...])

Fully resolved route ready for transport binding.

RestInterfaceCompiler(use_case_compiler[, ...])

Compiles RestInterface declarations into CompiledRoute records.

RouteSources([python, config, disabled])

Everything that decides which routes mount, and from which origin.

_RouteOrigin(value)

Which pillar declared a route — the label a collision error names.

_SeenRoute(origin, label)

A previously compiled route, tracked for collision detection.

Exceptions

InterfaceCompilationError

Raised when a RestInterface fails structural validation at startup.

class loom.rest.compiler.RouteSources(python=(), config=(), disabled=())[source]

Bases: object

Everything that decides which routes mount, and from which origin.

Groups the three inputs RestInterfaceCompiler.compile_sources() and create_fastapi_app() need — the Python interfaces, the config-declared ones, and the routes disabled between them — into the one value both call sites pass along together.

Parameters:
exception loom.rest.compiler.InterfaceCompilationError[source]

Bases: Exception

Raised when a RestInterface fails structural validation at startup.

Parameters:

message – Human-readable description of the compilation failure.

Example:

raise InterfaceCompilationError(
    "UserRestInterface: duplicate route (GET, /{user_id})"
)
class loom.rest.compiler.CompiledRoute(interface_name, route, full_path, effective_pagination_mode, effective_profile_default, effective_allowed_profiles, effective_expose_profile, effective_allow_pagination_override, read_only=False, interface_tags=(), execute_param_types=(), effective_requires_roles=(), effective_max_limit=1000)[source]

Bases: object

Fully resolved route ready for transport binding.

Produced by RestInterfaceCompiler for each valid route declaration. All policy fields are resolved — no further lookup is needed at request time.

Parameters:
  • interface_name (str) – Qualified name of the originating RestInterface.

  • route (RestRoute) – Original RestRoute declaration.

  • full_path (str) – Absolute HTTP path (interface.prefix + route.path).

  • effective_pagination_mode (PaginationMode) – Resolved pagination strategy after applying route → interface → global precedence.

  • effective_profile_default (str) – Resolved default profile name.

  • effective_allowed_profiles (tuple[str, ...]) – Resolved set of allowed profiles.

  • effective_expose_profile (bool) – Whether ?profile=... is publicly accepted for this route.

  • effective_allow_pagination_override (bool) – Whether callers may override pagination mode via query parameters for this route.

  • effective_requires_roles (tuple[str, ...]) – Resolved roles granting access to this route, after applying route → interface precedence. Empty means the route declares no role requirement.

  • effective_max_limit (int) – Ceiling applied to the ?limit= query parameter of this route.

  • read_only (bool) – True for GET routes — instructs the executor to skip the UnitOfWork transaction for this request.

  • interface_tags (tuple[str, ...]) – OpenAPI tags inherited from the parent RestInterface.

  • execute_param_types (tuple[tuple[str, Any], ...])

class loom.rest.compiler.RestInterfaceCompiler(use_case_compiler, defaults=None, metrics=None)[source]

Bases: object

Compiles RestInterface declarations into CompiledRoute records.

Validates structure, resolves policies, and caches the result. Designed to run once at startup, driven by bootstrap_app() or the FastAPI composition root.

Parameters:
  • use_case_compiler (UseCaseCompiler) – Compiler that holds the cached ExecutionPlan registry.

  • defaults (RestApiDefaults | None) – Global REST API defaults applied when interface/route level is unset. Defaults to RestApiDefaults with offset pagination.

  • metrics (MetricsAdapter | None) – Optional metrics adapter. Reserved for future use (HTTP metrics are emitted at request time by the router runtime).

Example:

compiler = RestInterfaceCompiler(use_case_compiler)
routes = compiler.compile(UserRestInterface)
compile(interface)[source]

Compile interface and return the list of CompiledRoute.

Compilation is idempotent: repeated calls with the same class return the cached result.

Parameters:

interface (type[RestInterface[Any]]) – RestInterface subclass to compile.

Returns:

Ordered list of compiled routes ready for transport binding.

Raises:

InterfaceCompilationError – If the interface fails validation.

Return type:

list[CompiledRoute]

compile_sources(sources)[source]

Compile interfaces from both origins into one deterministic route set.

Python-declared interfaces compile first. sources.disabled is then applied to that Python-only set — see _apply_disablement() for why it never targets config-declared routes. Only after disablement do app.rest.interfaces entries compile and join the result. A (method, path) collision between what remains aborts naming both origins involved — order only decides which origin the message names first, it grants neither side precedence.

This sequencing is what makes overriding a route per environment possible: disabling a Python route removes it, and only then does the collision check run, so the config redeclaration mounts cleanly instead of colliding with a route that would otherwise still be considered occupied.

Parameters:

sources (RouteSources) – Interfaces to compile, grouped by origin, plus the Python routes to drop before the merge.

Returns:

Compiled routes, Python-declared ones first (minus any disabled), followed by the config-declared ones.

Raises:

InterfaceCompilationError – On a same- or cross-origin collision, or a disabled entry matching no Python-declared route.

Return type:

list[CompiledRoute]