Skip to content

Request and WebSocket Context in Services

Inject fastapi.Request or fastapi.WebSocket into scoped services when your service logic needs connection context.

Enable Request/WebSocket Context Injection

Include the FastAPI integration module in container injectables:

import wireup
import wireup.integration.fastapi

container = wireup.create_async_container(
    injectables=[services, wireup.integration.fastapi],
)

Inject fastapi.Request

import fastapi
from wireup import injectable


@injectable(lifetime="scoped")
class HttpAuthenticationService:
    def __init__(self, request: fastapi.Request) -> None:
        self.request = request

    def current_user_id(self) -> str:
        return self.request.headers["x-user-id"]

Inject fastapi.WebSocket

import fastapi
from wireup import injectable


@injectable(lifetime="scoped")
class WebSocketSessionService:
    def __init__(self, websocket: fastapi.WebSocket) -> None:
        self.websocket = websocket

    async def send_welcome(self) -> None:
        await self.websocket.send_text("connected")

FastAPI Security and OAuth Scopes

Keep OAuth, Security(...), and OpenAPI scope declarations in FastAPI's security system. After the security dependency resolves the authenticated user, store the value on request.state; scoped Wireup services can then read it through the injected fastapi.Request.

from typing import Annotated, NewType

from fastapi import Request, Security
from fastapi.security import OAuth2PasswordBearer, SecurityScopes
from wireup import Injected, injectable

oauth2_scheme = OAuth2PasswordBearer(
    tokenUrl="token",
    scopes={"profile": "Read the current user's profile"},
)

CurrentUserId = NewType("CurrentUserId", str)


async def load_current_user(
    request: Request,
    security_scopes: SecurityScopes,
    token: Annotated[str, Security(oauth2_scheme)],
) -> None:
    user_id = await verify_token(token, security_scopes.scopes)
    request.state.current_user_id = user_id


@injectable(lifetime="scoped")
def current_user_id_factory(request: Request) -> CurrentUserId:
    return CurrentUserId(request.state.current_user_id)


@app.get("/me", dependencies=[Security(load_current_user, scopes=["profile"])])
async def me(user_id: Injected[CurrentUserId]):
    return {"user_id": user_id}

This keeps FastAPI responsible for security dependencies and generated OpenAPI documentation, while Wireup remains responsible for service wiring after the request context has been established.