diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a47b7738..88ca4a00 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -21,6 +21,7 @@ accessible via `from esmerald import Controller`. - Fix escaped " in TemplateResponse. - Fix TemplateResponse's auto-detection of the media-type when used directly. +- Don't mangle strings by default for other media-types than json. ## 3.6.2 diff --git a/esmerald/responses/base.py b/esmerald/responses/base.py index 2bacd09c..1865674f 100644 --- a/esmerald/responses/base.py +++ b/esmerald/responses/base.py @@ -192,20 +192,25 @@ def make_response(self, content: Any) -> bytes | memoryview | str: transform_kwargs = RESPONSE_TRANSFORM_KWARGS.get() if transform_kwargs: transform_kwargs = transform_kwargs.copy() + elif isinstance(content, str) and self.media_type != MediaType.JSON: + # treat strings special when not using json and disable mangling when no context is active. + transform_kwargs = None else: transform_kwargs = {} - transform_kwargs.setdefault( - "json_encode_fn", - partial( - orjson.dumps, - option=orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_OMIT_MICROSECONDS, - ), - ) + if transform_kwargs is not None: + transform_kwargs.setdefault( + "json_encode_fn", + partial( + orjson.dumps, + option=orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_OMIT_MICROSECONDS, + ), + ) try: # switch to a special mode for MediaType.JSON (default handlers) if self.media_type == MediaType.JSON: # keep it a serialized json object - transform_kwargs.setdefault("post_transform_fn", None) + if transform_kwargs is not None: + transform_kwargs.setdefault("post_transform_fn", None) # otherwise use default logic of lilya striping '"' with self.with_transform_kwargs(transform_kwargs): # if content is bytes it won't be transformed and diff --git a/tests/test_responses.py b/tests/test_responses.py index 273cd454..e9dac76e 100644 --- a/tests/test_responses.py +++ b/tests/test_responses.py @@ -3,6 +3,7 @@ from lilya import status from esmerald import Response +from esmerald.enums import MediaType from esmerald.responses.encoders import ORJSONResponse, UJSONResponse from esmerald.routing.gateways import Gateway from esmerald.routing.handlers import get @@ -54,6 +55,11 @@ def route_nine() -> None: pass +@get("/ten", media_type=MediaType.TEXT) +def route_ten() -> str: + return "hel\"'lo" + + def test_ujson_response(test_client_factory): with create_client(routes=[Gateway(handler=route_one)]) as client: response = client.get("/one") @@ -113,6 +119,13 @@ def test_str_returnal(test_client_factory): assert response.text == '"hello"' +def test_str_returnal_non_json(test_client_factory): + with create_client(routes=[Gateway(handler=route_ten)]) as client: + response = client.get("/ten") + + assert response.text == "hel\"'lo" + + def test_implicit_none_returnal(test_client_factory): with create_client(routes=[route_nine]) as client: response = client.get("/nine")