に参加して、VS Code の AI 支援開発について学びましょう。

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

dictionarybased branch selected in the python-sample-vscode-fastapi-tutorial GitHub repo

次に、コード > Codespaces > ブランチで Codespace を作成 を選択して、プロジェクトの Codespace を作成して開きます。

完了したら、以下のデータベースの置き換えセクションに進むことができます。

VS Code でローカルに

VS Code でこのチュートリアルを正常に完了するには、まず Python 開発環境をセットアップする必要があります。具体的には、このチュートリアルでは次のものが必要です。

このセクションでは、VS Code でワークスペースとして開くフォルダーを作成し、Python 仮想環境をセットアップし、プロジェクトの依存関係をインストールします。

  1. ファイルシステムに、このチュートリアル用のプロジェクトフォルダー (例: groceries-plugin) を作成します。

  2. この新しいフォルダーを VS Code で開きます (ファイル > フォルダーを開く…)。

  3. ワークスペースの信頼プロンプトが表示されたら、はい、作者を信頼しますを選択して、ワークスペースが必要なリソースと拡張機能にアクセスできるようにします。ワークスペースの信頼の詳細については、ドキュメントを参照してください。

次に、アプリケーションにインストールする依存関係をリストする requirements.txt ファイルを作成しましょう。requirements.txt ファイルは Python 開発で一般的な慣行であり、プロジェクトが依存するライブラリとそのバージョンを指定するために使用されます。このファイルは、プロジェクトで作業する誰もが同様の開発環境を再現できるようにするのに役立ち、一貫性を維持するための便利なコンポーネントとなります。

アプリを作成するために FastAPI、サーバーとして機能するために uvicorn、データストレージを処理し Redis データベースとやり取りするために Redistype-redis をインストールします。

  1. VS Code で新しいファイルを作成します (ファイル > 新しいテキストファイル または ⌘N (Windows、Linux Ctrl+N))。

  2. 次の内容を追加します。

    fastapi
    redis
    types-redis
    uvicorn
    
  3. ファイルを保存し (⌘S (Windows、Linux Ctrl+S))、requirements.txt と名前を付けます。

  4. コマンドパレットを開き (⇧⌘P (Windows、Linux Ctrl+Shift+P))、Python: 環境を作成 コマンドを実行して仮想環境を作成します。

    : この手順には数分かかる場合があります。

  5. 環境タイプを尋ねられたら、Venv を選択します。

    Dropdown with "Venv" or "Conda" as options for environments that can be created with the Python: Create Environment command

  6. 次に、お使いのコンピューターで利用可能な最新バージョンの Python を選択します。

    List of available global environments that can be used to create a virtual environment

  7. ドロップダウンリストから requirements.txt ファイルを選択すると、依存関係が自動的にインストールされ、OK を選択します。

    Check box selected to install dependencies from requirements.txt file

仮想環境が作成され、依存関係が自動的にインストールされ、Python 拡張機能で使用するためにワークスペースに環境が選択されます。VS Code の右下隅を確認して、選択されていることを確認できます。

Environment in the Status bar

: ステータスバーに新しく作成された環境情報が見つからない場合は、Python インタープリターインジケーターをクリックするか (またはコマンドパレットから Python: インタープリターを選択 コマンドを実行)、仮想環境を手動で選択できます。

コーディングを開始

アプリケーションを作成しましょう!

  1. ファイル > 新しいファイル… を使用して新しい Python ファイルを作成し、Python ファイルを選択します。

  2. groceries-plugin フォルダーに main.py として保存します (⇧⌘S (Windows、Linux Ctrl+Shift+S))。

  3. 次のコードを main.py に追加し、ファイルを保存します。

    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/")
    def root():
        return {"message": "Hello World"}
    
  4. デバッガーを起動してコードを実行します (F5)。

  5. ドロップダウンメニューから、リストから FastAPI 構成オプションを選択します。

    Dropdown with debugger configuration options, with FastAPI being highlighted

    これにより、uvicorn を呼び出してデバッガーを介してアプリケーションサーバーを起動し、ソースコードをステップ実行して動作を検査できるデバッグ構成が自動的に作成されます。ターミナルに次のようなものが表示されます。

    Uvicorn server running message displayed in the terminal, with an URL to access the app

    ヒント: デフォルトのポートがすでに使用されている場合は、デバッガーを停止し、コマンドパレットを開き (⇧⌘P (Windows、Linux Ctrl+Shift+P))、デバッグ: 構成の追加 を検索し、Python デバッガー、次に FastAPI を選択します。これにより、編集可能な .vscode/launch.json にカスタム構成ファイルが作成されます。カスタムポートを設定するには、"args":[]"--port=5000" を追加します。ファイルを保存し、(F5) を使用してデバッガーを再起動します。

  6. ターミナルで http://127.0.0.1:8000/ URL を Ctrl+クリック すると、デフォルトのブラウザーでそのアドレスが開きます。

    Hello World message displayed in the browser

    おめでとうございます!FastAPI アプリが起動して実行されています!

  7. デバッグツールバーの 停止 ボタン、または ⇧F5 (Windows、Linux Shift+F5) を使用してデバッガーを停止します。

