So I have a custom middleware like this:
Its objective is to add some meta_data fields to every response from all endpoints of my FastAPI app.
@app.middelware("http")
async def add_metadata_to_response_payload(request: Request, call_next):
response = await call_next(request)
body = b""
async for chunk in response.body_iterator:
body+=chunk
data = {}
data["data"] = json.loads(body.decode())
data["metadata"] = {
"some_data_key_1": "some_data_value_1",
"some_data_key_2": "some_data_value_2",
"some_data_key_3": "some_data_value_3"
}
body = json.dumps(data, indent=2, default=str).encode("utf-8")
return Response(
content=body,
status_code=response.status_code,
media_type=response.media_type
)
However, when I served my app using uvicorn, and launched the swagger URL, here is what I see:
Unable to render this definition
The provided definition does not specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported version fields are
Swagger: "2.0" and those that match openapi: 3.0.n (for example, openapi: 3.0.0)
With a lot of debugging, I found that this error was due to the custom middleware and specifically this line:
body = json.dumps(data, indent=2, default=str).encode("utf-8")
If I simply comment out this line, swagger renders just fine for me. However, I need this line for passing the content argument in Response from Middleware. How to sort this out?
UPDATE:
I tried the following:
body = json.dumps(data, indent=2).encode("utf-8")
by removing default arg, the swagger did successfully load. But now when I hit any of the APIs, here is what swagger tells me along with response payload on screen:
Unrecognised response type; displaying content as text
More Updates (6th April 2022):
Got a solution to fix 1 part of the problem by Chris, but the swagger wasn't still loading. The code was hung up in the middleware level indefinitely and the page was not still loading.
So, I found in all these places:
- https://github.com/encode/starlette/issues/919
- Blocked code while using middleware and dependency injections to log requests in FastAPI(Python)
- https://github.com/tiangolo/fastapi/issues/394
that this way of adding custom middleware works by inheriting from BaseHTTPMiddleware in Starlette and has its own issues (something to do with awaiting inside middleware, streamingresponse and normal response, and the way it is called). I don't understand it yet.
if request.url.path in ['/docs', '/redoc', 'openapi.json']: return response
– Muniments