[QUESTION] Why not introduce pydantic @validator in docs?
See original GitHub issueDescription
I am new to fastapi and web APIs in general, but found it astonishing simple and fast to create a first working api. In the process, I found using pydantic @validators very useful for custom class validation. I was wondering why this is not introduced in the docs. Perhaps the use of @validators
is discouraged and there’s a better way?
Here’s a minimum working example to discuss. If this is the right way to do it, I can create a pull request to add it to the docs. Otherwise, I would be grateful for any hint towards a better approach to do this:
from fastapi import FastAPI
from pydantic import BaseModel, validator, BaseConfig
from geoalchemy2 import WKTElement
app = FastAPI()
class Coordinates(BaseModel):
lat: float = 0
lng: float = 0
@validator('lat')
def lat_within_range(cls, v):
if not -90 <= v <= 90:
raise ValueError('Latitude outside allowed range')
return v
@validator('lng')
def lng_within_range(cls, v):
if not -180 <= v <= 180:
raise ValueError('Longitude outside allowed range')
return v
class UserIn(BaseModel):
username: str
coordinates: Coordinates
class UserOut(BaseModel):
username: str
class UserInDB(BaseModel):
username: str
coordinates_geom: WKTElement
class Config(BaseConfig):
arbitrary_types_allowed = True
def get_geom_from_coordinates(coordinates: Coordinates):
geom_wkte = WKTElement(
f"Point ({coordinates.lng} {coordinates.lat})",
srid=4326, extended=True)
return geom_wkte
def fake_save_user(user_in: UserIn):
coordinates_geom = get_geom_from_coordinates(user_in.coordinates)
user_in_db = UserInDB(**user_in.dict(), coordinates_geom=coordinates_geom)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(*, user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
Explanation In the example above, there are two steps where I make use of pydantic, validation (1) and conversion (2).
First (1), I need to validate coordinates, which are usually submitted from the frontend using Latitude
and Longitude
as floats
. Then (2), I need to store these in the database in a special custom format, for which no validator is available from pydantic (e.g. as WKTElement
from geoalchemy2
, which is then stored as PostGis Geometry in the db). To summarize the use of pydantic:
- Validation (1): I need a check for input lat/lng range, that’s where I make use of the @validator above
- Conversion (2): I need conversion of input lat/lng values to the custom format
WKTElement
used to store values in the db, that’s the functionget_geom_from_coordinates
, which constructs a WellKnownText (WKT) representation of lat/lng - this requires making use of pydanticclass Config
to enablearbitrary_types_allowed
Here is a gist with a complete example that also includes loading of geometry to coordinates conversion.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:6 (3 by maintainers)
Top GitHub Comments
Thanks for the insight @Sieboldianus !
For range validations you can use
Schema
, it’s a bit less verbose and also generates the corresponding JSON Schema (used by OpenAPI). That way, even the Swagger UI will complain if the values provided are not in range.You could do:
Nevertheless, there are other more complex scenarios that benefit from
@validator
. Although I consider them more of a “power user” feature.I think
@validator
is a great way to do data validation, especially with FastAPI – you get clear error responses for free! It’s probably worth a section in the documentation.