Перейти к содержанию

Router

Router является главным объектом, который связывает Esmerald с Gateway, WebSocketGateway и handlers.

Класс Router

Класс Router состоит из множества атрибутов, которые по умолчанию заполняются в приложении. Однако Esmerald также позволяет добавить дополнительные пользовательские маршрутизаторы или добавить приложение ChildEsmerald.

from pydantic import BaseModel

from esmerald import Esmerald, Gateway, post


class User(BaseModel):
    name: str
    email: str


@post("/create")
def create(data: User) -> User: ...


app = Esmerald(routes=[Gateway(handler=create)])

Основной класс Router создается в приложении Esmerald с заданными маршрутами и приложение запускается.

Info

При добавлении другого маршрутизатора в приложение доступны два варианта: пользовательские маршрутизаторы и ChildEsmerald. В данном случае пользовательские маршрутизаторы более ограничены, чем ChildEsmerald.

Параметры

Все параметры и значения по умолчанию доступны в Router.

Warning

response_class, response_cookies, response_headers, tags и include_in_schema не используются в add_route, только при использовании ChildEsmerald.

Пользовательский маршрутизатор

Предположим, что существуют определенные подмодули customer в файле customers, посвященном клиентам. Существует три способа разделения маршрутов в приложении: с использованием Include, ChildEsmerald или созданием другого маршрутизатора. Давайте сосредоточимся на последнем варианте.

/application/apps/routers/customers.py
from pydantic import BaseModel

from esmerald import Gateway, JSONResponse, Router, get, post


class Address(BaseModel):
    address_line: str
    street: str
    post_code: str


class Customer(BaseModel):
    name: str
    email: str
    address: Address


@post("/")
def create(data: Customer) -> JSONResponse:
    return JSONResponse({"created": True})


@get("/{customer_id:int}")
async def get_customer(customer_id: int) -> JSONResponse:
    return JSONResponse({"created": True})


router = Router(
    path="/customers",
    routes=[
        Gateway("/", handler=get_customer),
        Gateway("/create", handler=create),
    ],
)

Выше вы создали /application/apps/routers/customers.py с необходимой информацией. Он не обязательно должен быть в одном файле, вы можете создать совершенно отдельный пакет, только для управления customer.

Теперь вам нужно добавить новый пользовательский маршрутизатор в основное приложение.

/application/app.py
from apps.routers.customers import router as customers_router

from esmerald import Esmerald

app = Esmerald()
app.add_router(customers_router)

Ваш маршрутизатор добавлен в основное приложение Esmerald.

Child Esmerald Application

Что это такое? Мы называем его ChildEsmerald, но на самом деле это просто Esmerald, но под другим именем, в основном для удобства организации.

Check

Использование ChildEsmerald или Esmerald абсолютно одно и тоже, если вы хотите создать sub application и предпочитаете использовать другой класс вместо Esmerald для более удобной организации.

При организации маршрутов использование самого класса Router может быть немного ограничивающим, поскольку существуют определенные атрибуты, которые при использовании в экземпляре или Router для передачи в add_route не будут учтены.

Пример:

  • response_class
  • response_cookies
  • response_headers
  • tags
  • include_in_schema

Это не ограничение и не ошибка, на самом деле это сделано намеренно, поскольку мы хотим сохранить целостность приложения.

Как это работает

Давайте используем тот же пример, что и в пользовательских маршрутизаторах с маршрутами и правилами, специфичными для клиентов.

/application/apps/routers/customers.py
from pydantic import BaseModel

from esmerald import ChildEsmerald, Gateway, JSONResponse, get, post


class Address(BaseModel):
    address_line: str
    street: str
    post_code: str


class Customer(BaseModel):
    name: str
    email: str
    address: Address


@post("/")
def create(data: Customer) -> JSONResponse:
    return JSONResponse({"created": True})


@get("/{customer_id:int}")
async def get_customer(customer_id: int) -> JSONResponse:
    return JSONResponse({"created": True})


router = ChildEsmerald(
    routes=[
        Gateway("/", handler=get_customer),
        Gateway("/create", handler=create),
    ],
    include_in_schema=...,
    response_class=...,
    response_headers=...,
    response_cookies=...,
)

Поскольку ChildEsmerald является представлением класса Esmerald, мы можем передать ранее ограниченные параметры в пользовательском маршрутизаторе и все параметры, доступные для Esmerald.

Вы можете добавить столько ChildEsmerald, сколько захотите, ограничений нет.

Теперь в основном приложении:

/application/app.py
from apps.routers.customers import router as customers_router

from esmerald import Esmerald, Include

app = Esmerald(routes=[Include("/customers", app=customers_router)])

Добавление вложенных приложений

/application/app.py
from apps.routers.clients import router as clients_router
from apps.routers.customers import router as customers_router
from apps.routers.restrict import router as restrict_router

from esmerald import Esmerald, Include

