メインコンテンツまでスキップ

ルート

ルートを定義すると、クライアントがリクエストできる特定のパスを通じてリソースを公開します。そして、ルートにEndpointを追加して、クライアントがそのリソースで何ができるかを決定します。

URL https://dontclickme.com/usersを例に取ると、パス/usersはリソースusersを指し示します。

ルートの定義

from lihil import Route

users_route = Route("/users")

使用したい既存のlihil.Graphlihil.MessageRegistryがある場合は、ルートコンストラクタに入れてください。

これは依存関係とイベントリスナーを別々のファイルに保持している場合に便利です。例:

from project.users.deps import user_graph
from project.users.listeners import user_eventregistry

user_route = Route(graph=user_graph, registry=user_eventregistry)

また、特定のルートにのみ適用したいミドルウェアをルートに追加することもできます。

from starlette.middleware.cors import CORSMiddleware
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware

Route(middlewares=[CORSMiddleware])
route.add_middleware(HTTPSRedirectMiddleware)

ルートにエンドポイントを登録

前の議論では、users_routePOSTリクエストのエンドポイントとしてcreate_userを公開しました。 同様の構文で他のHTTPメソッドも宣言でき、これには以下が含まれます:

メソッド冪等性目的
GETはいサーバー状態を変更せずにデータを取得@route.get
POSTいいえリソースを作成またはアクションをトリガーするデータを送信@route.post
HEADはいGETと同じですが、ヘッダーのみを返す@route.head
OPTIONSはい許可されたメソッドとCORS情報を発見@route.options
TRACEはい受信したリクエストをエコー(デバッグ用)@route.trace
PUTはい提供されたデータでリソースを置換@route.put
DELETEはいリソースを削除@route.delete
PATCHいいえリソースに部分的な変更を適用@route.patch
CONNECTいいえサーバーへのトンネルを確立(例:HTTPS)@route.connect

これは、ルートが0-9個のエンドポイントを持つことができることを意味します。

複数のHTTPメソッドに関数を公開するには

  • 関数に複数のデコレータを適用

  • または、同等にRoute.add_endpointを使用

users_route.add_endpoint("GET", "POST", ...,  create_user)

サブルートの定義

前の議論では、ユーザーリソースのコレクションであるusersのルートを作成しました。 特定のユーザーリソースを公開するには:

user_route = users_route.sub("{user_id}")

@user_route.get
async def get_user(user_id: str, limit: int = 1): ...

ここで、 users_routeのサブルートを定義し、ルートをLihilに含めると、そのすべてのサブルートも再帰的に含まれます。

Route.subは冪等で、同じパスで複数回呼び出すことができます。

@users_route.sub("{user_id}").get
async def get_user(user_id: str, limit: int = 1): ...

@users_route.sub("{user_id}").put
async def update_user(data: UserUpdate): ...

ここで、get_userupdate_userは両方とも同じルートの下にあります。

サブルートを含める

大きなアプリでは、通常、人々は最初にサブルートを作成してから親ルートに含めます。そのためには、Route.include_subroutesを使用します

parent = Route("/parent")
sub = Route("/sub")

parent.include_subroutes(sub)
assert parent.subroutes[0].path == "/parent/sub"

Route.subRoute.include_subroutesの違いは:

  • Route.subは文字列型のパスに基づいて新しい空のルートを作成
  • Route.include_subroutesは既存のルートをサブルートとして再帰的に含め、それらのプロパティ(エンドポイント、ミドルウェアなど)に基づいて再作成

各ルートに対してファイルを作成することが推奨されます:

api/cart/items.py
items = Route("/items")

@items.get
def list_items(): ...

@items.sub("/{item_id}").get
def get_item(item_id: str) :...

次に、フォルダの__init__.pyで親ルートを作成し、サブルートを含めます

api/cart/__init__.py
from .items import items

carts = Route("/carts")
carts.include_subroutes(items)

ルートルート

パス/のルートがルートルートです。提供されない場合、ルートルートはデフォルトでLihilによって作成され、Lihil.{http method}を通じて登録されたものはすべてルートルートの下にあります。

以下の例は機能的に同じです

  1. Lihilインスタンスをルートルートとして使用
lhl = Lihil()
@lhl.get
async def hello():
return "hello, world"
  1. ルートルートを作成してからLihilインスタンスに含める
root = Route()

@root.get
async def hello():
return "hello, world"
lhl = Lihil(root)