from collections.abc import Mapping from typing import Any from ..api_config import APIEndpointRegistry from ..request import APIClient, APIResponseFormatError from .base import APIBusinessError, EndpointAdapter class JX3ApiAdapter(EndpointAdapter): """适配 JX3API 的鉴权参数和业务响应协议。""" SUCCESS_CODE = 200 def __init__( self, client: APIClient, registry: APIEndpointRegistry, *, token: str = "", ticket: str = "", ): super().__init__(client, registry) self._credentials = { "token": token.strip(), "ticket": ticket.strip(), } def prepare_params( self, endpoint: Mapping[str, Any], params: Mapping[str, Any] | None, ) -> dict[str, Any]: request_params = super().prepare_params(endpoint, params) declared_params = endpoint.get("params", {}) # api_config.json 中出现 token/ticket 即表示此端点需要对应凭证。 # 业务 Service 不再重复拼装,也不会把空凭证发送给上游。 for name, value in self._credentials.items(): if name not in declared_params: continue if value: request_params[name] = value else: request_params.pop(name, None) return request_params def validate_payload(self, endpoint_name: str, payload: Any) -> Any: if not isinstance(payload, Mapping): raise APIResponseFormatError("JX3API 响应必须是对象") if "code" not in payload: raise APIResponseFormatError("JX3API 响应缺少业务码: code") code = payload.get("code") if code != self.SUCCESS_CODE: message = payload.get("msg") or "未知错误" raise APIBusinessError( f"JX3API 业务错误: code={code}, message={message}", endpoint=endpoint_name, code=code, ) return payload def extract_payload(self, payload: Any, out_key: str | None) -> Any: if out_key in (None, ""): return payload if not isinstance(payload, Mapping): raise APIResponseFormatError( f"JX3API 响应不是对象,无法提取字段: {out_key}" ) if out_key not in payload: raise APIResponseFormatError(f"JX3API 响应缺少字段: {out_key}") return payload[out_key]