Open34

読者コミュニティ|FastAPI入門

takasakitakasaki

こんにちは
FastAPIのサンプルを探していて、とても勉強になりました。

いくつかエラーになった箇所をお知らせします。

  • 9章 api/routers/task.py GETのサンプルにfrom typing import Listがありません。
  • 10章 api/schemas/task.py class Task(BaseModel):class Task(TaskBase):に修正する内容が記載されていません。(最終的なソースがあるので、見比べるとわかります)
  • 11章 間違っているわけではないのですが、M1 macだと1行追加が必要でした。
  db:
    image: mysql:8.0
    platform: linux/x86_64.   ←この行を追加
    environment:
  • 11章 api/migrate_db.py にfrom api.models.task import Task, Doneがありません。
  • 12章 api/routers/task.pyのPOSTのサンプルにfrom fastapi import APIRouter, DependsDependsのインポートが必要です。

ここから要望です。

  • テストの実行コマンドを追記して欲しいです。
    $ docker-compose exec demo-app poetry run Pytest testsで確認できました。
  • 本番環境で稼働させる前提の書き方が知りたいです。データベースの接続URLなどを環境変数に持たせるなどです。
  • CORSなどセキュリティー関係の設定があると嬉しいです。
  • 続編でも良いですが、クラウドのサーバ構築、CI/CDがあると嬉しいです。
  • これも続編でも良いですが、アクセスログなど本番環境で稼働させる場合のログ出力の情報があると嬉しいです。
smithonisansmithonisan

フィードバックいただきありがとうございます!
ご指摘の点、的確かつ詳細に記載いただきありがとうございました。取り急ぎ修正させていただきました!🙇

11章 api/migrate_db.py にfrom api.models.task import Task, Doneがありません。

こちらコード的には不要かと思うのですが、エラー内容いただけますと幸いです。

要望についてもありがとうございます。続編も考えておりましたので大変励みになります。一部本書にも反映させていただくかもしれません!他にもございましたら遠慮なくお願いします。

smithonisansmithonisan

11章 api/migrate_db.py にfrom api.models.task import Task, Doneがありません。

こちらコード的には不要かと思うのですが、エラー内容いただけますと幸いです。

import順によって Task および Done クラスが認識されない場合があるようです。
以下のように修正いたしました!

python
< from api.db import Base
> from api.models.task import Base
TaroKawaTaroKawa

Chapter 09 : スキーマ(Schemas) - レスポンスにおいて、api/routers/task.pyの書き換えの際に

from fastapi import APIRouter

が抜けている気がしますが、いかがでしょうか?

look2233look2233

https://zenn.dev/sh0nk/books/537bb028709ab9/viewer/b92ab0
1)

from fastapi import APIRouter
from fastapi import APIRouter, Depends

の部分+/-が逆のようです

NameError: name 'AsyncSession' is not defined

というエラーがでていたので、

from sqlalchemy.ext.asyncio import AsyncSession

という行を足したらエラーはでなくなりました。

TMTM

こんにちわ
とてもわかりやすい内容でした!

書籍化してみませんか? 
ご連絡おまちしております!

smithonisansmithonisan

ご興味を持っていただきありがとうございます!

既にkindleでも読めるように こちら でセルフパブリッシングしているので書籍化は考えていなかったのですが、それでもよろしければ、こちらは読者コミュニティですので twitter よりご連絡頂ければと存じます!

TMTM

ご連絡ありがとうございます。
それではTwitterにてご連絡いたします。
takabonというハンドルネームです。

MkMkMkMk

こんにちは。
勉強したいと思っていた内容をわかりやすく書いていただき、ありがとうございます。
一通り自分でもコードを書きながら読ませていただいています。

1点、自身で解決できていないエラーがあるため質問させていただいてもよろしいでしょうか?

13章ユニットテストでテストを実行した際、

============================================================== short test summary info ===============================================================
FAILED tests/test_main.py::test_create_and_read - AttributeError: 'async_generator' object has no attribute 'post'
FAILED tests/test_main.py::test_done_flag - AttributeError: 'async_generator' object has no attribute 'post'
================================================================= 2 failed in 0.52s ==================================================================
ERROR: 1

というように、

AttributeError: 'async_generator' object has no attribute 'post'

が出てしまいます。async_generatorについても調べてみましたが、自己解決できておりません。
アドバイスいただけると幸いです。

smithonisansmithonisan

使われている pytest-asyncio のバージョンはいくつでしょうか?(pyproject.tomlからわかります)

>=0.19 であれば、fixtureの指定方法が デフォルトで変わっている ようです。以下のように指定すると、パスするかもしれません。

$ pytest tests --asyncio-mode=auto
MkMkMkMk

アドバイスしていただきありがとうございます。
pytest-asyncoのバージョンは0.19.0です。

$ pytest tests --asyncio-mode=auto

を実行しましたが、

コマンド 'pytest' が見つかりません。

