-
Notifications
You must be signed in to change notification settings - Fork 34
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
FastAPI validation errors for openapi schema #42
Comments
Update: This is caused by OpenAPI spec not allowing Tuples with exact values inside (for the Coordinate and BBox attributes)(tiangolo/fastapi#466). I think FastAPI + Geojson Pydantic is an awesome combination so I think it should be looked into. I was quickly able to fix this by using nested Pydantic models instead - would such a fix be acceptable?
|
Note this would be a breaking change because (at least as-is) it would disallow positional arguments like a tuple Current: from geojson_pydantic import Point
Point(coordinates=(1, 2)) # Point(coordinates=(1.0, 2.0), type='Point') New: from typing import Union, Any
from pydantic import BaseModel, Field
import abc
NumType = Union[float, int]
class coord_2d(BaseModel):
x: NumType
y: NumType
class coord_3d(BaseModel):
x: NumType
y: NumType
z: NumType
Coordinate = Union[coord_2d, coord_3d]
class _GeometryBase(BaseModel, abc.ABC):
"""Base class for geometry models"""
coordinates: Any # will be constrained in child classes
@property
def __geo_interface__(self):
return self.dict()
class Point(_GeometryBase):
"""Point Model"""
type: str = Field("Point", const=True)
coordinates: Coordinate
Point(coordinates=(1, 2))
# ---------------------------------------------------------------------------
# ValidationError Traceback (most recent call last)
# <ipython-input-23-ff3c2dca9424> in <module>
# ----> 1 Point(coordinates=(1, 2))
#
# ~/.pyenv/versions/miniconda3-3.8-4.8.3/lib/python3.8/site-packages/pydantic/main.cpython-38-darwin.so in pydantic.main.BaseModel.__init__()
#
# ValidationError: 2 validation errors for Point
# coordinates
# value is not a valid dict (type=type_error.dict)
# coordinates
# value is not a valid dict (type=type_error.dict)
Point(coordinates={'x': 1, 'y': 2})
# Point(coordinates=coord_2d(x=1.0, y=2.0), type='Point') |
This is really unlucky, but I don't think it's a geojson-pydantic problem. We have to enforce the number of coordinates here and the coordinates are tuples not dict. Sadly I think this is a fastapi/OpenAPI problem (don't get me wrong I'd love to see this working because I also work a lot with fastapi). I understand that OpenAPI spec explicitly says that tuples with exact values inside is unsupported but it seems that work has been done to resolve it: kinda want to know what @geospatial-jeff thinks |
@vincentsarago OpenAPI doesn't support tuples until version 3.1, looks like FastAPI is not using this version yet. |
FYI I just had the same issue with our TileJSON model which use center: Optional[Tuple[float, float, int]] But the error only happens with the latest fastAPI version, locally with |
Hi! I've just met the same issue. I think it'll be possible to make this change in types.py (if using Python 3.9+):
As for me this helped also:
I know that it's not correct to use List instead of Tuple, but this helped me to use fastAPI+pydantic+SQLAlchemy. |
Could somebody have a look, please? :) |
@muety this has been looked at already and is not something that can be fixed until swagger-api/swagger-ui#5891 and tiangolo/fastapi#3038 get resolved if you know another way, I'll be pleased to learn 🙏 |
Hi, First of all, many thanks for the lib. Really appreciate it. I met with the same issue and the temporary solution is similar to @alexeynick with a little variance. from typing import List, Union
from pydantic import Field
from typing_extensions import Annotated
NumType = Union[float, int]
Position = Annotated[List[NumType], Field(min_items=2, max_items=3)] This ensures that the list length is constrained. Hope the issue is fixed on FastAPI side! 🙂 |
I'm trying to follow the different solution but I'm not sure it will work. here are couple notes: First, using Annotated List will change the type from Tuple to List which is kinda a breaking change, but I think I'll be 👌 with this.
✅ schema from typing import List, Union
from typing_extensions import Annotated
from pydantic import BaseModel, Field
import pydantic
pydantic.__version__
>> '1.9.0a1'
NumType = Union[float, int]
Position = Annotated[List[NumType], Field(min_items=2, max_items=3)]
class Point(BaseModel):
coordinates: Position
print(Point.schema_json())
>> {
"title": "Point",
"type": "object",
"properties": {
"coordinates": {
"title": "Coordinates",
"minItems": 2,
"maxItems": 3,
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "integer"
}
]
}
}
},
"required": [
"coordinates"
]
}
Point(coordinates=[0.0])
>> ValidationError: 1 validation error for Point
coordinates
ensure this value has at least 2 items (type=value_error.list.min_items; limit_value=2)
🚫 schema from typing import List, Union
from typing_extensions import Annotated
from pydantic import BaseModel
import pydantic
pydantic.__version__
>> '1.9.0a1'
NumType = Union[float, int]
Position = Union[Annotated[List[NumType], 2], Annotated[List[NumType], 3]]
class Point(BaseModel):
coordinates: Position
print(Point.schema_json())
# Not the schema we expect
>> {
"title": "Point",
"type": "object",
"properties": {
"coordinates": {
"title": "Coordinates",
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "integer"
}
]
}
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "integer"
}
]
}
}
]
}
},
"required": [
"coordinates"
]
}
Point(coordinates=[0.0]) # Should raise an error, but is not
>> Point(coordinates=[0.0]) Option 1 (pydantic field), is definitely better than using pure type but it change the Position even if Option 1 seems to be working, we can't use it for BBOX BBox = Union[
Annotated[List[NumType], Field(min_items=4, max_items=4)], # 2D bbox
Annotated[List[NumType], Field(min_items=6, max_items=6)] # 3D bbox
] This is not a valid expression 🤷 |
New release of FastAPI 0.73.0 seems to have been shipped with the fix. |
🥳 thanks for the update @pt-cervest 🙏 I guess we can close the issue then |
considering that this is now fixed! |
Using geojson-pydantic as a FastAPI model attribute type causes a pydantic openapi validation error.
The error is for all coordinates/bbox. I am not sure but it may be related to stricter checking of the coordinate optional numeric values for the openapi schema - previously it would not be able to resolve the items on the docs, but now the docs do not load.
This causes the following exception when attempting to view the fastapi openapi schema docs:
The text was updated successfully, but these errors were encountered: