Skip to content

ApiEndpoint

Bases: Generic[ResponseBodyT]

Descriptor for defining API endpoints on a client.

Allows us to share state (like auth or HTTP client) between API endpoints of the same client.

See BaseClient for an example of how to use this.

Source code in quickapi/client.py
Python
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
class ApiEndpoint(Generic[ResponseBodyT]):
    """
    Descriptor for defining API endpoints on a client.

    Allows us to share state (like auth or HTTP client) between API endpoints
    of the same client.

    See `BaseClient` for an example of how to use this.
    """

    def __init__(self, cls: type[BaseApi[ResponseBodyT]]):
        self._api: BaseApi[ResponseBodyT] | None = None
        self._api_cls = cls

        if self._api_cls is not None and not (issubclass(self._api_cls, BaseApi)):
            raise ClientSetupError(attribute="cls")

    def __set_name__(self, owner: type[BaseClient] | None, field_name: str) -> None:
        self._field_name = field_name

    @overload
    def __get__(
        self, instance: None, owner: type[BaseClient] | None
    ) -> type[BaseApi[ResponseBodyT]]: ...

    @overload
    def __get__(self, instance: BaseClient, owner: type[BaseClient] | None) -> Self: ...

    def __get__(self, instance, owner):  # type: ignore [no-untyped-def]
        if instance is None:
            # Client has not been initialized, return the API class.
            return self._api_cls

        if self._api is None:
            # If client has been initialized, also initialize the API class.
            self._api = self._api_cls(
                base_url=instance.base_url,
                http_client=instance.http_client,
                auth=instance.auth,
            )

        return self

    def __call__(
        self,
        request_params: "DictSerializableT | None" = None,
        request_body: "DictSerializableT | None" = None,
        http_client: BaseHttpClient | None = None,
        auth: BaseHttpClientAuth = USE_DEFAULT,
    ) -> BaseResponse[ResponseBodyT]:
        if self._api is None:
            raise AttributeError("API endpoint not part of a `BaseClient` instance.")  # noqa: TRY003

        return self._api.execute(
            request_params=request_params,
            request_body=request_body,
            http_client=http_client,
            auth=auth,
        )

    def __set__(self, instance: BaseClient, value: Any) -> NoReturn:
        raise AttributeError(  # noqa: TRY003
            f"`{self._field_name}` is read-only and cannot be modified.",
            name=self._field_name,
        )

    def __delete__(self, instance: BaseClient) -> NoReturn:
        raise AttributeError(  # noqa: TRY003
            f"`{self._field_name}` is read-only and cannot be deleted.",
            name=self._field_name,
        )