と表示されます。
そのため、以下のコマンドを実行しました。

$ docker-compose run --entrypoint "pytest tests --asyncio-mode=auto" demo-app

しかしながら、下記のエラーが出ました。

Error response from daemon: failed to create shim task: 
OCI runtime create failed: runc create failed: 
unable to start container process: exec:
 "pytest": executable file not found in $PATH: unknown

再度、アドバイスいただけますと幸いです。

smithonisansmithonisan

0.19.0 でしたらちょうど pytest-asyncio のバージョンが変更されたところなので、こちらの方法で解決できるかと思います。

poetryを利用してpytestを実行しているので、 poetry run が必要になります。本書に沿ったコマンドは以下となります。

$ docker-compose run --entrypoint "poetry run pytest --asyncio-mode=auto" demo-app
MkMkMkMk

早速のアドバイスありがとうございます。

質問させていただいたエラーは解決できました。
ありがとうございました。

しかしながら、

FAILED tests/test_main.py::test_create_and_read - AttributeError: module 'api.schemas.task' has no attribute 'dict'
FAILED tests/test_main.py::test_done_flag - AttributeError: module 'api.schemas.task' has no attribute 'dict'

のエラーが出たので、私のコード入力が間違っているのだと思います。

確認のため、コード一式が確認できるリンク等をご教授いただけますでしょうか。

smithonisansmithonisan

pytest-asyncioのエラーが解消されたようで良かったです。

なお、現在コードベース全体は公開していない状態です、ご容赦ください。
エラーのスタックトレースを貼っていただければある程度お力添えできるかもしれません。

KITFJNKITFJN

はじめまして。
FastAPIを含め、プログラミングはまだまだ初学者です。

このFastAPIの入門書を見つけて、同じようにコードを書いていましたが、手順どおりに進めていくと、uvicornは起動するもののファイルを保存しても--reloadが実行されませんでした。
docker-composeの設定なのか、フォルダ構成の問題なのか、はたまた他の問題なのかが分かりませんでした。
なにか設定等で必要なことがあれば教えていただけないでしょうか。

質問の仕方もどうしたらよいかわからなかったため、とりあえず書かせていただきました。
よろしくお願いいたします。

smithonisansmithonisan

docker-compose up を実行しても こちら のようにSwagger UIが表示されない状態でしょうか?あるいは、ファイルを追加で上書きしても、reloadが走らないということでしょうか?

前者であれば、エラーメッセージを貼って頂ければ何かお力添えできるかもしれません。

KITFJNKITFJN

ありがとうございます。
詳細をお伝えすると、Windows PCでの実行をしようとしています。
同じ設定で記述しましたので、Swagger UIの表示はされます。
ですが、main.py等のファイルを上書きしてもreloadされず、返されるjsonの各値が変更にならない状態です。
何度やってもダメでした。
requirements.txtでやると上手くいく時があり、poetryが原因かとも疑いましたが、原因不明です。
Macで実行すると問題なく起動します。

gensgens
docker-compose run --entrypoint "poetry install" demo-app 

実行後に

/src/demo_app does not contain any element

とエラー表示されるのですがどういったエラーでしょうか?

MAAAAAAAAAAAMAAAAAAAAAAA

初学者の質問で申し訳ありません。私も同じところにハマってしまい、なんやかんやで抜け出せたのですが、自分が行った手順の何が正しかったのかをいまいち理解していないためどなたかご教授いただけませんでしょうか。。

やったこと

Dockerfileの修正

# poetryでライブラリをインストール (pyproject.tomlが既にある場合)
RUN poetry config virtualenvs.in-project true
- RUN if [ -f pyproject.toml ]; then poetry install; fi
+ RUN if [ -f pyproject.toml ]; then poetry install --no-root; fi
# uvicornのサーバーを立ち上げる

ターミナルで実行したコマンドの修正

- docker-compose run --entrypoint "poetry install" demo-app
+ docker-compose run --entrypoint "poetry install --no-root" demo-app
smithonisansmithonisan

コメントありがとうございます。当初執筆時のpoetryのバージョンが1.1.2と古かったのですが、現行のpoetryでは poetry init 時に packages = [{include = "demo_app"}] が含まれるようになり、 poetry install した際に、デフォルトでプロジェクト自身をインストールしようとします。

「FastAPI入門」ではプロジェクト自身をpoetryでインストールする必要がないため、 poetry install 時に --no-root オプションを渡すことでプロジェクトをパッケージとしてインストールするステップがスキップされ、エラーなくインストールを進めることが可能です。(MAAAAAAAAAAAさんのコメントの通りの変更で問題有りません)

記事の方にも反映しておきました。

∞ループ∞∞ループ∞

僕の環境で詰まった場所と、その解決策を共有します。

環境(OS)

  • ubuntu-22.04 (Windows11のwsl2上で動作)

完了フラグがtrueのタスクをdeleteできない

