FastAPIでORMを使って取得してきた結果をreturnしようと思ったときに

Traceback (most recent call last):
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/fastapi/applications.py", line 270, in __call__
    await super().__call__(scope, receive, send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/middleware/cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/fastapi/routing.py", line 255, in app
    content = await serialize_response(
  File "/home/raiu/work/project/porukatu/porukatu-back/porukatu-env/lib/python3.8/site-packages/fastapi/routing.py", line 141, in serialize_response
    raise ValidationError(errors, field.type_)
pydantic.error_wrappers.ValidationError: 1 validation error for RepairShop
response -> 0
  value is not a valid dict (type=type_error.dict)

というエラーが出てきて困った

pydantic.error_wrappers.ValidationError: 1 validation error for RepairShop
response -> 0
value is not a valid dict (type=type_error.dict)

とかって書いてるからreturnしているオブジェクトの辞書がおかしいよって怒られてるっぽい

気持ち悪いのが、似たようなコードで動くときと動かない場合があること。

解決策はFastAPIのドキュメントに書いてあった

https://fastapi.tiangolo.com/ja/tutorial/sql-databases/#use-pydantics-orm_mode

一応原因としてはレスポンスは辞書(dict)を期待しているが、実際にはSQLAlchemyのモデルが返ってきてしまっているので invalid となりエラーになってしまうということらしい

解決策

BaseModelを継承したクラスの定義に追記する

class RepairShop(BaseModel):
    name: str
    tel: str
    link: str
    description: str
    lat: float
    lon: float
    star: int
    outside_img: str
   
   	# ここを追加 
    class Config:
        orm_mode = True

これで正しくシリアライズできるようになっていい感じに動くようになった