This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Strange behavior when return with custom Response class #4998
Comments
I cannot reproduce on the exact same specs (MacOS 12.4, python 3.10.4 and FastAPI 0.78.0). And by that, I mean in my case, even in the |
Do you think maybe it has something to do with the version of other modules
|
My pip freeze: Don't see relevant differences. I am trying to follow the request through the application to see where the value gets truncated, but I am getting stuck (or actually, confused on what is happening). |
If you're testing from the swagger interface, the results will also got trimmed by JavaScript. Try visit directly to the path: http://0.0.0.0:8000/explicit-at-return. This should avoid the problem. |
Alright I traced it back to the default decoders of Pydantic. I don't think the code does what you intent to have it done. The This raw response is then fed into your This was a fun trip through the source code. The good news is, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None, This is actually a test case in the official tests. The bad news however, is that you can only use that parameter when calling the method directly. But, luckily for us, we can leverage the from decimal import Decimal
import uvicorn
import simplejson
from fastapi import FastAPI
from pydantic import BaseModel
class ModelWithDecimal(BaseModel):
foo: Decimal
class Config:
json_encoders = {
Decimal: lambda a: simplejson.dumps(
a,
ensure_ascii=False,
allow_nan=False,
indent=None,
separators=(",", ":"),
use_decimal=True
)
}
app = FastAPI()
pi_model = ModelWithDecimal(foo=Decimal("3.14159265358979323846264338327950288"))
@app.get("/implicit", response_model=ModelWithDecimal)
def implicit():
return pi_model
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000) Result: {
"foo":"3.14159265358979323846264338327950288",
} Let me know if this helps! |
I had a thought this morning on how to get a non-string decimal value in your JSON response. I tried the following: from decimal import Decimal
from typing import Any
import uvicorn
import simplejson
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel
class ModelWithDecimal(BaseModel):
foo: Decimal
class Config:
json_encoders = {
Decimal: lambda a: a
}
class MyJSONResponse(JSONResponse):
def render(self, content: Any) -> bytes:
print("MyJSONResponse is called")
v = simplejson.dumps(
content,
ensure_ascii=False,
allow_nan=False,
indent=None,
separators=(",", ":"),
use_decimal=True,
).encode("utf-8")
return v
app = FastAPI(default_response_class=MyJSONResponse)
pi_model = ModelWithDecimal(foo=Decimal("3.14159265358979323846264338327950288"))
@app.get("/implicit", response_model=ModelWithDecimal)
def implicit():
return pi_model
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000) Basically, this tells Working example with requirements: https://github.com/JarroVGIT/fastapi-github-issues/tree/master/4998 |
I actually did tried tweaking @JarroVGIT Thank you so much for your effort in experimenting this case. 👏🏻 |
In addition, I was building my new app with FastAPI, Pydantic, and SQLModel, which is why I'm bumping into this case. As I found out @tiangolo implement the Decimal support for Pydantic in pydantic/pydantic#3507. It's sooner or later that many developers using the same stack will have stuck on this issue. So here's my proposal:
If that sounds good to all, I'm willing to make this happens. 👍🏻 |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
First Check
Commit to Help
Example Code
Description
I implement a custom
MyJSONResponse
JSONResponse
is used, long decimal places will be trimmedI assigned
MyJSONResponse
as the default response class during app initializationOpen the browser to
/implicit
The expected results should be
but it's actually
/explicit-at-path
/explicit-at-return
, where I explicitly initialized the response when returning the data.MyJSONResponse
did get called in all path, but somehow only the last one worksI was also wondering how FastAPI handled data after the route function returns data. Specifically, what components did data flow through, in what order?
My naive observation and guessing:
response_model
to validate schemaresponse_class
to encode into JSON or plaintextPlease do correct me if I'm wrong, because this is just I imagine how it should be, but doesn't seems it actually is the case.
Operating System
macOS
Operating System Details
I don't think it matters, but incase you believe so, I'm running macOS 12.4.
FastAPI Version
0.78.0
Python Version
3.10.4
Additional Context
No response
The text was updated successfully, but these errors were encountered: