Передать зависимость запроса#

Зависимость подходит для значения, которым владеет приложение, а не вызывающий код. Автор SDK объявляет тип и назначение, приложение регистрирует provider, а runtime разрешает значение перед подготовкой запроса.

# examples/docs/dependencies.py
DEVICE = dependency(
    Device,
    name="device",
    apply=(field("id").to_header("X-Device-Id"),),
)


@dataclass(frozen=True, slots=True, kw_only=True)
class GetDevice(HttpOperation[Result]):
    __http__ = Http.get("/device", requires=(DEVICE,))

    device_id: Annotated[Omittable[str], markers.Header("X-Device-Id")] = UNSET


class DeviceApi(SyncApi):
    get = op(GetDevice)


def main() -> None:
    registry = DependencyRegistry()
    registry.register(DEVICE.dependency, DeviceProvider(Device("device-7")))
    identity = Identity(dependencies=registry)
    with guide_client(GuideSite()) as client:
        result = DeviceApi(client, identity=identity).get()
    print(f"device: {result.value}")

DEVICE выбирает поле id результата и пишет его в объявленный X-Device-Id. Поле операции имеет UNSET по умолчанию, поэтому provider заполняет его только тогда, когда вызывающий не передал значение сам.

DependencyRegistry принадлежит Identity и обслуживает все роутеры корня. Отсутствующий обязательный provider останавливает вызов до сети.

Файл целиком
"""Provide application-owned request data through Identity."""

from dataclasses import dataclass
from typing import Annotated

from pydantic import BaseModel

from eazy_sdk import Http, HttpOperation, Identity, Omittable, SyncApi, UNSET, op
from eazy_sdk.dependencies import DependencyContext, DependencyRegistry, dependency, field
from eazy_sdk.request import markers
from examples.docs.guide_site import GuideSite, guide_client


class Result(BaseModel):
    value: str


@dataclass(frozen=True, slots=True)
class Device:
    id: str


@dataclass(frozen=True, slots=True)
class DeviceProvider:
    device: Device

    def resolve(self, context: DependencyContext) -> Device:
        return self.device


# region docs: dependencies
# examples/docs/dependencies.py
DEVICE = dependency(
    Device,
    name="device",
    apply=(field("id").to_header("X-Device-Id"),),
)


@dataclass(frozen=True, slots=True, kw_only=True)
class GetDevice(HttpOperation[Result]):
    __http__ = Http.get("/device", requires=(DEVICE,))

    device_id: Annotated[Omittable[str], markers.Header("X-Device-Id")] = UNSET


class DeviceApi(SyncApi):
    get = op(GetDevice)


def main() -> None:
    registry = DependencyRegistry()
    registry.register(DEVICE.dependency, DeviceProvider(Device("device-7")))
    identity = Identity(dependencies=registry)
    with guide_client(GuideSite()) as client:
        result = DeviceApi(client, identity=identity).get()
    print(f"device: {result.value}")
# endregion docs: dependencies


if __name__ == "__main__":
    main()
device: device-7

Выбрать способ применения#

Способ

Когда использовать

Inject(...)

Значение целиком занимает новый header, query, cookie или поле тела

requires= с apply=

Значение заполняет уже объявленный слот операции

requires= с BodyProjection

Значение нужно внутри private wire-документа

Выбрать срок кэша#

Политика

Когда provider вызывается снова

NONE

При каждом обращении к зависимости

CLIENT

После создания нового роутера

CALL

Для нового логического вызова

ATTEMPT

Для каждой попытки, включая retry и redirect

Nonce и timestamp обычно требуют ATTEMPT, а неизменяемый device context можно хранить с CLIENT. Маркер secret=True скрывает значение из диагностики.

Примечание

Access token относится к авторизации, captcha к защите, а ключ HMAC к key_provider. У этих значений другой жизненный цикл, поэтому не оформляйте их как обычные зависимости.

Дальше#