Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Principle:Neuml Txtai API Server Bootstrap

From Leeroopedia
Revision as of 18:20, 16 February 2026 by Admin (talk | contribs) (Auto-imported from principles/Neuml_Txtai_API_Server_Bootstrap.md)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)


Overview

txtai bootstraps its REST API through a FastAPI application with dynamic route registration and ASGI lifecycle management. The bootstrap process reads environment variables to determine configuration, security settings, and custom extensions, then dynamically discovers and registers only the API routes that correspond to configured components. This ensures that the API surface precisely matches the application's capabilities.

Theoretical Foundation

ASGI Application Lifecycle

txtai's API is built on ASGI (Asynchronous Server Gateway Interface), the standard for Python async web applications. The ASGI lifecycle defines two critical phases:

  • Startup: occurs once when the server process starts, before any requests are served
  • Shutdown: occurs once when the server process is terminating

txtai uses FastAPI's lifespan context manager to handle these phases. During startup, the application:

  1. Reads YAML configuration from the path specified by the CONFIG environment variable
  2. Instantiates the API class (which extends Application) with the parsed configuration
  3. Discovers available routers and registers only those matching configured components
  4. Executes any registered extensions

The lifespan pattern (using Python's yield) ensures that startup logic completes before any requests are processed, and provides a clean shutdown hook.

# Conceptual lifespan pattern
def lifespan(app):
    # Startup: initialize everything
    setup_application()
    yield
    # Shutdown: cleanup (implicit)

Dependency Injection

FastAPI's dependency injection system is central to txtai's API architecture. Dependencies are callables that FastAPI invokes before route handlers:

  • Application-level dependencies apply to every request (e.g., token authorization)
  • Route-level dependencies apply to specific endpoints

txtai registers security dependencies at the application level during the create() function, before the FastAPI instance is even returned. This means:

  • Security enforcement is guaranteed -- no endpoint can be accidentally left unprotected
  • The dependency chain is evaluated before any route handler code executes
  • Custom dependencies can be added via the DEPENDENCIES environment variable

Dynamic Route Registration

Rather than registering all possible endpoints at module import time, txtai uses dynamic route registration during the lifespan startup phase. The system:

  1. Introspects the txtai.api module to find all available APIRouter instances
  2. Checks each router's name against the YAML configuration keys
  3. Only includes routers whose corresponding component is configured

This design means:

  • An API with only embeddings configured will expose search endpoints but not pipeline-specific endpoints
  • Adding a new component to the YAML automatically exposes its API endpoints on the next restart
  • No unused endpoints are exposed, reducing the attack surface

Bootstrap Architecture

Environment Variables

The bootstrap process is controlled through environment variables:

Variable Purpose Example
CONFIG Path to YAML configuration file config.yml
TOKEN SHA-256 hash of auth token (enables auth) a1b2c3d4...
API_CLASS Custom API class (overrides default API) mymodule.CustomAPI
DEPENDENCIES Comma-separated custom dependency classes myauth.OAuth2,myrate.Limiter
EXTENSIONS Comma-separated extension classes myext.CustomRoutes

Module-Level Initialization

The FastAPI application and global API instance are created at module level:

app, INSTANCE = create(), None
  • app is the FastAPI instance, created immediately when the module is imported
  • INSTANCE is the txtai API instance, initialized to None and populated during the lifespan startup

This two-phase initialization is critical: the FastAPI app must exist before the ASGI server (e.g., uvicorn) can bind to it, but the heavyweight model loading happens lazily during the lifespan event.

Router Discovery

The apirouters() function uses Python's inspect module to discover all available routers:

  1. It gets a reference to the txtai.api package
  2. It iterates over all submodules using inspect.getmembers
  3. For each submodule that has a router attribute of type APIRouter, it registers it by name

This reflection-based approach means new router modules added to the txtai.api package are automatically discoverable without modifying the bootstrap code.

Special Cases

The bootstrap logic handles two special routing cases:

  • Cluster without embeddings: If cluster is configured but embeddings is not, the embeddings router is still included because the cluster proxies search requests
  • Embeddings without similarity: If embeddings is configured but similarity is not, the similarity router is included because the embeddings index can compute similarity

Extension System

The EXTENSIONS environment variable allows injecting custom startup logic:

# Each extension is a callable that receives the FastAPI application
extension = APIFactory.get(extension_class)()
extension(application)

Extensions can:

  • Add custom routes that are not part of the standard txtai API
  • Register middleware (CORS, logging, metrics)
  • Modify application state

MCP Service

If the configuration includes mcp: true, txtai mounts a Model Context Protocol service, enabling LLM tools to discover and use the API programmatically:

if config.get("mcp"):
    mcp = FastApiMCP(application, http_client=AsyncClient(timeout=100))
    mcp.mount()

Design Rationale

Why Dynamic Registration

Static route registration (declaring all routes at import time) would:

  • Expose endpoints for unconfigured components, returning errors or null responses
  • Create a misleading API surface that suggests capabilities the instance does not have
  • Potentially trigger unnecessary module imports and model loading

Dynamic registration ensures the API is what it does -- the exposed endpoints precisely match the configured capabilities.

Why Module-Level App Creation

ASGI servers like uvicorn expect a module-level ASGI application object. By creating app at module level, txtai supports the standard invocation pattern:

uvicorn "txtai.api:app"

The actual initialization (model loading, index loading) is deferred to the lifespan handler, keeping module import fast.

See Also

Implemented By

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment