component_framework.adapters.fastapi

FastAPI adapter for component endpoints.

 1"""FastAPI adapter for component endpoints."""
 2
 3import logging
 4
 5try:
 6    from fastapi import HTTPException, Request
 7    from fastapi.responses import JSONResponse
 8except ImportError as e:
 9    from . import _require_extra
10
11    raise _require_extra("fastapi", "fastapi") from e
12
13from ..core import StateSerializer, registry
14
15logger = logging.getLogger(__name__)
16
17
18async def component_endpoint(name: str, request: Request) -> JSONResponse:
19    """
20    Generic component endpoint for FastAPI.
21
22    POST /components/{name}
23    Body: {
24        "event": "event_name",
25        "payload": {...},
26        "state": "serialized_state"
27    }
28
29    Returns: {
30        "html": "rendered_html",
31        "state": "serialized_state",
32        "component_id": "component-id"
33    }
34    """
35    try:
36        # Get component class
37        component_cls = registry.get(name)
38        if not component_cls:
39            raise HTTPException(status_code=404, detail=f"Component '{name}' not found")
40
41        # Parse request data
42        try:
43            data = await request.json()
44        except Exception as e:
45            raise HTTPException(status_code=400, detail=f"Invalid JSON: {e}")
46
47        # Extract parameters
48        params = data.get("params", {})
49        event = data.get("event")
50        payload = data.get("payload", {})
51        state_str = data.get("state")
52
53        # Deserialize state if provided
54        state = None
55        if state_str:
56            try:
57                state = StateSerializer.deserialize(state_str)
58            except Exception as e:
59                raise HTTPException(status_code=400, detail=f"Invalid state: {e}")
60
61        # Create and dispatch component
62        component = component_cls(**params)
63        result = component.dispatch(event=event, payload=payload, state=state)
64
65        # Serialize state for response
66        result["state"] = StateSerializer.serialize(result["state"])
67
68        return JSONResponse(content=result)
69
70    except HTTPException:
71        raise
72    except Exception:
73        logger.exception(f"Error processing component '{name}'")
74        raise HTTPException(status_code=500, detail="Internal server error")
75
76
77def create_component_routes(app):
78    """
79    Add component endpoint to FastAPI app.
80
81    Usage:
82        from fastapi import FastAPI
83        app = FastAPI()
84        create_component_routes(app)
85    """
86    app.add_api_route(
87        "/components/{name}",
88        component_endpoint,
89        methods=["POST"],
90        name="component_endpoint",
91    )
logger = <Logger component_framework.adapters.fastapi (WARNING)>
async def component_endpoint( name: str, request: starlette.requests.Request) -> starlette.responses.JSONResponse:
19async def component_endpoint(name: str, request: Request) -> JSONResponse:
20    """
21    Generic component endpoint for FastAPI.
22
23    POST /components/{name}
24    Body: {
25        "event": "event_name",
26        "payload": {...},
27        "state": "serialized_state"
28    }
29
30    Returns: {
31        "html": "rendered_html",
32        "state": "serialized_state",
33        "component_id": "component-id"
34    }
35    """
36    try:
37        # Get component class
38        component_cls = registry.get(name)
39        if not component_cls:
40            raise HTTPException(status_code=404, detail=f"Component '{name}' not found")
41
42        # Parse request data
43        try:
44            data = await request.json()
45        except Exception as e:
46            raise HTTPException(status_code=400, detail=f"Invalid JSON: {e}")
47
48        # Extract parameters
49        params = data.get("params", {})
50        event = data.get("event")
51        payload = data.get("payload", {})
52        state_str = data.get("state")
53
54        # Deserialize state if provided
55        state = None
56        if state_str:
57            try:
58                state = StateSerializer.deserialize(state_str)
59            except Exception as e:
60                raise HTTPException(status_code=400, detail=f"Invalid state: {e}")
61
62        # Create and dispatch component
63        component = component_cls(**params)
64        result = component.dispatch(event=event, payload=payload, state=state)
65
66        # Serialize state for response
67        result["state"] = StateSerializer.serialize(result["state"])
68
69        return JSONResponse(content=result)
70
71    except HTTPException:
72        raise
73    except Exception:
74        logger.exception(f"Error processing component '{name}'")
75        raise HTTPException(status_code=500, detail="Internal server error")

Generic component endpoint for FastAPI.

POST /components/{name} Body: { "event": "event_name", "payload": {...}, "state": "serialized_state" }

Returns: { "html": "rendered_html", "state": "serialized_state", "component_id": "component-id" }

def create_component_routes(app):
78def create_component_routes(app):
79    """
80    Add component endpoint to FastAPI app.
81
82    Usage:
83        from fastapi import FastAPI
84        app = FastAPI()
85        create_component_routes(app)
86    """
87    app.add_api_route(
88        "/components/{name}",
89        component_endpoint,
90        methods=["POST"],
91        name="component_endpoint",
92    )

Add component endpoint to FastAPI app.

Usage:

from fastapi import FastAPI app = FastAPI() create_component_routes(app)