I discovered recently that I could create a custom response class for use with FastAPI and that I could use this to create a pretty printed json-like reponse for my API. I didn’t want to force all my responses to go through this custom class though, just when a specific response_format=pretty
parameter was selected. I therefore spent quite a bit of time trying to find a way to add a conditional response class. Turns out it was pretty simple to do what I wanted.
The custom response class shown here was shamefully nicked from @dmontagu
import json
from typing import Any
from starlette.responses import Response
class PrettyJSONResponse(Response):
media_type = "application/json"
def render(self, content: Any) -> bytes:
return json.dumps(
content,
ensure_ascii=False,
allow_nan=False,
indent=4,
separators=(", ", ": "),
).encode("utf-8")
@dmontagu in the above link is then showing it used like:
@app.get("/", response_class=PrettyJSONResponse)
def get_some_json():
But that forces everything to be output using the PrettyJsonResponse instruction.
I already have a response_format
parameter that accepts ‘json’ and ‘csv’ and would like to add ‘prettyprint’ as an option.
Here’s how I achieved that and implemented a ‘conditional response class’:
import json
from enum import Enum
from pydantic import BaseModel, Field
from typing import Any, List
from starlette.responses import Response
class PrettyJSONResponse(Response):
media_type = "application/json"
def render(self, content: Any) -> bytes:
return json.dumps(
content,
ensure_ascii=False,
allow_nan=False,
indent=4,
separators=(", ", ": "),
).encode("utf-8")
# Enum for restricting parameter values
class Format(str, Enum):
json = 'json'
csv = 'csv'
prettyprint = 'prettyprint'
# Response model for Events
class Event(BaseModel):
event_id: str
name: str
place: List[str] = []
organisation: List[str] = []
@app.get("/event/{event_id}", response_model=Event, tags=["unique_id"])
def get_stuff(event_id: str = Path(..., title="The unique id of the event"),
response_format: Format = 'json'):
elastic_index = 'events'
result = EMGet(client=es_client,
index=elastic_index,
doc_id=event_id)
event = result['_source']
if response_format == 'prettyprint':
return PrettyJSONResponse(event)
elif response_format == 'csv':
....
else:
return event
/event/event_1
would give me the standard json output from fastapi while, /event/event_1?response_format=prettyprint
would return the data with indentation and formatting that makes the output easy to read even without the use of parsing tools such as chrome extensions and the like.
Comments