Skip to main content

A simple response bandwidth limiting extension for FastAPI and Starlette

Project description

Response Bandwidth Limiter

FastAPIとStarlette用のレスポンス帯域制限ミドルウェア。特定のエンドポイントのレスポンス送信速度を制限することができます。

インストール

pipを使用してインストールできます:

pip install response-bandwidth-limiter

依存関係

このライブラリは最小限の依存関係で動作しますが、実際の使用にはFastAPIまたはStarletteが必要です。 必要に応じて以下のようにインストールしてください:

# FastAPIと一緒に使用する場合
pip install fastapi

# Starletteと一緒に使用する場合
pip install starlette

# 開発やテストに必要な依存関係を含める場合
pip install response-bandwidth-limiter[dev]

基本的な使い方

デコレータを使った方法(推奨)

from fastapi import FastAPI, Request
from starlette.responses import FileResponse
from response_bandwidth_limiter import ResponseBandwidthLimiter, ResponseBandwidthLimitExceeded, _response_bandwidth_limit_exceeded_handler

# リミッターの初期化
limiter = ResponseBandwidthLimiter()
app = FastAPI()

# アプリケーションに登録
app.state.response_bandwidth_limiter = limiter
app.add_exception_handler(ResponseBandwidthLimitExceeded, _response_bandwidth_limit_exceeded_handler)

# エンドポイントのレスポンス帯域制限(1024 bytes/sec)
@app.get("/download")
@limiter.limit(1024)  # 1024 bytes/sec
async def download_file(request: Request):
    return FileResponse("path/to/large_file.txt")

# 別のエンドポイントに別の制限(2048 bytes/sec)
@app.get("/video")
@limiter.limit(2048)  # 2048 bytes/sec
async def stream_video(request: Request):
    return FileResponse("path/to/video.mp4")

Starletteでの使用例

from starlette.applications import Starlette
from starlette.responses import FileResponse
from starlette.routing import Route
from response_bandwidth_limiter import ResponseBandwidthLimiter

# デコレータ方式
limiter = ResponseBandwidthLimiter()

async def download_file(request):
    return FileResponse("path/to/large_file.txt")

# デコレータを適用
download_with_limit = limiter.limit(1024)(download_file)

# ルートを定義
routes = [
    Route("/download", endpoint=download_with_limit)
]

app = Starlette(routes=routes)

# リミッターをアプリに登録
limiter.init_app(app)

高度な使用例

デコレータを使った帯域制限の設定(シンプルなケース)

シンプルに帯域制限を設定する場合は、set_response_bandwidth_limitデコレータを使用できます:

from fastapi import FastAPI
from starlette.responses import FileResponse
from response_bandwidth_limiter import set_response_bandwidth_limit

app = FastAPI()

@app.get("/download")
@set_response_bandwidth_limit(1024)  # 1024 bytes/sec
async def download_file():
    return FileResponse("path/to/large_file.txt")

この方法では、ResponseBandwidthLimiterクラスを初期化せずに、直接エンドポイントに帯域制限を設定できます。 さらに、このデコレータを使用する場合は、ミドルウェアを明示的に追加する必要があります:

from response_bandwidth_limiter import ResponseBandwidthLimiterMiddleware

app = FastAPI()
app.add_middleware(ResponseBandwidthLimiterMiddleware)

@app.get("/download")
@set_response_bandwidth_limit(1024)
async def download_file():
    return FileResponse("path/to/large_file.txt")

このシンプルなデコレータはグローバルな設定を使用するため、複数のアプリケーションで同じ関数名を使用する場合は注意してください。より複雑なシナリオでは、ResponseBandwidthLimiterクラスを使用するアプローチが推奨されます。

シンプルデコレータと標準デコレータの違い

シンプルデコレータ (set_response_bandwidth_limit) と標準デコレータ (ResponseBandwidthLimiter.limit) の主な違い:

  1. シンプルデコレータ:

    • グローバルな設定を使用
    • アプリインスタンスに依存しない
    • 複数アプリで同名の関数を使うと競合する可能性あり
    • 設定が簡単
  2. 標準デコレータ:

    • アプリインスタンスごとに分離された設定
    • 複数のアプリで安全に使用可能
    • より明示的な初期化が必要
    • 大規模アプリに適している

両方のデコレータを併用する

同じアプリ内で両方のデコレータを使用することもできます:

from fastapi import FastAPI, Request
from response_bandwidth_limiter import (
    ResponseBandwidthLimiter,
    set_response_bandwidth_limit,
    ResponseBandwidthLimiterMiddleware
)

app = FastAPI()
limiter = ResponseBandwidthLimiter()
app.state.response_bandwidth_limiter = limiter

# ミドルウェアは一度だけ追加
app.add_middleware(ResponseBandwidthLimiterMiddleware)

# 標準デコレータの使用例
@app.get("/video")
@limiter.limit(2048)
async def stream_video(request: Request):
    # ...

# シンプルデコレータの使用例
@app.get("/download")
@set_response_bandwidth_limit(1024)
async def download_file(request: Request):
    # ...

動的な帯域制限

実行時に帯域制限を変更したい場合:

limiter = ResponseBandwidthLimiter()
app = FastAPI()
app.state.response_bandwidth_limiter = limiter

@app.get("/admin/set-limit")
async def set_limit(endpoint: str, limit: int):
    limiter.routes[endpoint] = limit
    return {"status": "success", "endpoint": endpoint, "limit": limit}

