This commit is contained in:
2026-07-26 17:57:44 +08:00
parent a555f785ba
commit 069f1bafe1
27 changed files with 4893 additions and 3846 deletions
+85
View File
@@ -0,0 +1,85 @@
from collections.abc import Mapping
from typing import Any
from ..api_config import APIEndpointRegistry
from ..request import APIClient, APIClientError, APIResponseFormatError
class APIAdapterError(APIClientError):
"""Adapter 层的结构化异常。"""
class APIBusinessError(APIAdapterError):
"""HTTP 请求成功,但上游接口返回业务错误。"""
def __init__(
self,
message: str,
*,
endpoint: str,
code: Any = None,
):
super().__init__(message)
self.endpoint = endpoint
self.code = code
class EndpointAdapter:
"""把端点配置转换为 HTTP 请求;子类只处理各上游的协议差异。"""
def __init__(self, client: APIClient, registry: APIEndpointRegistry):
self._client = client
self._registry = registry
async def request(
self,
endpoint_name: str,
*,
params: Mapping[str, Any] | None = None,
out_key: str | None = "data",
path_params: Mapping[str, Any] | None = None,
) -> Any:
endpoint = self._registry.get(endpoint_name)
request_params = self.prepare_params(endpoint, params)
url = self._registry.resolve(endpoint_name, path_params)
configured_method = str(endpoint.get("method", "GET")).upper()
if configured_method == "POST":
payload = await self._client.post(
url,
data=request_params,
retry=bool(endpoint.get("retry", False)),
)
else:
payload = await self._client.get(
url,
params=request_params,
retry=bool(endpoint.get("retry", True)),
)
payload = self.validate_payload(endpoint_name, payload)
return self.extract_payload(payload, out_key)
def prepare_params(
self,
endpoint: Mapping[str, Any],
params: Mapping[str, Any] | None,
) -> dict[str, Any]:
request_params = dict(endpoint.get("params", {}))
if params:
request_params.update(params)
return request_params
def validate_payload(self, endpoint_name: str, payload: Any) -> Any:
return payload
def extract_payload(self, payload: Any, out_key: str | None) -> Any:
if out_key in (None, ""):
return payload
if isinstance(payload, bytes):
raise APIResponseFormatError("二进制响应无法提取 JSON 字段")
if not isinstance(payload, Mapping):
raise APIResponseFormatError(f"响应不是对象,无法提取字段: {out_key}")
if out_key not in payload:
raise APIResponseFormatError(f"响应缺少字段: {out_key}")
return payload[out_key]