app = Esmerald(
    routes=[
        Include("/customers", app=customers_router),
        Include(
            "/api/v1",
            routes=[
                Include("/clients", clients_router),
                Include("/restrict", routes=[Include("/access", restrict_router)]),
            ],
        ),
    ]
)

Приведенный выше пример показывает, что вы даже можете добавить то же самое приложение внутри вложенных includes, и для каждого include вы можете добавить уникальные permissions, middlewares, обработчики исключений и зависимости, которые доступны для каждого экземпляра Include. Вариантов бесконечно много.

Note

С точки зрения организации, ChildEsmerald имеет чистый подход к изоляции обязанностей и позволяет рассматривать каждый модуль отдельно и просто добавлять его в основное приложение в форме Include.

Tip

Рассматривайте ChildEsmerald как независимый экземпляр Esmerald.

Check

При добавлении приложения ChildEsmerald или Esmerald не забудьте добавить уникальный путь в базовый Include, таким образом вы можете быть уверены, что маршруты будут найдены правильно.

Утилиты

Объект Router имеет ряд функций, которые могут быть полезны.

add_route

from esmerald import Esmerald

app = Esmerald()

app.add_route(
    handler=...,
    dependencies=...,
    exception_handlers=...,
    permissions=...,
    middleware=...,
    name=...,
    interceptors=...,
    include_in_schema=...,
)

Параметры

  • name - Название маршрута.
  • include_in_schema - Добавлять ли маршрут в схему OpenAPI.
  • handler - HTTP обработчик.
  • permissions - Список permissions для обслуживания входящих запросов приложения (HTTP и WebSockets).
  • middleware - Список middleware выполняемых для каждого запроса. Middlewares из Include будут проверяться сверху вниз.
  • interceptors - Список interceptors или Lilya Middleware, поскольку они оба внутренне преобразуются. Узнайте больше о Python Protocols.
  • dependencies - Словарь строк и экземпляров Inject, позволяющих внедрить зависимости на уровне приложения.
  • exception_handlers - Словарь типов исключений (или пользовательских исключений) и функций-обработчиков на верхнем уровне приложения. Вызываемые обработчики исключений должны иметь вид handler(request, exc) -> response и могут быть как синхронными, так и асинхронными функциями.

add_websocket_route

from esmerald import Esmerald

app = Esmerald()

app.add_websocket_route(
    handler=...,
    dependencies=...,
    exception_handlers=...,
    permissions=...,
    middleware=...,
    interceptors=...,
    name=...,
)

Параметры

  • name - Название маршрута.
  • Websocket handler - Websocket обработчик.
  • permissions - Список permissions для обслуживания входящих запросов приложения (HTTP и WebSockets).
  • interceptors - Список interceptors.
  • middleware - Список middleware выполняемых для каждого запроса. Middlewares из Include будут проверяться сверху вниз. Или Lilya Middleware, поскольку они оба внутренне преобразуются. Узнайте больше о Python Protocols.
  • dependencies - Словарь строк и экземпляров Inject, позволяющих внедрить зависимости на уровне приложения.
  • exception_handlers - Словарь типов исключений (или пользовательских исключений) и функций-обработчиков на верхнем уровне приложения. Вызываемые обработчики исключений должны иметь вид handler(request, exc) -> response и могут быть как синхронными, так и асинхронными функциями.

add_child_esmerald

from esmerald import ChildEsmerald, Esmerald, Gateway, get


@get()
async def home() -> str:
    return "home"


child = ChildEsmerald(routes=[Gateway(handler=home, name="my-apiview")])

app = Esmerald()
app.add_child_esmerald(
    path="/child",
    child=child,
    name=...,
    middleware=...,
    dependencies=...,
    exception_handlers=...,
    interceptors=...,
    permissions=...,
    include_in_schema=...,
    deprecated=...,
    security=...,
)

Параметры

  • path - Путь для ChildEsmerald.
  • child - Экземпляр ChildEsmerald.
  • name - Название маршрута.
  • Websocket handler - Websocket обработчик.
  • permissions - Список permissions для обслуживания входящих запросов приложения (HTTP и WebSockets).
  • interceptors - Список interceptors.
  • middleware - Список middleware выполняемых для каждого запроса. Middlewares из Include будут проверяться сверху вниз. Или Lilya Middleware, поскольку они оба внутренне преобразуются. Узнайте больше о Python Protocols.
  • dependencies - Словарь строк и экземпляров Inject, позволяющих внедрить зависимости на уровне приложения.
  • exception_handlers - Словарь типов исключений (или пользовательских исключений) и функций-обработчиков на верхнем уровне приложения. Вызываемые обработчики исключений должны иметь вид handler(request, exc) -> response и могут быть как синхронными, так и асинхронными функциями.
  • include_in_schema - Флаг, указывающий, следует ли включать ChildEsmerald в схему OpenAPI.
  • deprecated - Флаг, указывающий, следует ли пометить ChildEsmerald как устаревший.