Fastapi: Cannot control json serialization with custom response_class

Created on 1 Oct 2020  路  5Comments  路  Source: tiangolo/fastapi

class CustomJSONResponse(JSONResponse):
    media_type = "application/json"

    def render(self, content: typing.Any) -> bytes:
        return dumps(content)

With dumps being a custom function, managing datetime values specifically.

@router.post("/requests")
async def insert_user_request(request: Request):
   return CustomJSONResponse(content={"timestamp": datetime.now()}, status_code=HTTP_201_CREATED)

Will work as expected but

@router.post("/requests", response_class=CustomJSONResponse, status_code=HTTP_201_CREATED)
async def insert_user_request(request: Request):
    return {"timestamp": datetime.now()}

Will fail to use the custom dump function.

The cause is in https://github.com/tiangolo/fastapi/blob/master/fastapi/routing.py#L190 : serialize_response (which calls jsonable_encoder) is called before the response_class instantiation (https://github.com/tiangolo/fastapi/blob/master/fastapi/routing.py#L201) so datetime values are converted to str prematurely.

question

Most helpful comment

Have the same issue. Did you solve it?

Only a PR would really solve it, provided it's considered as an issue, hence my "question" here.
Two possible workarounds:

  1. Explicit instantiation as illustrated above
  2. Tweak pydantic as suggested by @TTRh, e.g. pydantic.json.ENCODERS_BY_TYPE[datetime] = lambda dt: dt.replace(tzinfo=pytz.utc).isoformat()

All 5 comments

datetime encoder is coming from pydantic : https://github.com/samuelcolvin/pydantic/blob/master/pydantic/json.py#L20 i guess it's still possible to alter this one if we need custom encoder for datetime.

@TTRh : the explicit return of an CustomJSONResponse instance works fine without having to tweak pydantic. My point is that I wouldn't have expected a different behavior between the two syntaxes.

Have the same issue. Did you solve it?

Have the same issue. Did you solve it?

Only a PR would really solve it, provided it's considered as an issue, hence my "question" here.
Two possible workarounds:

  1. Explicit instantiation as illustrated above
  2. Tweak pydantic as suggested by @TTRh, e.g. pydantic.json.ENCODERS_BY_TYPE[datetime] = lambda dt: dt.replace(tzinfo=pytz.utc).isoformat()

@kshilov also you can create a workaround with default=str and encode()

class CustomJSONResponse(JSONResponse):
    media_type = "application/json"

    def render(self, content: typing.Any) -> bytes:
        return dumps(content, default=str).encode()

This will work however, I agree with @tangi75 it is a serious bug and should be handled by a PR.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kkinder picture kkinder  路  3Comments

zero0nee picture zero0nee  路  3Comments

scheung38 picture scheung38  路  3Comments

updatatoday picture updatatoday  路  3Comments

tsdmrfth picture tsdmrfth  路  3Comments