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 ブランチを選択してください。

次に、コード > Codespaces >
完了したら、以下のデータベースの置き換えセクションに進むことができます。
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 を使用すると、API リクエストで受信するデータ (「ペイロード」と呼ばれる) の自動検証と解析のために、型ヒントを持つ Python クラスを使用してデータモデルを定義できます。
買い物リストアイテムのモデルを作成しましょう。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 が Pyright (コード内の型エラーを検出してバグを防止し、コード品質を向上させることができる Python 用の静的型チェッカー) の上に構築されているためです。
以下の 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エンドポイントの両方を使用することです。/docsエンドポイントは、利用可能なすべての API ルートに関する情報を提供し、API と対話してそのパラメーターと応答を探索できます。このドキュメントは、FastAPI アプリケーションで定義されたメタデータと型ヒントに基づいて動的に生成されます。 -
行番号の左余白をクリックするか (F9)、
if quantity <= 0ステートメントの横にブレークポイントを設定します。デバッガーはその行の実行前に停止するため、コードを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 をお使いの場合、Redis は Docker コンテナ または GitHub Codespace を設定することで利用できます。このチュートリアルでは Docker コンテナを使用しますが、GitHub Codespace の設定方法については上記のセクションを参照してください。
それ以外の場合、Linux または macOS マシンをお使いの場合は、ウェブサイトの指示に従って Redis をインストールし、データベースの置き換え セクションに進んでください。
Windows で Docker コンテナをセットアップする
VS Code の 開発コンテナ 拡張機能は、プロジェクト、その依存関係、および必要なすべてのツールを1つの整理されたコンテナに統合し、フル機能の開発環境を作成する合理化されたアプローチを提供します。この拡張機能を使用すると、プロジェクトを VS Code のコンテナ内 (またはコンテナにマウントされた状態) で開くことができ、そのすべての機能を利用できます。
以下の手順を実行するには、お使いのマシンに次の要件がインストールされていることを確認してください。
要件
- Windows 用 Docker
- 開発コンテナ 拡張機能
開発コンテナ構成を作成する
-
コマンドパレットを開き、開発コンテナ: 開発コンテナ構成ファイルの追加… を実行します。
-
Python 3 を選択します。

-
デフォルトバージョンを選択します。
-
追加機能として Redis Server を選択し、OK を押してから Keep Defaults を選択します。
オプションで、コンテナに含める フィーチャー をインストールできます。このチュートリアルでは、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 拡張機能がコンテナーに正常にインストールされていることを再確認してください。インストールされていない場合は、Dev Container にインストール を実行してインストールできます。
選択された Python インタープリター情報は、ステータスバーの右下隅に表示され、devcontainer.json ファイルで指定されたバージョンと一致します。

注: ステータスバーに Python インタープリター情報が見つからない場合は、Python インタープリターインジケーターをクリックするか (またはコマンドパレットから Python: インタープリターを選択 コマンドを実行)、コンテナー内の Python インタープリターを手動で選択できます。
これで、データストレージを置き換える次のセクションに進む準備ができました。
データベースの置き換え
買い物リストのアイテムを保存する辞書がありますが、それを Redis データベースに置き換えたいと考えています。このチュートリアルでは、複数のキーと値のペアを保存できるデータ構造である Redis ハッシュを使用してデータを保存します。
従来のデータベースとは異なり、ID を知らなくてもアイテムを取得できますが、Redis ハッシュキーを知っている必要があります。このチュートリアルでは、アイテムを名前で取得するための item_name_to_id というハッシュを作成し、それらを 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ハッシュを作成し、IDによる取得を容易にするためにハッシュ名として"item_id:{item_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) と値 (新しく作成されたアイテムの 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, })次に、新しく作成された ID を、最初に参照したハッシュ
item_name_to_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ルートと対話することでこのアプリケーションをテストします。完了したら、デバッガーを停止できます。
おめでとうございます!買い物リストにアイテムを追加、リスト、削除するルートを持ち、データが Redis データベースに永続化される、動作する FastAPI アプリケーションができました。
オプション: データベース削除のセットアップ
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 ファイルを実行 コマンドを実行します。
これは、現在のデータベース内のすべてのキーを削除するため、注意して行う必要があります。本番環境で行うとデータ損失につながる可能性があります。
オプション: GPT アクションを作成する
GitHub Codespaces を使用すると、GPT アクションを使用する際に、テスト目的でアプリケーションをホストできます。GPT アクションは、ChatGPT が既存の API と連携して 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 記事も参照できます。