クラス内にいくつかのルートが必要ですが、ルートメソッドにはattrが必要ですself
(クラスの属性にアクセスするため)。ただし、FastAPIはself
独自の必須引数を想定し、それをクエリパラメータとして配置します。
私が持っているのはこれです:
app = FastAPI()
class Foo:
def __init__(y: int):
self.x = y
@app.get("/somewhere")
def bar(self): return self.x
ただし、422
に移動しない限り、は を返します/somewhere?self=something
。これの問題は、 がself
str になり、役に立たなくなることです。
self
必須の引数として指定せずにアクセスできる方法が必要です。
ベストアンサー1
APIRouter
これは のメソッドを使用して実行できますadd_api_route
。
from fastapi import FastAPI, APIRouter
class Hello:
def __init__(self, name: str):
self.name = name
self.router = APIRouter()
self.router.add_api_route("/hello", self.hello, methods=["GET"])
def hello(self):
return {"Hello": self.name}
app = FastAPI()
hello = Hello("World")
app.include_router(hello.router)
例:
$ curl 127.0.0.1:5000/hello
{"Hello":"World"}
add_api_route
の2番目の引数(endpoint
)は 型なのでCallable[..., Any]
、どの呼び出し可能オブジェクトでも動作するはずです(FastAPIがその引数のHTTPリクエストデータを解析する方法を見つけられる限り)。この呼び出し可能オブジェクトは、FastAPIドキュメントではパス操作関数(以下、「POF」といいます)。
装飾方法がうまくいかない理由
警告: OPの回答のコードがなぜ機能しないのかの技術的な説明に興味がない場合は、この回答の残りの部分を無視してください。
@app.get
クラス本体でメソッドを や の仲間で装飾しても、実際にはHello.hello
ではなくhello.hello
(別名self.hello
)を に渡すことになるため、機能しadd_api_route
ません。バインドされたメソッドとバインドされていないメソッド(別名単に「関数」)Python 3以降) には異なる署名があります。
import inspect
inspect.signature(Hello.hello) # <Signature (self)>
inspect.signature(hello.hello) # <Signature ()>
FastAPI は、HTTP リクエスト (本文またはクエリ パラメータ) 内のデータを POF で実際に使用されるオブジェクトに自動的に解析しようとするために、さまざまな魔法を実行します。
バインドされていないメソッド (=通常の関数) ( Hello.hello
) を POF として使用すると、FastAPI は次のいずれかを行う必要があります。
ルートを含むクラスの性質について想定し、オンザフライで を生成
self
(つまり を呼び出すHello.__init__
) します。これにより、FastAPI の複雑さが大幅に増す可能性があり、FastAPI 開発者は (当然のことながら) サポートすることに興味がないと思われるユースケースです。アプリケーション/リソースの状態を処理するための推奨される方法は、 を使用した外部依存関係に問題全体を委ねることのようですDepends
。何らかの方法で、呼び出し元から送信された HTTP リクエスト データ (通常は JSON) からオブジェクトを生成できるようにします
self
。これは、文字列やその他の組み込みデータ以外では技術的に実現不可能であるため、実際には使用できません。
OP のコードで何が起きるかは #2 です。FastAPI は、HTTP リクエスト クエリ パラメータからHello.hello
(= self
、型) の最初の引数を解析しようとしますが、明らかに失敗し、 を発生させます。これは、呼び出し元に HTTP 422 応答として表示されます。Hello
RequestValidationError
self
クエリパラメータからの解析
上記の 2 を証明するために、FastAPI が実際にself
HTTP リクエストから「解析」できる場合の (役に立たない) 例を次に示します。
(免責事項:以下のコードを実際のアプリケーションに使用しないでください。)
from fastapi import FastAPI
app = FastAPI()
class Hello(str):
@app.get("/hello")
def hello(self):
return {"Hello": self}
例:
$ curl '127.0.0.1:5000/hello?self=World'
{"Hello":"World"}