Pydantic Settingsで設定を階層化!複雑なFastAPIアプリケーションを管理する
2025-03-21
Pydantic Settingsとは?
FastAPIアプリケーションの設定管理を容易にするための仕組みです。Pydanticはデータ検証と設定管理のためのライブラリであり、FastAPIと組み合わせることで、環境変数や設定ファイルから設定値を読み込み、型安全な方法で利用できるようになります。
主な機能と利点
- 設定値のドキュメント化
Pydanticモデルのスキーマを自動的に生成できるため、設定値のドキュメントを簡単に作成できます。 - 開発と本番環境の分離
環境変数や設定ファイルを使い分けることで、開発環境と本番環境で異なる設定を適用できます。 - 設定値の階層化
ネストされたPydanticモデルを使用することで、複雑な設定を階層的に管理できます。 - 設定値の検証
Pydanticモデルのバリデーション機能により、設定値が期待される範囲や形式であることを検証できます。 - 環境変数と設定ファイルのサポート
環境変数、.env
ファイル、JSON、YAMLなどの設定ファイルから設定値を読み込むことができます。 - 型安全な設定
設定値をPydanticモデルで定義することで、型チェックが自動的に行われます。これにより、設定値の型の間違いによる実行時エラーを防ぎます。
使い方
-
- 設定値を格納するためのPydanticモデルを作成します。
- 各設定値の型とデフォルト値を定義します。
Settings
クラスを継承します。
-
設定値の読み込み
Settings
クラスのインスタンスを作成すると、環境変数や設定ファイルから設定値が自動的に読み込まれます。- 設定値はモデルの属性としてアクセスできます。
-
FastAPIでの利用
- 作成した設定モデルのインスタンスをFastAPIアプリケーションの依存性としてインジェクトします。
- ルーティング関数内で設定値を利用します。
コード例
from fastapi import FastAPI, Depends
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "My FastAPI App"
database_url: str = "sqlite:///./test.db"
debug: bool = False
class Config:
env_file = ".env"
def get_settings():
return Settings()
app = FastAPI()
@app.get("/info")
async def read_info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"database_url": settings.database_url,
"debug": settings.debug,
}
この例では、Settings
モデルを定義し、app_name
、database_url
、debug
の3つの設定値を定義しています。Config
クラスで.env
ファイルを指定することで、環境変数に加えて.env
ファイルからも設定値を読み込むことができます。get_settings
関数でSettings
インスタンスを生成し、FastAPIの依存性としてインジェクトしています。ルーティング関数read_info
では、インジェクトされた設定値を利用してレスポンスを生成しています。
一般的なエラーとトラブルシューティング
-
- エラー
環境変数が正しく設定されていない、または.env
ファイルのパスが間違っている。 - トラブルシューティング
- 環境変数が正しく設定されているか確認します。
print(os.environ)
などで確認できます。 .env
ファイルのパスがSettings
クラスのConfig
のenv_file
で正しく指定されているか確認します。相対パス、絶対パスに注意してください。.env
ファイルがアプリケーションの実行ディレクトリに存在することを確認します。.env
ファイル内の変数のスペルミスや形式(KEY=VALUE
)を確認します。.env
ファイルが正しく読み込まれているかを確認するために、読み込み後に設定値を出力してみます。
- 環境変数が正しく設定されているか確認します。
- エラー
-
型検証エラー
- エラー
環境変数や設定ファイルの値が、Pydanticモデルで定義された型と一致しない。 - トラブルシューティング
- エラーメッセージをよく読み、どの設定値で型エラーが発生しているかを確認します。
- 設定値の型がPydanticモデルで定義された型と一致しているか確認します。
- 必要に応じて、型変換やバリデーションを追加します。
- 特にbool値は文字列として読み込まれることがあるので、
strtobool
などを使用してbool値に変換することを検討してください。
- エラー
-
設定値のデフォルト値が適用されない
- エラー
環境変数や設定ファイルで値が指定されていない場合に、デフォルト値が適用されない。 - トラブルシューティング
- Pydanticモデルでデフォルト値が正しく定義されているか確認します。
- 環境変数や設定ファイルで値が設定されていないか確認します。
- 設定値の優先順位(環境変数 >
.env
ファイル > デフォルト値)を理解しておきます。
- エラー
-
設定値の階層構造のエラー
- エラー
ネストされたPydanticモデルで設定値を管理する際に、構造が正しくない。 - トラブルシューティング
- ネストされたPydanticモデルの定義を確認し、構造が正しいか確認します。
- 設定ファイル(JSON、YAMLなど)の構造が、ネストされたPydanticモデルの構造と一致しているか確認します。
- エラー
-
Configクラスの誤用
- エラー
Config
クラスの属性を誤って設定している。 - トラブルシューティング
Config
クラスのドキュメントを参照し、属性の正しい使い方を確認します。- よく使う
env_file
、env_prefix
、case_sensitive
などの属性の設定を確認します。
- エラー
-
設定値の遅延評価(Lazy Loading)
- エラー
設定値がアプリケーションの起動時に読み込まれない。 - トラブルシューティング
Settings
クラスのインスタンスが、設定値を使用する前に作成されているか確認します。- 依存性インジェクションを使用している場合、依存性が正しく解決されているか確認します。
- エラー
-
Docker環境でのエラー
- エラー
Dockerコンテナ内で環境変数が正しく設定されていない。 - トラブルシューティング
- Dockerコンテナの起動時に、環境変数を正しく設定しているか確認します。
-e
オプションや--env-file
オプションを使用します。 - Docker Composeを使用している場合、
environment
セクションで環境変数を設定します。 - Dockerコンテナ内で環境変数を確認します。
docker exec <container_id> printenv
などを使用します。
- Dockerコンテナの起動時に、環境変数を正しく設定しているか確認します。
- エラー
デバッグのヒント
- シンプルな設定で動作確認を行い、徐々に複雑な設定を追加していくことで、エラーの原因を特定しやすくなります。
- ログ出力を有効にし、設定値の読み込みや検証の過程を追跡します。
- エラーメッセージをよく読み、どの設定値でエラーが発生しているかを確認します。
- 設定値を読み込んだ後に、
print(settings.dict())
などで設定値の内容を出力して確認します。
基本的な例:環境変数と.envファイルの利用
from fastapi import FastAPI, Depends
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "デフォルトアプリ名"
database_url: str = "sqlite:///./default.db"
debug: bool = False
class Config:
env_file = ".env" # .envファイルを読み込む
def get_settings():
return Settings()
app = FastAPI()
@app.get("/info")
async def read_info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"database_url": settings.database_url,
"debug": settings.debug,
}
- 実行
.env
ファイルを作成し、上記の例のように設定します。- FastAPIアプリケーションを実行します。
/info
エンドポイントにアクセスすると、.env
ファイルの設定が適用された結果が表示されます。
- .envファイルの例
APP_NAME="カスタムアプリ名" DATABASE_URL="postgresql://user:password@host:port/database" DEBUG=True
- 説明
Settings
クラスは設定値を定義します。app_name
,database_url
,debug
は設定値の変数です。class Config: env_file = ".env"
で.env
ファイルを読み込みます。get_settings()
関数はSettings
のインスタンスを作成し、依存性として提供します。/info
エンドポイントは設定値を返します。
設定値のプレフィックスとケースセンシティブの設定
from fastapi import FastAPI, Depends
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "デフォルトアプリ名"
database_url: str = "sqlite:///./default.db"
debug: bool = False
class Config:
env_prefix = "MY_APP_" # 環境変数のプレフィックスを設定
case_sensitive = False #環境変数の大文字小文字を区別しない
def get_settings():
return Settings()
app = FastAPI()
@app.get("/info")
async def read_info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"database_url": settings.database_url,
"debug": settings.debug,
}
- 環境変数の例
MY_APP_APP_NAME="プレフィックス付きアプリ名" MY_APP_DATABASE_URL="mongodb://user:password@host:port/database" MY_APP_DEBUG=true
- 説明
env_prefix = "MY_APP_"
で環境変数のプレフィックスを設定します。例えば、MY_APP_APP_NAME
という環境変数が読み込まれます。case_sensitive = False
で環境変数の大文字小文字を区別しないようにします。MY_APP_app_name
もMY_APP_APP_NAME
として読み込まれます。
ネストされた設定
from fastapi import FastAPI, Depends
from pydantic import BaseSettings, BaseModel
class DatabaseSettings(BaseModel):
url: str
port: int
class Settings(BaseSettings):
app_name: str = "デフォルトアプリ名"
database: DatabaseSettings
debug: bool = False
class Config:
env_nested_delimiter = "__" #ネストされた設定を環境変数で表現する際区切り文字の設定
def get_settings():
return Settings()
app = FastAPI()
@app.get("/info")
async def read_info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"database_url": settings.database.url,
"database_port": settings.database.port,
"debug": settings.debug,
}
- 環境変数の例
APP_NAME="ネストされた設定アプリ" DATABASE__URL="mysql://user:password@host" DATABASE__PORT=3306 DEBUG=false
- 説明
DatabaseSettings
モデルはデータベースの設定を定義します。Settings
モデルはDatabaseSettings
モデルをネストして使用します。env_nested_delimiter = "__"
でネストされた設定を環境変数で表現する際の区切り文字を設定します。
import json
from fastapi import FastAPI, Depends
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str
database_url: str
debug: bool
class Config:
json_file = "config.json" #jsonファイルからの設定
def get_settings():
return Settings()
app = FastAPI()
@app.get("/info")
async def read_info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"database_url": settings.database_url,
"debug": settings.debug,
}
- config.jsonファイルの例
{ "app_name": "JSON設定アプリ", "database_url": "redis://host:port/database", "debug": true }
- 説明
json_file = "config.json"
でconfig.json
ファイルを読み込みます。
環境変数のみを使用する
- 例
- 欠点
型チェックやバリデーションを手動で行う必要があり、設定の階層化が難しい。.env
ファイルのサポートも自分で実装する必要があります。 - 利点
シンプルで、外部ライブラリへの依存が少ない。 - 方法
Pydantic Settingsを使用せず、os.environ
を使用して環境変数を直接読み込みます。
import os
from fastapi import FastAPI
app = FastAPI()
@app.get("/info")
async def read_info():
app_name = os.environ.get("APP_NAME", "デフォルトアプリ名")
database_url = os.environ.get("DATABASE_URL", "sqlite:///./default.db")
debug = os.environ.get("DEBUG", "False").lower() == "true" #bool値の変換
return {
"app_name": app_name,
"database_url": database_url,
"debug": debug,
}
Pythonの標準ライブラリconfigparserを使用する
- 例
- 欠点
型チェックやバリデーションを手動で行う必要があり、複雑なデータ構造の表現が難しい。 - 利点
構造化された設定ファイルを扱えます。 - 方法
INI形式の設定ファイルを読み込むためにconfigparser
を使用します。
import configparser
from fastapi import FastAPI
app = FastAPI()
@app.get("/info")
async def read_info():
config = configparser.ConfigParser()
config.read("config.ini")
app_name = config.get("DEFAULT", "APP_NAME", fallback="デフォルトアプリ名")
database_url = config.get("DATABASE", "URL", fallback="sqlite:///./default.db")
debug = config.getboolean("DEFAULT", "DEBUG", fallback=False)
return {
"app_name": app_name,
"database_url": database_url,
"debug": debug,
}
- config.iniの例
[DEFAULT]
APP_NAME = カスタムアプリ名
DEBUG = True
[DATABASE]
URL = postgresql://user:password@host:port/database
YAMLまたはJSONファイルを直接読み込む
- 例 (YAML)
- 欠点
型チェックやバリデーションを手動で行う必要があり、設定の階層化を自分で実装する必要があります。 - 利点
複雑なデータ構造を扱えます。 - 方法
PyYAML
やjson
ライブラリを使用して、YAMLまたはJSONファイルを直接読み込みます。
import yaml
from fastapi import FastAPI
app = FastAPI()
@app.get("/info")
async def read_info():
with open("config.yaml", "r") as f:
config = yaml.safe_load(f)
app_name = config.get("app_name", "デフォルトアプリ名")
database_url = config.get("database", {}).get("url", "sqlite:///./default.db")
debug = config.get("debug", False)
return {
"app_name": app_name,
"database_url": database_url,
"debug": debug,
}
- config.yamlの例
app_name: カスタムアプリ名
database:
url: mongodb://user:password@host:port/database
debug: true
独自の設定管理クラスを作成する
- 例
(省略) - 欠点
実装に時間がかかり、メンテナンスが大変になる可能性があります。 - 利点
柔軟性が高く、特定の要件に合わせてカスタマイズできます。 - 方法
設定の読み込み、検証、管理を行う独自のクラスを作成します。
環境変数と設定ファイルを組み合わせる
- 例
(省略) - 欠点
組み合わせる方法を自分で実装する必要があります。 - 利点
環境変数で設定を上書きできるため、柔軟性が高い。 - 方法
環境変数を優先し、設定ファイルでデフォルト値を定義します。
- ドキュメント化
設定値のドキュメントを手動で作成する必要があります。 - エラー処理
設定ファイルの読み込みや環境変数の取得でエラーが発生した場合、適切なエラー処理を行う必要があります。 - 設定の階層化
複雑な設定を管理する場合、自分で階層構造を実装する必要があります。 - 型チェックとバリデーション
手動で型チェックとバリデーションを行う必要があります。