買い物リストアイテムのモデルを作成する

FastAPI アプリが動作するようになったので、FastAPI とシームレスに統合されるデータ検証および解析ライブラリである Pydantic を使用して、買い物リストアイテムを定義できます。Pydantic を使用すると、API リクエストで受信するデータ (「ペイロード」と呼ばれる) の自動検証と解析のために、型ヒントを持つ Python クラスを使用してデータモデルを定義できます。

買い物リストアイテムのモデルを作成しましょう。ItemPayload モデルを使用して、買い物リストに追加するアイテムのデータ構造を定義します。このモデルには、item_iditem_namequantity の 3 つのフィールドがあります。

  1. ファイル > 新しいファイル… を使用して新しい Python ファイルを作成し、Python ファイルを選択します。

  2. ファイルに次の行を追加し、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 の型チェック機能を利用して早期にエラーをキャッチできます。

  1. 設定エディターを開きます (⌘, (Windows、Linux Ctrl+,))。

  2. 「python type checking mode」を検索し、基本的な型チェックのために basic に設定します。Pylance は、単純な型関連のエラーをキャッチするための診断と警告を表示するようになります。または、より高度な 型チェックルールを適用するために strict に設定することもできます。

    Python Analysis Type Checking Mode options (off, basic and strict) in Settings editor

  3. 次に、「Python インレイ型ヒント」を検索し、変数型関数戻り値型のインレイヒントを有効にします。

    Two Python Analysis Type Hints settings being enabled in the Settings editor: for Function Return Types and for Variable Types

ルートを作成する

