Visual Studio Code での FastAPI チュートリアル
FastAPI は、Python で API を構築するための、最新の高性能 Web フレームワークです。自動検証、シリアル化、API のドキュメント化などの機能を提供しながら、API を迅速かつ効率的に構築しやすく設計されており、Web サービスやマイクロサービスを構築するための人気のある選択肢となっています。
この FastAPI チュートリアルでは、FastAPI を使用して買い物リストアプリを作成します。チュートリアルの終わりまでに、Visual Studio Code のターミナル、エディター、デバッガーで FastAPI を操作する方法を理解できます。このチュートリアルは FastAPI の詳細な解説ではありません。詳細については、公式の FastAPI ドキュメントを参照してください。
Python を初めて使用する場合は、言語と VS Code の Python サポートに慣れるために、まずPython チュートリアルから始めることをお勧めします。このチュートリアルは、すでに Python に慣れており、VS Code で FastAPI を操作する方法を学びたい人により適しています。
この FastAPI チュートリアルの完成したコードプロジェクトは、GitHub で見つけることができます: python-sample-vscode-fastapi-tutorial。
問題が発生した場合は、Python 拡張機能 Discussions Q&A で回答を検索したり、質問したりできます。
プロジェクトのセットアップ
このチュートリアルでは、プロジェクトをセットアップするさまざまな方法があります。GitHub Codespaces でのセットアップ方法と、ローカルマシン上の VS Code でのセットアップ方法について説明します。
GitHub Codespaces
このプロジェクトは、GitHub Codespaces で開発できるようにセットアップできます。Codespace では、リモートでアプリのコーディング、デバッグ、実行が可能です。Codespace は、クラウドでホストされる完全に構成された開発環境を提供し、ローカルでのセットアップの必要性を排除します。この環境には、プロジェクトの依存関係、ツール、拡張機能が含まれており、一貫性のある再現可能な開発エクスペリエンスを保証します。リアルタイム編集、統合されたバージョン管理、デバッグおよびテストツールへの容易なアクセスを提供することで、コラボレーションを効率化し、プロジェクトのセキュリティと信頼性を維持します。
注: すべての GitHub.com アカウントには、Free または Pro プランに含まれる GitHub Codespaces の月額無料使用量があります。詳細については、GitHub Codespaces の課金についてを参照してください。
このチュートリアルの Codespace をセットアップするには、このプロジェクトの GitHub リポジトリに移動します。この Codespace には、FastAPI 開発をすぐに開始するために必要なすべての構成と依存関係が含まれています。
このチュートリアルでは、dictionarybased ブランチを選択します。
次に、Code > Codespaces > Create Codespace on <dictionarybased> ブランチを選択して、プロジェクトの Codespace を作成して開きます。
完了したら、下記のデータベースを置き換えるセクションに進むことができます。
VS Code をローカルで使用する
VS Code でこのチュートリアルを正常に完了するには、まず Python 開発環境をセットアップする必要があります。具体的には、このチュートリアルでは次のものが必要です。
- Python 3 (インストールガイドを参照してください。インストールされていない場合)
- VS Code 用 Python 拡張機能 (拡張機能のインストールに関する追加の詳細については、拡張機能マーケットプレイスを参照してください)。
このセクションでは、VS Code でワークスペースとして開くフォルダーを作成し、Python 仮想環境をセットアップし、プロジェクトの依存関係をインストールします。
-
ファイルシステムに、
groceries-plugin
のようなこのチュートリアルのプロジェクトフォルダーを作成します。 -
この新しいフォルダーを VS Code で開きます (ファイル > フォルダーを開く…)。
-
ワークスペース信頼のプロンプトが表示されたら、はい、作成者を信頼しますを選択して、ワークスペースが必要なリソースと拡張機能にアクセスできるようにします。ワークスペース信頼の詳細については、ドキュメントを参照してください。
次に、アプリケーションにインストールする依存関係をリストする requirements.txt
ファイルを作成しましょう。requirements.txt
ファイルは、Python 開発で一般的な慣行であり、プロジェクトが依存するライブラリとそのバージョンを指定するために使用されます。このファイルは、プロジェクトに取り組む誰もが同様の開発環境を再現できるようにするのに役立ち、一貫性を維持するための便利なコンポーネントとなります。
アプリケーションを作成するために FastAPI、サーバーとして機能するためにuvicorn、データストレージを処理し、Redis データベースと対話するためにRedis と type-redis
をインストールします。
-
VS Code で新しいファイルを作成します (ファイル > 新しいテキストファイル または ⌘N (Windows、Linux Ctrl+N))。
-
次のコンテンツを追加します
fastapi redis types-redis uvicorn
-
ファイルを保存し (⌘S (Windows、Linux Ctrl+S))、
requirements.txt
と名前を付けます。 -
コマンドパレットを開き (⇧⌘P (Windows、Linux Ctrl+Shift+P))、Python: 環境の作成コマンドを実行して、仮想環境を作成します。
注: この手順は完了するまでに数分かかる場合があります。
-
環境の種類を尋ねられたら、Venv を選択します。
-
次に、マシンで利用可能な最新バージョンの Python を選択します。
-
ドロップダウンリストから
requirements.txt
ファイルを選択し、依存関係が自動的にインストールされるようにしてから、OK を選択します。
仮想環境が作成され、依存関係が自動的にインストールされ、Python 拡張機能で使用するワークスペースの環境が選択されます。VS Code の右下隅を確認することで、選択されたことを確認できます。
注: ステータスバーに新しく作成された環境情報が見つからない場合は、Python インタープリターインジケーターをクリックするか (またはコマンドパレットからPython: インタープリターの選択コマンドを実行して)、手動で仮想環境を選択できます。
コーディングを開始する
アプリケーションを作成しましょう!
-
ファイル > 新しいファイル… を使用して新しい Python ファイルを作成し、Python ファイルを選択します。
-
groceries-plugin
フォルダーにmain.py
として保存します (⇧⌘S (Windows、Linux Ctrl+Shift+S))。 -
main.py
に次のコードを追加し、ファイルを保存します。from fastapi import FastAPI app = FastAPI() @app.get("/") def root(): return {"message": "Hello World"}
-
デバッガーを起動してコードを実行します (F5)。
-
ドロップダウンメニューから、リストからFastAPI構成オプションを選択します。
これにより、uvicorn を呼び出してデバッガーを介してアプリケーションサーバーを起動し、ソースコードをステップ実行してその動作を検査できるデバッグ構成が自動的に作成されます。ターミナルには次のような表示がされるはずです。
ヒント: デフォルトのポートがすでに使用されている場合は、デバッガーを停止し、コマンドパレットを開き (⇧⌘P (Windows、Linux Ctrl+Shift+P))、デバッグ: 構成の追加を検索し、Python デバッガー、次に FastAPI を選択します。これにより、編集可能なカスタム構成ファイルが
.vscode/launch.json
に作成されます。カスタムポートを設定するには、"args":[]
に"--port=5000"
を追加します。ファイルを保存し、(F5) を使用してデバッガーを再起動します。 -
ターミナルの
http://127.0.0.1:8000/
URL をCtrl+クリックして、そのアドレスをデフォルトのブラウザーで開きます。おめでとうございます!FastAPI アプリが起動して実行されています!
-
デバッグツールバーの停止ボタンを使用するか、⇧F5 (Windows、Linux Shift+F5) を使用してデバッガーを停止します。
買い物リストアイテムのモデルを作成する
FastAPI アプリが動作するようになったので、FastAPI とシームレスに統合できるデータ検証および解析ライブラリであるPydantic を使用して、買い物リストアイテムを定義できます。Pydantic を使用すると、Python クラスと型ヒントを使用してデータモデルを定義でき、API リクエストで受信データ (「ペイロード」と呼ばれる) の自動検証と解析を行うことができます。
買い物リストアイテムのモデルを作成しましょう。ItemPayload
モデルを使用して、買い物リストに追加するアイテムのデータ構造を定義します。このモデルには、item_id
、item_name
、および quantity
の3つのフィールドがあります。
-
ファイル > 新しいファイル… を使用して新しい Python ファイルを作成し、Python ファイルを選択します。
-
ファイルに次の行を追加し、
groceries-plugin
フォルダーにmodels.py
として保存します (⇧⌘S (Windows、Linux Ctrl+Shift+S))。from typing import Optional from pydantic import BaseModel class ItemPayload(BaseModel): item_id: Optional[int] item_name: str quantity: int
VS Code の Python のデフォルト言語サーバーであるPylance は、Pydantic モデルと FastAPI を使用する際に役立つ型ヒント機能をサポートしています。これは、Pylance が Python の静的型チェッカーであるPyright の上に構築されており、コード内の型エラーを検出してバグを防ぎ、コード品質を向上させることができるためです。
以下の3つの手順はオプションですが、FastAPI はコードの可読性と検証を向上させるために型ヒントを広範囲に利用しているため、Pylance の型チェック機能を活用して早期にエラーを検出できます。
-
設定エディターを開きます (⌘, (Windows、Linux Ctrl+,))。
-
「python type checking mode」を検索し、基本的な型チェックのために
basic
に設定します。これにより、Pylance は簡単な型関連のエラーを検出するための診断と警告を表示します。または、より高度な型チェックルールを適用するためにstrict
に設定することもできます。 -
次に、「Python インレイ型ヒント」を検索し、変数型と関数戻り値型のインレイヒントを有効にします。
ルートを作成する
次に、買い物リストアイテムを保存する場所が必要です。簡潔にするため、空の辞書から始めましょう。
-
まず、サンプルに必要なすべてのパッケージをインポートしましょう。
main.py
ファイルを開き、最初のインポート行を次の行に置き換えます。from fastapi import FastAPI, HTTPException from models import ItemPayload
-
次に、
app = FastAPI()
のすぐ下に次の行を追加します。grocery_list: dict[int, ItemPayload] = {}
これにより、型
int
のキー (アイテム ID として) と型ItemPayload
の値を受け取る新しい空の辞書が作成されます。次に、FastAPI アプリケーションでルートを定義します。Web アプリケーションのコンテキストでは、ルートは特定の URL をそれらを処理するコードにマッピングするパスのようなものです。これらのルートは、アプリケーション内のさまざまな機能のエントリポイントとして機能します。Web ブラウザーや他のプログラムなどのクライアントが特定の URL でアプリケーションにリクエストを送信すると、FastAPI はその URL に基づいて適切な関数 (ルートハンドラーまたはビュー関数とも呼ばれる) にそのリクエストをルーティングし、その関数はリクエストを処理して応答を生成します。
個々のアイテムを追加および取得し、買い物リスト内のすべてのアイテムを返すルートを定義する手順に進みましょう。
-
main.py
ファイルの最後に次のルートを追加します。# Route to add a item @app.post("/items/{item_name}/{quantity}") def add_item(item_name: str, quantity: int): if quantity <= 0: raise HTTPException(status_code=400, detail="Quantity must be greater than 0.") # if item already exists, we'll just add the quantity. # get all item names items_ids = {item.item_name: item.item_id if item.item_id is not None else 0 for item in grocery_list.values()} if item_name in items_ids.keys(): # get index of item_name in item_ids, which is the item_id item_id = items_ids[item_name] grocery_list[item_id].quantity += quantity # otherwise, create a new item else: # generate an ID for the item based on the highest ID in the grocery_list item_id = max(grocery_list.keys()) + 1 if grocery_list else 0 grocery_list[item_id] = ItemPayload( item_id=item_id, item_name=item_name, quantity=quantity ) return {"item": grocery_list[item_id]}
前のセクションで型ヒントを有効にしている場合、Pylance が関数戻り値型と
item_ids
およびitem_id
の型のインレイヒントを追加することに気づくかもしれません。オプションで、各提案をダブルクリックしてコードに挿入できます。次に、このルートが期待どおりに機能しているか確認しましょう。最も速い方法は、VS Code のデバッガーと FastAPI の
/docs
エンドポイントの両方を使用することです。これにより、利用可能なすべての API ルートに関する情報が提供され、API と対話してそのパラメーターと応答を探索できます。このドキュメントは、FastAPI アプリケーションで定義されたメタデータと型ヒントに基づいて動的に生成されます。 -
if quantity <= 0
ステートメントの横に、行番号の左余白をクリックして (または F9)、ブレークポイントを追加します。デバッガーはその行の実行前に停止するため、コードを1行ずつ検査できます。 -
デバッガーを開始し (F5)、ブラウザーで
http://127.0.0.1:8000/docs
に移動します。アプリで利用可能な2つのエンドポイント
/items
とルート (/
) を持つ Swagger インターフェイスがあるはずです。 -
/items
ルートの横にある下向き矢印を選択して展開し、右側に表示される試してみるボタンを選択します。 -
item_name
フィールドに文字列を、quantity
に数値を渡して買い物リストアイテムを追加します。たとえば、item_name
に apple、quantity
に 2 を指定できます。 -
実行を選択します。
-
もう一度 VS Code を開き、デバッガーが以前設定したブレークポイントで停止していることに注目してください。
左側には、この時点で定義されているすべてのローカル変数とグローバル変数が、実行とデバッグビューの変数ウィンドウに表示されます。この例では、ローカル変数ビューの下に
item_name
が 'apple' に、quantity
が 2 に設定されており、グローバル変数ビューの下に空のgrocery_list
辞書があります。次に、VS Code のデバッグコンソールを使用していくつかの探索を行いましょう。
-
quantity <= 0
ステートメントを選択し、エディターを右クリックしてデバッグコンソールで評価を選択します。これによりデバッグコンソールが開き、選択された式が実行されます。この例では、期待どおりに式は
False
と評価されます。デバッグコンソールは、式を素早くテストし、ブレークポイント時のコードの状態をよりよく理解するための強力なツールです。関数を呼び出したり変数を表示したりするなど、任意のコードを実行するためにも使用できます。VS Code での Python デバッグの詳細については、Python チュートリアルで学ぶことができます。
デバッグビューツールバーの続行を選択するか、F5 を押してコードの実行を続行できます。
最後に、すべてのアイテムまたは特定のアイテムをリストしたり、買い物リストから削除したりできるように、アプリケーションの残りのルートを追加しましょう。次のステップで行う変更を保存すると、デバッガーはアプリケーションを自動的にリロードするため、デバッガーを実行したままにできます。
-
main.py
のコンテンツを以下のコードに置き換えます。from fastapi import FastAPI, HTTPException from models import ItemPayload app = FastAPI() grocery_list: dict[int, ItemPayload] = {} # Route to add an item @app.post("/items/{item_name}/{quantity}") def add_item(item_name: str, quantity: int) -> dict[str, ItemPayload]: if quantity <= 0: raise HTTPException(status_code=400, detail="Quantity must be greater than 0.") # if item already exists, we'll just add the quantity. # get all item names items_ids: dict[str, int] = { item.item_name: item.item_id if item.item_id is not None else 0 for item in grocery_list.values() } if item_name in items_ids.keys(): # get index of item_name in item_ids, which is the item_id item_id: int = items_ids[item_name] grocery_list[item_id].quantity += quantity # otherwise, create a new item else: # generate an ID for the item based on the highest ID in the grocery_list item_id: int = max(grocery_list.keys()) + 1 if grocery_list else 0 grocery_list[item_id] = ItemPayload( item_id=item_id, item_name=item_name, quantity=quantity ) return {"item": grocery_list[item_id]} # Route to list a specific item by ID @app.get("/items/{item_id}") def list_item(item_id: int) -> dict[str, ItemPayload]: if item_id not in grocery_list: raise HTTPException(status_code=404, detail="Item not found.") return {"item": grocery_list[item_id]} # Route to list all items @app.get("/items") def list_items() -> dict[str, dict[int, ItemPayload]]: return {"items": grocery_list} # Route to delete a specific item by ID @app.delete("/items/{item_id}") def delete_item(item_id: int) -> dict[str, str]: if item_id not in grocery_list: raise HTTPException(status_code=404, detail="Item not found.") del grocery_list[item_id] return {"result": "Item deleted."} # Route to remove some quantity of a specific item by ID @app.delete("/items/{item_id}/{quantity}") def remove_quantity(item_id: int, quantity: int) -> dict[str, str]: if item_id not in grocery_list: raise HTTPException(status_code=404, detail="Item not found.") # if quantity to be removed is higher or equal to item's quantity, delete the item if grocery_list[item_id].quantity <= quantity: del grocery_list[item_id] return {"result": "Item deleted."} else: grocery_list[item_id].quantity -= quantity return {"result": f"{quantity} items removed."}
-
ファイルを保存します (⌘S (Windows、Linux Ctrl+S))。アプリケーションは自動的にリロードされるはずです。
これで、/docs
ページを再度開き、デバッガーとデバッグコンソールを使用してコードの実行をよりよく理解しながら、新しいルートをテストできます。完了したら、デバッガーを停止できます (⇧F5 (Windows、Linux Shift+F5))。ステップ4で追加したブレークポイントは、クリックすることで削除することもできます。
おめでとうございます!これで、買い物リストにアイテムを追加、リスト表示、削除するためのルートを持つ、動作する FastAPI アプリケーションが完成しました。
データストレージをセットアップする
この時点で、基本機能を持つ動作するバージョンのアプリケーションが既にあります。このセクションでは、永続性のためのデータストレージのセットアップについて説明しますが、すでに学習した内容に満足している場合は、このセクションをスキップすることもできます。
これまでのところ、データを辞書に保存していますが、アプリケーションが再起動するとすべてのデータが失われるため、理想的ではありません。
データを永続化するために、オープンソースのインメモリデータ構造ストアであるRedis を使用します。Redis はその速度と汎用性により、Web アプリケーション、リアルタイム分析システム、キャッシュレイヤー、このチュートリアルなど、幅広いアプリケーションでデータストレージシステムとして一般的に使用されています。
既存のテンプレートでGitHub Codespaces を既に利用している場合は、データベースを置き換えるセクションに直接スキップできます。
Windows を使用している場合は、Docker コンテナーまたはGitHub Codespace のいずれかをセットアップして Redis を操作できます。このチュートリアルでは Docker コンテナーを使用しますが、GitHub Codespace のセットアップ方法については、上記のセクションを参照してください。
それ以外の場合、Linux または macOS マシンを使用している場合は、彼らのウェブサイトの指示に従って Redis をインストールし、データベースを置き換えるセクションに進むことができます。
Windows で Docker コンテナーをセットアップする
VS Code のDev Containers 拡張機能は、プロジェクト、その依存関係、および必要なすべてのツールを1つのきれいなコンテナーに統合し、フル機能の開発環境を作成するための合理化されたアプローチを提供します。この拡張機能を使用すると、VS Code でプロジェクトをコンテナー内 (またはマウントされたコンテナー内) で開くことができ、そのすべての機能セットを利用できます。
以下の手順では、マシンに次の要件がインストールされていることを確認してください。
要件
開発コンテナー構成を作成する
-
コマンドパレットを開き、開発コンテナー: 開発コンテナー構成ファイルの追加…を実行します。
-
Python 3 を選択します。
-
デフォルトバージョンを選択します。
-
インストールする追加機能としてRedis Server を選択し、OK を押してから、既定値を保持を選択します。
オプションで、コンテナーに含める機能をインストールできます。このチュートリアルでは、Redis の適切な開発コンテナーセットアップをインストールして追加する、コミュニティが貢献した機能であるRedis Server をインストールします。
これにより、ワークスペースに
.devcontainer
フォルダーとdevcontainer.json
ファイルが作成されます。このファイルを編集して、コンテナーのセットアップに、必要な VS Code 拡張機能のインストールやプロジェクトの依存関係のインストールなどの手順が含まれるようにしましょう。 -
devcontainer.json
ファイルを開きます。 -
"features" : { ... }
エントリの後に「,」を追加して、ファイルにさらに設定を追加できるようにします。次に、必要な依存関係のインストールコマンドを
devcontainer.json
ファイルのpostCreateCommand
プロパティに追加します。これにより、コンテナーがセットアップされたらすぐにアプリケーションが実行できるようになります。 -
以下のコンテンツを見つけ、その行からコメント (
//
) を削除して、コンテナーが作成された後に依存関係がインストールされるようにします。"postCreateCommand": "pip3 install --user -r requirements.txt",
postCreateCommand
およびその他のライフサイクルスクリプトについては、開発コンテナー仕様で学ぶことができます。次に、
customizations
プロパティを使用して、コンテナーにインストールしたい VS Code 拡張機能を追加します。 -
devcontainer.json
に次の設定を追加します。// Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "pip3 install --user -r requirements.txt", // Configure tool-specific properties. "customizations": { "vscode": { "extensions": [ "ms-python.python", //Python extension ID "ms-python.vscode-pylance" //Pylance extension ID ] } }
-
ファイルを保存します。
-
右下隅に表示される通知からコンテナーで再度開くを選択するか、コマンドパレットから開発コンテナー: コンテナーで再度開くコマンドを実行します。
注: コンテナーのビルドには、インターネット速度とマシンのパフォーマンスに応じて、数分かかる場合があります。
開発コンテナーの構成の詳細については、Dev Containers ドキュメントを参照してください。
完了すると、Python 3 と Redis Server がインストールされた、完全に構成された Linux ベースのワークスペースが手に入ります。
コンテナーがセットアップされると、VS Code の左下隅にインジケーターが表示されます。
注: 拡張機能ビュー (⇧⌘X (Windows、Linux Ctrl+Shift+X)) を開き、Python と Pylance の拡張機能がコンテナーに正常にインストールされていることを再確認してください。インストールされていない場合は、開発コンテナーにインストールを実行してインストールできます。
選択された Python インタープリター情報は、devcontainer.json
ファイルで指定されたバージョンと一致して、右下のステータスバーに表示されます。
注: ステータスバーに Python インタープリター情報が見つからない場合は、Python インタープリターインジケーターをクリックするか (またはコマンドパレットからPython: インタープリターの選択コマンドを実行して)、コンテナー内の Python インタープリターを手動で選択できます。
これで、データストレージを置き換える次のセクションに進む準備ができました。
データベースを置き換える
買い物リストアイテムを保存する辞書がありますが、これを Redis データベースに置き換えたいと考えています。このチュートリアルでは、複数のキーと値のペアを保存できるデータ構造である Redis ハッシュを使用してデータを保存します。
ID を知らなくてもアイテムを取得できる従来のデータベースとは異なり、Redis ハッシュから値を取得するには Redis ハッシュキーを知る必要があります。このチュートリアルでは、名前でアイテムを取得し、それらを ID にマッピングするために item_name_to_id
というハッシュを作成します。さらに、ID でアイテムを取得するために他のハッシュを作成し、それらを名前と数量にマッピングします。各アイテムハッシュは item_id:{item_id}
と命名され、item_name
と quantity
の2つのフィールドを持ちます。
まず、辞書を Redis サーバーに接続する Redis クライアントオブジェクトに置き換えることから始めましょう。
-
main.py
ファイルの冒頭にあるgrocery_list: dict[int, ItemPayload] = {}
を以下の行に置き換えます。redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True)
Redis がまだインポートされていないため、Pylance がエラーメッセージを表示します。
-
エディターの「redis」にカーソルを置き、表示される電球をクリックします (または ⌘. (Windows、Linux Ctrl+.))。次に、'import redis' を追加を選択します。
ヒント: 設定エディター (⌘, (Windows、Linux Ctrl+,)) で自動インポート補完設定を探して有効にすることで、Pylance が自動的にインポートを追加するように設定できます。
これで、ローカルホスト (
host="0.0.0.0"
) で実行され、ポート 6379 (port=6379
) でリッスンしている Redis サーバーに接続する Redis クライアントオブジェクトができました。db
パラメーターは使用する Redis データベースを指定します。Redis は複数のデータベースをサポートしており、このコードではデフォルトのデータベースであるデータベース 0 を使用します。また、応答が文字列 (バイトではなく) としてデコードされるようにdecode_responses=True
を渡しています。最初のルート
add_item
でさらにいくつかの置き換えを行いましょう。提供されたアイテム名を見つけるために辞書のすべてのキーを見る代わりに、Redis ハッシュからその情報を直接取得できます。item_name_to_id
ハッシュが既に存在し、アイテム名をその ID にマッピングしていると仮定します (心配しないでください、このコードはすぐに後で追加します!)。次に、Redis のhget
メソッドを呼び出すことで、リクエストで受信しているアイテム名の ID を取得できます。これにより、要求された名前がハッシュに既に存在する場合はアイテム ID が返され、存在しない場合はNone
が返されます。 -
以下の内容の行を削除します。
items_ids = {item.item_name: item.item_id if item.item_id is not None else 0 for item in grocery_list.values()}
そして、次のように置き換えます。
item_id = redis_client.hget("item_name_to_id", item_name)
この変更により Pylance が問題を示すことに注目してください。これは、
hget
メソッドがstr
またはNone
(アイテムが存在しない場合) を返すためです。しかし、まだ置き換えていないコードの下の行は、item_id
が型int
であることを期待しています。この警告に対処するために、item_id
シンボルを名前変更しましょう。 -
item_id
をitem_id_str
に名前変更します。 -
インレイヒントを有効にしている場合、Pylance は
item_id_str
の横に変数型ヒントを表示するはずです。オプションでダブルクリックして受け入れることができます。 -
アイテムが存在しない場合、
item_id_str
はNone
です。したがって、次に以下の内容の行を削除できます。if item_name in items_ids.keys():
そして、次のように置き換えます。
if item_id_str is not None:
アイテム ID が文字列として取得できたので、それを
int
に変換し、アイテムの数量を更新する必要があります。現在、私たちの Redis ハッシュはアイテム名をその ID にのみマッピングしています。アイテム ID をその名前と数量にもマッピングするために、各アイテムに個別の Redis ハッシュを作成します。このハッシュ名には"item_id:{item_id}"
を使用し、ID による取得を容易にします。また、これらの各ハッシュにitem_name
とquantity
フィールドを追加します。 -
if
ブロック内のコードを削除します。item_id: int = items_ids[item_name] grocery_list[item_id].quantity += quantity
そして、
item_id
をint
に変換し、Redis のhincrby
メソッドを呼び出してアイテムの数量をインクリメントするために、次を追加します。このメソッドは、要求された量 (quantity
) だけ"quantity"
フィールドの値を増加させます。item_id = int(item_id_str) redis_client.hincrby(f"item_id:{item_id}", "quantity", quantity)
次に、アイテムが存在しない場合、つまり
item_id_str
がNone
の場合のコードを置き換えるだけです。この場合、新しいitem_id
を生成し、そのアイテム用に新しい Redis ハッシュを作成してから、提供されたアイテム名と数量を追加します。新しい
item_id
を生成するには、Redis のincr
メソッドを使用し、"item_ids"
という新しいハッシュを渡します。このハッシュは最後に生成された ID を格納するために使用され、新しいアイテムを作成するたびにこれをインクリメントすることで、すべてのアイテムが一意の ID を持つことを保証します。 -
以下の内容の行を削除します。
item_id: int = max(grocery_list.keys()) + 1 if grocery_list else 0
そして、次を追加します。
item_id: int = redis_client.incr("item_ids")
この
incr
呼び出しがitem_ids
キーで初めて実行されると、Redis はキーを作成し、値を1
にマッピングします。その後、実行されるたびに、保存された値を 1 ずつ増やします。次に、
hset
メソッドを使用して、フィールド (item_id
、item_name
、およびquantity
) と値 (アイテムの newly created ID、および提供された名前と数量) のマッピングを提供することで、アイテムを Redis ハッシュに追加します。 -
以下の内容の行を削除します。
grocery_list[item_id] = ItemPayload( item_id=item_id, item_name=item_name, quantity=quantity )
そして、次のように置き換えます。
redis_client.hset( f"item_id:{item_id}", mapping={ "item_id": item_id, "item_name": item_name, "quantity": quantity, })
次に、最初に参照したハッシュ
item_name_to_id
を設定することで、新しく作成された ID をアイテム名にマッピングするだけです。 -
この行をルートの末尾、
else
ブロック内に追加します。redis_client.hset("item_name_to_id", item_name, item_id)
-
以下の内容の行を削除します。
return {"item": grocery_list[item_id]}
そして、次のように置き換えます。
return {"item": ItemPayload(item_id=item_id, item_name=item_name, quantity=quantity)}
-
必要であれば、他のルートについても同様の置き換えを試すことができます。そうでなければ、ファイルのコンテンツ全体を以下の行に置き換えることができます。
import redis from fastapi import FastAPI, HTTPException from models import ItemPayload app = FastAPI() redis_client = redis.StrictRedis(host="0.0.0.0", port=6379, db=0, decode_responses=True) # Route to add an item @app.post("/items/{item_name}/{quantity}") def add_item(item_name: str, quantity: int) -> dict[str, ItemPayload]: if quantity <= 0: raise HTTPException(status_code=400, detail="Quantity must be greater than 0.") # Check if item already exists item_id_str: str | None = redis_client.hget("item_name_to_id", item_name) if item_id_str is not None: item_id = int(item_id_str) redis_client.hincrby(f"item_id:{item_id}", "quantity", quantity) else: # Generate an ID for the item item_id: int = redis_client.incr("item_ids") redis_client.hset( f"item_id:{item_id}", mapping={ "item_id": item_id, "item_name": item_name, "quantity": quantity, }, ) # Create a set so we can search by name too redis_client.hset("item_name_to_id", item_name, item_id) return { "item": ItemPayload(item_id=item_id, item_name=item_name, quantity=quantity) } # Route to list a specific item by ID but using Redis @app.get("/items/{item_id}") def list_item(item_id: int) -> dict[str, dict[str, str]]: if not redis_client.hexists(f"item_id:{item_id}", "item_id"): raise HTTPException(status_code=404, detail="Item not found.") else: return {"item": redis_client.hgetall(f"item_id:{item_id}")} @app.get("/items") def list_items() -> dict[str, list[ItemPayload]]: items: list[ItemPayload] = [] stored_items: dict[str, str] = redis_client.hgetall("item_name_to_id") for name, id_str in stored_items.items(): item_id: int = int(id_str) item_name_str: str | None = redis_client.hget(f"item_id:{item_id}", "item_name") if item_name_str is not None: item_name: str = item_name_str else: continue # skip this item if it has no name item_quantity_str: str | None = redis_client.hget( f"item_id:{item_id}", "quantity" ) if item_quantity_str is not None: item_quantity: int = int(item_quantity_str) else: item_quantity = 0 items.append( ItemPayload(item_id=item_id, item_name=item_name, quantity=item_quantity) ) return {"items": items} # Route to delete a specific item by ID but using Redis @app.delete("/items/{item_id}") def delete_item(item_id: int) -> dict[str, str]: if not redis_client.hexists(f"item_id:{item_id}", "item_id"): raise HTTPException(status_code=404, detail="Item not found.") else: item_name: str | None = redis_client.hget(f"item_id:{item_id}", "item_name") redis_client.hdel("item_name_to_id", f"{item_name}") redis_client.delete(f"item_id:{item_id}") return {"result": "Item deleted."} # Route to remove some quantity of a specific item by ID but using Redis @app.delete("/items/{item_id}/{quantity}") def remove_quantity(item_id: int, quantity: int) -> dict[str, str]: if not redis_client.hexists(f"item_id:{item_id}", "item_id"): raise HTTPException(status_code=404, detail="Item not found.") item_quantity: str | None = redis_client.hget(f"item_id:{item_id}", "quantity") # if quantity to be removed is higher or equal to item's quantity, delete the item if item_quantity is None: existing_quantity: int = 0 else: existing_quantity: int = int(item_quantity) if existing_quantity <= quantity: item_name: str | None = redis_client.hget(f"item_id:{item_id}", "item_name") redis_client.hdel("item_name_to_id", f"{item_name}") redis_client.delete(f"item_id:{item_id}") return {"result": "Item deleted."} else: redis_client.hincrby(f"item_id:{item_id}", "quantity", -quantity) return {"result": f"{quantity} items removed."}
-
/docs
ルートと対話して、このアプリケーションをテストするためにデバッガーを再実行します。完了したら、デバッガーを停止できます。
おめでとうございます!これで、買い物リストにアイテムを追加、リスト表示、削除するためのルートを持つ、動作する FastAPI アプリケーションが完成し、データは Redis データベースに永続化されました。
オプション: データベース削除をセットアップする
データが Redis によって永続化されるようになったので、すべてのテストデータを消去するスクリプトを作成することをお勧めします。そのためには、以下の内容で flushdb.py
という新しいファイルを作成します。
import redis
redis_client = redis.StrictRedis(host='0.0.0.0', port=6379, db=0, decode_responses=True)
redis_client.flushdb()
データベースをリセットしたいときは、VS Code で flushdb.py
ファイルを開き、エディターの右上隅にある実行ボタンを選択するか、コマンドパレットからPython: ターミナルで Python ファイルを実行コマンドを実行します。
ただし、これは現在のデータベース内のすべてのキーを削除するため、本番環境で行うとデータ損失につながる可能性があるため、注意して行う必要があります。
オプション: ChatGPT プラグインを作成する
GitHub Codespaces を使用すると、ChatGPT プラグインを使用する際に、テスト目的でアプリケーションをホストできます。ChatGPT プラグインは、ChatGPT が既存の API と対話して ChatGPT の能力を強化し、幅広いアクションを実行できるようにするツールです。ChatGPT プラグインは現在一般公開されていませんが、待機リストに参加してアクセスできます。アクセスできたら、以下のライブストリーム録画に従って、ChatGPT 用の独自の買い物リストプラグインを作成できます。
注: すべての個人 GitHub.com アカウントには、Free または Pro プランに含まれる GitHub Codespaces の月額無料使用量があります。詳細については、GitHub Codespaces の課金についてを参照してください。
次のステップ
このチュートリアルをご覧いただきありがとうございます!FastAPI と VS Code でのその使用方法について何か新しいことを学んでいただけたなら幸いです。
このチュートリアルの完成したコードプロジェクトは、GitHub で見つけることができます: python-sample-vscode-fastapi-tutorial。
FastAPI の詳細については、公式ドキュメントを参照してください。
本番ウェブサイトでアプリを試すには、チュートリアル「Docker コンテナーを使用して Python アプリを Azure App Service にデプロイする」を参照してください。
これらの他の VS Code Python 記事も参照できます。