11
This commit is contained in:
@@ -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]
|
||||
Reference in New Issue
Block a user