次に、買い物リストのアイテムを保存する場所が必要です。簡単にするために、最初は空の辞書から始めましょう。

  1. まず、サンプルに必要なすべてのパッケージをインポートしましょう。main.py ファイルを開き、最初のインポート行を次の行に置き換えます。

    from fastapi import FastAPI, HTTPException
    
    from models import ItemPayload
    
  2. 次に、app = FastAPI() のすぐ下に次の行を追加します。

    grocery_list: dict[int, ItemPayload] = {}
    

    これにより、型が int (アイテム ID として) のキーと、ItemPayload 型の値を受け取る新しい空の辞書が作成されます。

    次に、FastAPI アプリケーションでルートを定義します。Web アプリケーションのコンテキストでは、ルートは特定の URL をそれらを処理するコードにマッピングする経路のようなものです。これらのルートは、アプリケーション内のさまざまな機能のエントリポイントとして機能します。Web ブラウザーや他のプログラムなどのクライアントが特定の URL でアプリケーションにリクエストを送信すると、FastAPI はそのリクエストを URL に基づいて適切な関数 (ルートハンドラーまたはビュー関数とも呼ばれます) にルーティングし、その関数がリクエストを処理して応答を生成します。

    個々のアイテムを追加および取得し、買い物リスト内のすべてのアイテムを返すルートの定義に進みましょう。

  3. 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 の型を示すインレイヒントを追加していることに気付くかもしれません。必要に応じて、各提案をダブルクリックしてコードに挿入できます。

    Inlay function return and variable type hints being displayed by Pylance throughout the sample code

    次に、このルートが期待どおりに機能しているか確認しましょう。これを行う最も簡単な方法は、VS Code のデバッガーと FastAPI の /docs エンドポイントの両方を使用することです。/docs エンドポイントは、利用可能なすべての API ルートに関する情報を提供し、API と対話してそのパラメーターと応答を探索できます。このドキュメントは、FastAPI アプリケーションで定義されたメタデータと型ヒントに基づいて動的に生成されます。

  4. 行番号の左余白をクリックするか (F9)、if quantity <= 0 ステートメントの横にブレークポイントを設定します。デバッガーはその行の実行前に停止するため、コードを1行ずつ検査できます。

    Breakpoint set next to the first line in the add_item function

  5. デバッガーを起動し (F5)、ブラウザーで http://127.0.0.1:8000/docs に移動します。

    アプリで利用可能な2つのエンドポイント (/items とルート (/)) を持つ Swagger インターフェースが表示されるはずです。

    Swagger UI displaying two endpoints: /items and /

  6. /items ルートの横にある下矢印を選択して展開し、右側に表示される 試してみる ボタンを選択します。

    "Try it out" button displayed next to the /items route in the Swagger UI

  7. item_name フィールドに文字列を、quantity に数値を渡して買い物リストアイテムを追加します。たとえば、item_name に apple、quantity に 2 を指定できます。

  8. 実行 を選択します。

    Execute button displayed below the /items route

  9. VS Code を再度開き、デバッガーが以前に設定したブレークポイントで停止していることに注意してください。

    Debugger stopped at the breakpoint set in the add_item function

    左側には、実行とデバッグ ビューの下にある変数ウィンドウに、この時点で定義されているすべてのローカル変数とグローバル変数が表示されます。私たちの例では、ローカル変数ビューの下で item_name が 'apple' に、quantity が 2 に設定されており、グローバル変数ビューの下には空の grocery_list 辞書があります。

    Variables window displayed in the Run and Debug view, with the item and grocery_list variables highlighted

    次に、VS Code のデバッグコンソールを使用して探索してみましょう。

  10. quantity <= 0 ステートメントを選択し、エディターを右クリックして デバッグコンソールで評価 を選択します。

    Evaluate in Debug Console option displayed in the context menu when right-clicking on a line of code

    これにより、デバッグコンソールが開き、選択した式が実行されます。私たちの例では、期待どおりに式は False と評価されます。

    デバッグコンソールは、式をすばやくテストし、ブレークポイント時のコードの状態をよりよく理解するための強力なツールとなり得ます。関数呼び出しや変数の出力など、任意のコードを実行することもできます。VS Code での Python デバッグの詳細については、Python チュートリアルを参照してください。

    デバッグビューツールバーの 続行 を選択するか、F5 を押してコードの実行を続行できます。

    最後に、アプリケーションの残りのルートを追加して、すべてのアイテムまたは特定のアイテムをリストしたり、買い物リストから削除したりできるようにします。次のステップで行う変更を保存すると、アプリケーションが自動的に再読み込みされるため、デバッガーを実行したままにすることができます。

  11. 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."}
    
    
  12. ファイルを保存します (⌘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 のコンテナ内 (またはコンテナにマウントされた状態) で開くことができ、そのすべての機能を利用できます。

以下の手順を実行するには、お使いのマシンに次の要件がインストールされていることを確認してください。

要件

開発コンテナ構成を作成する

  1. コマンドパレットを開き、開発コンテナ: 開発コンテナ構成ファイルの追加… を実行します。

  2. Python 3 を選択します。

    Python 3 option selected in the Dev Containers configuration files list

  3. デフォルトバージョンを選択します。

  4. 追加機能として Redis Server を選択し、OK を押してから Keep Defaults を選択します。

    オプションで、コンテナに含める フィーチャー をインストールできます。このチュートリアルでは、Redis の適切な開発コンテナセットアップをインストールして追加する、コミュニティが提供するフィーチャーである Redis Server をインストールします。

    Redis Server option selected in the Dev Containers configuration files list

    これにより、ワークスペースに .devcontainer フォルダーが作成され、その中に devcontainer.json ファイルが作成されます。コンテナのセットアップに、必要な VS Code 拡張機能やプロジェクトの依存関係のインストールなどの手順が含まれるように、このファイルを編集しましょう。

  5. devcontainer.json ファイルを開きます。

  6. "features" : { ... } エントリの後に「,」を追加して、ファイルにさらに設定を追加できるようにします。

    次に、必要な依存関係インストールコマンドを devcontainer.json ファイルの postCreateCommand プロパティに追加します。これにより、コンテナがセットアップされたらすぐにアプリケーションを実行できるようになります。

  7. 以下の内容を見つけて、その行からコメント (//) を削除すると、コンテナが作成されたらすぐに依存関係がインストールされます。

    "postCreateCommand": "pip3 install --user -r requirements.txt",
    

    postCreateCommand およびその他のライフサイクルスクリプトの詳細については、開発コンテナ仕様を参照してください。

    次に、customizations プロパティを使用して、コンテナーにインストールする VS Code 拡張機能を追加します。

  8. 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
                ]
            }
        }
    
  9. ファイルを保存します。

  10. 右下隅に表示される通知から コンテナーで再度開く を選択するか、コマンドパレットから Dev Containers: コンテナーで再度開く コマンドを実行します。

    : コンテナーの構築には、インターネット速度とマシンのパフォーマンスに応じて、数分かかる場合があります。

    開発コンテナ構成の詳細については、開発コンテナのドキュメントを参照してください。

完了すると、Python 3 と Redis Server がインストールされた、完全に構成された Linux ベースのワークスペースが利用できます。

コンテナがセットアップされると、VS Code の左下隅にインジケーターが表示されます。

Dev Containers indicator displayed on the bottom left corner of VS Code

: 拡張機能ビュー (⇧⌘X (Windows、Linux Ctrl+Shift+X)) を開いて検索し、Python および Pylance 拡張機能がコンテナーに正常にインストールされていることを再確認してください。インストールされていない場合は、Dev Container にインストール を実行してインストールできます。

選択された Python インタープリター情報は、ステータスバーの右下隅に表示され、devcontainer.json ファイルで指定されたバージョンと一致します。

Python interpreter selection

: ステータスバーに Python インタープリター情報が見つからない場合は、Python インタープリターインジケーターをクリックするか (またはコマンドパレットから Python: インタープリターを選択 コマンドを実行)、コンテナー内の Python インタープリターを手動で選択できます。

これで、データストレージを置き換える次のセクションに進む準備ができました。

データベースの置き換え

買い物リストのアイテムを保存する辞書がありますが、それを Redis データベースに置き換えたいと考えています。このチュートリアルでは、複数のキーと値のペアを保存できるデータ構造である Redis ハッシュを使用してデータを保存します。

従来のデータベースとは異なり、ID を知らなくてもアイテムを取得できますが、Redis ハッシュキーを知っている必要があります。このチュートリアルでは、アイテムを名前で取得するための item_name_to_id というハッシュを作成し、それらを ID にマッピングします。さらに、ID でアイテムを取得するための他のハッシュを作成し、それらを名前と数量にマッピングします。各アイテムハッシュは item_id:{item_id} と命名され、item_namequantity の2つのフィールドを持っています。

まず、辞書を Redis サーバーに接続する Redis クライアントオブジェクトに置き換えることから始めましょう。

  1. 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 はエラーメッセージを表示します。

  2. エディターで「redis」にカーソルを置き、表示される電球をクリックします (⌘. (Windows、Linux Ctrl+.))。次に 'import redis' を追加 を選択します。

    Light bulb displayed next to the Redis variable, with the option to add the import statement

    ヒント: 設定エディター (⌘, (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 が返されます。

  3. 以下の内容の行を削除します。

    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_idint 型であることを期待しています。この警告に対処するために、item_id シンボルをリネームしましょう。

  4. item_iditem_id_str にリネームします。

  5. インレイヒントを有効にしている場合、Pylance は item_id_str の横に変数型ヒントを表示するはずです。必要に応じて、ダブルクリックして受け入れることができます。

    Variable type hint displayed next to the item_id_str variable

  6. アイテムが存在しない場合、item_id_strNone になります。したがって、次の内容の行を削除できます。

    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_namequantity フィールドを追加します。

  7. if ブロック内のコードを削除します。

    item_id: int = items_ids[item_name]
    grocery_list[item_id].quantity += quantity
    

    そして、次の内容を追加して、item_idint に変換し、Redis の hincrby メソッドを呼び出してアイテムの数量を増分します。このメソッドは、要求 (quantity) で指定された量だけ「quantity」フィールドの値を増分します。

    item_id = int(item_id_str)
    redis_client.hincrby(f"item_id:{item_id}", "quantity", quantity)
    

    これで、item_id_strNone である場合の、アイテムが存在しない場合のコードを置き換えるだけです。この場合、新しい item_id を生成し、アイテムの新しい Redis ハッシュを作成し、提供されたアイテム名と数量を追加します。

    新しい item_id を生成するために、Redis の incr メソッドを使用し、"item_ids" と呼ばれる新しいハッシュを渡します。このハッシュは、最後に生成された ID を保存するために使用され、新しいアイテムを作成するたびにそれをインクリメントして、すべてがユニークな ID を持つようにします。

  8. 以下の内容の行を削除します。

    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_iditem_namequantity) と値 (新しく作成されたアイテムの ID、および提供された名前と数量) のマッピングを提供して、アイテムを Redis ハッシュに追加します。

  9. 以下の内容の行を削除します。

    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 を設定して、アイテム名にマッピングするだけです。

  10. この行をルートの末尾、else ブロック内に追加します。

    redis_client.hset("item_name_to_id", item_name, item_id)
    
  11. 以下の内容の行を削除します。

    return {"item": grocery_list[item_id]}
    

    そして、次のように置き換えます。

    return {"item": ItemPayload(item_id=item_id, item_name=item_name, quantity=quantity)}
    
  12. よろしければ、他のルートでも同様の置換を試すことができます。そうでなければ、ファイルのすべての内容を以下の行に置き換えるだけです。

    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."}
    
    
  13. デバッガーを再実行して、/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 記事も参照できます。

© . This site is unofficial and not affiliated with Microsoft.