Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FastAPI Automatically Rounds-off Decimal Values in Response

I am using Pydantic-based Response Model with a Decimal in FastAPI-based app. I want to return a response with precision up to 20 decimal values. But after serialization, it rounds off the decimal of 15 digits to 14 digits.

For example:

Original Decimal    : 328.448267489936666
Decimal in Response : 328.44826748993665

I have tried setting getcontext.prec = 15, but it has no effect on it.

Minimal reproducible Example :

from decimal import getcontent, Decimal
from fastapi import FastAPI
from typing import Dict

app = FastAPI()


@app.get("/")
def read_root()->Dict[str, Decimal]:
    getcontext().prec = 15 
    return {"a": Decimal(328.448267489936666)}

Dependencies : fastapi==0.92.0

uvicorn==0.20.0

pydantic==1.10.5

Python 3.7

like image 591
Keshav Mishra Avatar asked Jun 17 '26 01:06

Keshav Mishra


1 Answers

Some precision loss happens with Decimal(328.448267489936666) since you're converting a float to a Decimal – convert a string to a Decimal with Decimal("328.448267489936666") so you have a precise Decimal to begin with, and then:

import decimal
from fastapi import FastAPI
from typing import Dict

app = FastAPI()


@app.get("/")
def read_root() -> Dict[str, decimal.Decimal]:
    decimal.getcontext().prec = 15
    return {"a": decimal.Decimal("328.448267489936666")}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, port=11111)
~ $ curl http://localhost:11111
{"a":"328.448267489936666"}

Note how the Decimal is a string in the JSON; that's because many JSON decoders just use floats for number content (at least by default), and that can't be trusted to be precise either.

The serialization behavior actually seems to depend on the version of Pydantic in use; Pydantic 2.x encodes decimals as strings, while Pydantic 1 doesn't.

You can patch the encoder dict in FastAPI to fix this though; do something like this early enough in your app (or in a startup hook):

from fastapi import encoders
encoders.ENCODERS_BY_TYPE[decimal.Decimal] = str
like image 160
AKX Avatar answered Jun 19 '26 14:06

AKX



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!