FastAPI Essentials

Course Content

FastAPI Essentials

1 sections · 32 lessons

What is UTF8JSONResponse?


What you need to know

Start with Python's default:

Python
import jsonanswer = "आपका रिफंड 5-7 दिनों में आएगा"          # "Your refund will arrive in 5-7 days"json.dumps({"answer": answer})                     # ensure_ascii=True by defaultjson.dumps({"answer": answer}, ensure_ascii=False)
Text
{"answer": "आपका रिफं ...148 bytes escaped vs 85 bytes raw UTF-8

Both are valid JSON, and any correct client decodes them to the same text. But the escaped version is unreadable in logs and, for Devanagari, about 75% larger. For an LLM app answering in Indian languages, that is more bandwidth and harder debugging.

Older projects fixed this with a custom class:

Python
import jsonfrom fastapi.responses import JSONResponseclass UTF8JSONResponse(JSONResponse):    def render(self, content) -> bytes:        return json.dumps(content, ensure_ascii=False, separators=(",", ":")).encode("utf-8")

Now check what current FastAPI actually sends, with no custom class:

Text
GET /plain  (returns a dict)         -> application/json {"answer":"आपका रिफंड 5-7 दिनों में आएगा"}  84 bytesGET /typed  (return type -> Reply)   -> application/json {"answer":"आपका रिफंड 5-7 दिनों में आएगा"}  84 bytes

Both are raw UTF-8 already. Starlette's JSONResponse uses ensure_ascii=False, and since FastAPI 0.130 routes with a return type or response_model are encoded directly by Pydantic, which also writes UTF-8.

What about ORJSONResponse?

ORJSONResponse and UJSONResponse used to be the advice for speed. Since FastAPI 0.131 they are deprecated, because declaring a return type now gives Pydantic's Rust encoder, which is fast without an extra library. If you see default_response_class=ORJSONResponse in a codebase, the modern fix is to declare response types and remove it.

A real-life example

A Hindi-and-English customer-support bot logs every response body for quality review. An older service in the stack used plain json.dumps for its responses, and reviewers saw walls of आप... in the log viewer. Someone added a UTF8JSONResponse class, copied from a blog post, to every service.

Months later, during an upgrade, an engineer checked what FastAPI sent without the class and found it identical. The custom class was deleted from the FastAPI services, and the one old service that really used json.dumps got ensure_ascii=False. The same review found ORJSONResponse on three routes; replacing it with declared return types removed a dependency and kept the speed.

Follow-up questions to expect

  • "Does the client need to do anything for raw UTF-8?" — No. The application/json content type implies UTF-8, and every standard JSON parser handles both forms.
  • "When would you write a custom response class today?" — For a different format (CSV, MessagePack), special number handling, or a fixed envelope — not for UTF-8.
  • "How do you stream JSON?" — Yield items from the route to get JSON Lines, or use EventSourceResponse for SSE, both in recent FastAPI.