これは、MySQLの外部キー制約で、消したいtablesテーブルの列のid要素がdonesテーブルに存在する場合にエラーが発生したためである。
DELETE CASCADEを設定することで直った。

api/models/task.py
 from sqlalchemy import Column, Integer, String, ForeignKey
 from sqlalchemy.orm import relationship
 
 from api.db import Base
 
 
 class Task(Base):
     __tablename__ = "tasks"
 
     id = Column(Integer, primary_key=True)
     title = Column(String(1024))
 
+    done = relationship("Done", back_populates="task", cascade="delete")
-    done = relationship("Done", back_populates="task")
 
 
 class Done(Base):
     __tablename__ = "dones"
 
+    id = Column(Integer, ForeignKey("tasks.id", ondelete="CASCADE"), primary_key=True)
-    id = Column(Integer, ForeignKey("tasks.id"), primary_key=True)
 
     task = relationship("Task", back_populates="done")

https://zenn.dev/sh0nk/books/537bb028709ab9/viewer/281ee0

smithonisansmithonisan

ご報告ありがとうございます!

仰るとおりですね。doneフラグが立っている(doneテーブルにレコードがある)際のみDELETEエラーとなるので見落としておりました。
ForeignKeyの変更ですとmigration時に ON DELETE CASCADE がforeign keyに付与されるのですが、これだけですと削除時のエラーは改善しませんでした。一方で、relationshipにcascadeオプションを設定した場合、SQLAlchemyのレイヤーで解決してくれるので、こちらを採用し、 Chapter 11 に反映いたしました。

musclemuscle

初めまして。
プログラミング初心者です。
smithonisanのFastAPI入門の、poetryによるPython環境のセットアップで詰まってしまいました。

$ docker-compose run
--entrypoint "poetry init
--name demo-app
--dependency fastapi
--dependency uvicorn[standard]"
demo-app
 ↑このコードでエラーが出てしまいました。

エラーコードは↓

発生場所 行:1 文字:5

  • --entrypoint "poetry init \
  • ~
    

単項演算子 '--' の後に式が存在しません。
発生場所 行:1 文字:5

  • --entrypoint "poetry init \
  • ~~~~~~~~~~
    

式またはステートメントのトークン 'entrypoint' を使用できません。
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRe
cordException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator

改善方法のご教授お願いします。(´;ω;`)

smithonisansmithonisan

コメント頂いていたのに気づくのが遅くなってしまいました。申し訳ございません。

エラー内容を拝見するに、PowerShellをお使いでしょうか?コマンドはシェルスクリプト(Unixシェル)を想定しておりました。PowerShellの場合はコマンドの改行に \ (back slash) ではなく ` (back quote) を利用するということです。こちらに読み替えた上でお試し頂けるでしょうか?
https://qiita.com/wsigma21/items/008aa3e1636f245811c5

たかだたかだ

はじめまして。
大変勉強になる本をありがとうございます。

Chapter 10 「スキーマ(Schemas) - リクエスト」の「ルーター」セクションでの記述について質問です。

ここで、 dict インスタンスに対して先頭に ** をつけることで、 dict を キーワード引数として展開 し、 task_schema.TaskCreateResponse クラスのコンストラクタに対して dict のkey/valueを渡します。
つまり、これは task_schema.TaskCreateResponse(id=1, title=task_body.title, done=task_body.done) と等価となります。

task_schema.TaskCreateResponse(id=1, title=task_body.title, done=task_body.done) と等価となります。」という記述がありますが、正しくは task_schema.TaskCreateResponse(id=1, title=task_body.title) ではないかと考えました。
** を用いて展開している、パスオペレーション関数 create_task() の引数 task_doby の型は task_schema.TaskCreate であり、 done フラグが存在しないのではないかと思いました。
どなたかのお考えをお聞かせいただけますと幸いです。

smithonisansmithonisan

コメントありがとうございます。
ご指摘の通りかと思います。以下のように本文の変更を行いました。

つまり、これは task_schema.TaskCreateResponse(id=1, title=task_body.title) と等価となります。なお、ここではクラスの持つインスタンス変数が1つのため ** を利用するメリットが見えづらいですが、変数が多い場合にすべてを羅列せずに済みます。

さぼてんさんさぼてんさん

分かりやすくコンパクトにまとまっていてとてもためになりました。

最新の環境でユニットテストが実行できないようになっているようです。
下記のように修正したら動きました。

tests/test_main.py
+ import pytest, pytest_asyncio
- import pytest

+ from httpx import AsyncClient, ASGITransport
- from httpx import AsyncClient

...

+ @pytest_asyncio.fixture
- @pytest.fixture

...

    # テスト用に非同期HTTPクライアントを返却
+     transport = ASGITransport(app=app)
+     async with AsyncClient(transport=transport, base_url="http://test") as client:
-     async with AsyncClient(app=app, base_url="http://test") as client: