from fastapi import FastAPI, Request, Response from starlette.middleware.base import BaseHTTPMiddleware from starlette.types import ASGIApp class TextPlainMiddleware(BaseHTTPMiddleware): def __init__(self, app: ASGIApp): super().__init__(app) async def dispatch(self, request: Request, call_next): # Check if content type is text/* content_type = request.headers.get("content-type", "") if content_type and content_type.startswith("text/"): # Store the original receive method original_receive = request._receive # Create a modified receive that will store the body body = b"" async def receive(): nonlocal body message = await original_receive() if message["type"] == "http.request": body += message.get("body", b"") # Update body to be empty so it won't be processed by other middleware # message["body"] = b"" return message # Replace the receive method request._receive = receive # Process the request response = await call_next(request) # After the response is generated, we can access the full body # and attach it to the request state for the route to access request.state.text_body = body.decode("utf-8") return response else: # For other content types, proceed as normal return await call_next(request)