重要な注意点: 帯域制限の変更は永続的です。一度エンドポイントの帯域制限を変更すると、その変更はサーバーが再起動されるまで保持され、次回以降のすべてのリクエストに適用されます。一時的な変更ではなく、設定の更新として扱われます。

例えば、あるエンドポイントの制限を1000 bytes/secから2000 bytes/secに変更した場合、それ以降のすべてのリクエストは2000 bytes/secの制限で処理されます。元の速度に戻す場合は、明示的に再設定する必要があります。

特定のユーザーやIPに対する帯域制限

@app.get("/download/{user_id}")
@limiter.limit(1024)
async def download_for_user(request: Request, user_id: str):
    # ユーザーごとに異なる制限を適用したい場合は、
    # ここでカスタム処理を行うことができます
    user_limits = {
        "premium": 5120,
        "basic": 1024
    }
    user_type = get_user_type(user_id)
    actual_limit = user_limits.get(user_type, 512)
    # ...レスポンス処理

制限事項と注意点

  • 帯域制限はサーバーサイドで適用されるため、クライアント側の帯域幅やネットワーク状況によっては、実際の転送速度が変わる場合があります。
  • 大きなファイル転送の場合は、メモリ使用量に注意してください。
  • 分散システムの場合、各サーバーごとに制限が適用されます。

APIリファレンス

このセクションでは、ライブラリが提供する主なクラスとメソッドの詳細なリファレンスを提供します。

ResponseBandwidthLimiter

レスポンス帯域制限の機能を提供するメインクラスです。

class ResponseBandwidthLimiter:
    def __init__(self, key_func=None):
        """
        レスポンス帯域幅制限機能を初期化します
        
        引数:
            key_func: 将来的な拡張用のキー関数(現在は使用されていません)
        """
        
    def limit(self, rate: int):
        """
        エンドポイントに対して帯域制限を適用するデコレータを返します
        
        引数:
            rate: 制限する速度(bytes/sec)
            
        戻り値:
            デコレータ関数
            
        例外:
            TypeError: rateが整数でない場合
        """
        
    def init_app(self, app):
        """
        FastAPIまたはStarletteアプリケーションにリミッターを登録します
        
        引数:
            app: FastAPIまたはStarletteアプリケーションインスタンス
        """

ResponseBandwidthLimiterMiddleware

FastAPIおよびStarlette用のミドルウェアで、帯域制限を実際に適用します。

class ResponseBandwidthLimiterMiddleware(BaseHTTPMiddleware):
    def __init__(self, app):
        """
        帯域制限ミドルウェアを初期化します
        
        引数:
            app: FastAPIまたはStarletteアプリケーション
        """
        
    def get_handler_name(self, request, path):
        """
        パスに一致するハンドラー名を取得します
        
        引数:
            request: リクエストオブジェクト
            path: リクエストパス
            
        戻り値:
            str または None: エンドポイント名(存在する場合)
        """
        
    async def dispatch(self, request, call_next):
        """
        リクエストに対して帯域制限を適用します
        
        引数:
            request: リクエストオブジェクト
            call_next: 次のミドルウェア関数
            
        戻り値:
            レスポンスオブジェクト
        """

set_response_bandwidth_limit

シンプルな帯域制限デコレータです。

def set_response_bandwidth_limit(limit: int):
    """
    エンドポイントごとに帯域制限を設定するシンプルなデコレータ
    
    引数:
        limit: 制限する速度(bytes/sec)
        
    戻り値:
        デコレータ関数
    """

ResponseBandwidthLimitExceeded

帯域制限超過時に発生する例外です。

class ResponseBandwidthLimitExceeded(Exception):
    """
    帯域幅の制限を超過した場合に発生する例外
    
    引数:
        limit: 制限値(bytes/sec)
        endpoint: 制限が適用されたエンドポイント名
    """

エラーハンドラ

async def _response_bandwidth_limit_exceeded_handler(request, exc):
    """
    帯域幅制限超過時のエラーハンドラー
    
    引数:
        request: リクエストオブジェクト
        exc: ResponseBandwidthLimitExceeded例外
        
    戻り値:
        JSONResponse: HTTPステータスコード429と説明
    """

ユーティリティ関数

def get_endpoint_name(request):
    """
    リクエストからエンドポイント名を取得します
    
    引数:
        request: リクエストオブジェクト
    
    戻り値:
        str: エンドポイント名
    """
    
def get_route_path(request):
    """
    リクエストからルートパスを取得します
    
    引数:
        request: リクエストオブジェクト
        
    戻り値:
        str: ルートパス
    """

謝辞

このライブラリは slowapi (MIT Licensed) にインスパイアされました。

ライセンス

MPL-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

response_bandwidth_limiter-0.1.0.tar.gz (20.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

response_bandwidth_limiter-0.1.0-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file response_bandwidth_limiter-0.1.0.tar.gz.

File metadata

File hashes

Hashes for response_bandwidth_limiter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bef52affc7bd7f0d359d1f7f4d099c89b1e1fcf3fdc7b49eaada8dabf994713b
MD5 f6fa37ec75e4018cad6d6ed4d57e86d4
BLAKE2b-256 d7924561fe5381cca966e69fbf92a10cc997a26811c230935dd75fc17c3bca68

See more details on using hashes here.

File details

Details for the file response_bandwidth_limiter-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for response_bandwidth_limiter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ff58d4cddd7258391852ce07a73f991e22a8c8b23f8848b4bcfadb8f050dca5
MD5 f14082a1081989629c2265799381ce44
BLAKE2b-256 b1bb94b03b0f22f27d1fb5ee264c649302e0da6588c2828f943fe9f3f273bd88

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page