Package: bkapi-client-core
蓝鲸云 API 客户端本项目基于 requests，提供了一种基于配置构建 SDK 的方案。Features同时支持网关 API 与组件 API，使用体验一致支持丰富的请求参数，包括魔法参数 data，requests.request 全部参数(除 data)、路径参数魔法参数 data，对于 GET/HEAD/OPTIONS 请求，参数将转换为 QueryString，其它请求方法，则转换为 json 格式的 Body支持从 django settings，Cookies 获取认证数据支持对 session 进行更新细粒度的控制，支持复用 session 的连接灵活的响应处理方式支持校验响应状态码，获取响应的 json 数据支持获取原始的 requests Response 对象，进行更细粒度的控制统一采用异常方案，出错时触发异常，如用户认证失败，请求状态码错误，请求网关超频，请求结果非 JSON 等详细的错误日志，触发异常时，将打印请求的 curl 语句支持数据懒加载，减小内存消耗对 IDE 开发友好，SDK 支持常见 IDE 智能提示及补全；兼容 Python2 及 Python3 的类型补全；SDK 使用样例1. 使用 Client1.1 直接调用 Client，并解析响应该方式下，SDK 会根据配置自动做请求和响应的转换和解析，隐藏文档已描述的通用细节（如参数位置，响应格式等），用户仅需关注具体字段传递，以减轻使用成本。fromdemo.clientimportClient# 需提供网关地址 endpoint，环境 stage 默认为 prodclient=Client(stage="prod",endpoint="http://bkapi.example.com/api/test/")# 根据需求，提供应用认证、用户认证信息client.update_bkapi_authorization(bk_app_code="xxx",bk_app_secret="yyy",bk_username="admin",)# 发起请求，检查 response.raise_for_status()，返回 response.json() 数据result=client.api.test({"key":"value"})print(result["ok"])1.2 直接调用 Client，不解析响应该方式下，SDK 不会有过多的封装，仅做参数传递，调用 requests 进行请求后返回响应，用户对请求流程有更细粒度的控制。fromdemo.clientimportClient# 需提供网关地址 endpoint，环境 stage 默认为 prodclient=Client(stage="prod",endpoint="http://bkapi.example.com/api/test/")# 根据需求，提供应用认证、用户认证信息client.update_bkapi_authorization(bk_app_code="xxx",bk_app_secret="yyy",bk_username="admin",)# 发起请求，但不对响应进行解析，直接返回 requests Response 对象，用户可对响应进行更细粒度的控制response=client.api.test.request({"key":"value"})result=response.json()print(result["ok"])2. 使用 shortcuts，简化 Client 创建为降低使用成本，SDK 提供了更简单地创建 Client 的方式：get_client_by_request、get_client_by_username2.1 使用 get_client_by_request此方式需提供 django request 对象get_client_by_requestfromdemo.shortcutsimportget_client_by_request# 需提供 django request，client 可从 request 中获取当前用户名或从 Cookies 中获取用户登录态# 并且，支持从 django settings 获取默认的 bk_app_code、bk_app_secret、endpoint，也可通过参数指定client=get_client_by_request(request)result=client.api.test({"key":"value"})print(result["ok])2.2 使用 get_client_by_usernameget_client_by_usernamefromdemo.shortcutsimportget_client_by_username# 支持从 django settings 获取默认的 bk_app_code、bk_app_secret、endpoint，也可通过参数指定client=get_client_by_username("admin")result=client.api.test({"key":"value"})print(result["ok])3. 复用 session支持复用 session 连接，提高请求效率fromdemo.shortcutsimportget_client_by_usernameclient=get_client_by_username("admin")withclient:result=client.api.test({"key":"value"})print(result["ok])SDK 配置说明SDK 支持通过配置更改一些默认的行为，Django settings 配置优先级高于环境变量。变量名描述类型格式默认值Django 配置环境变量别名BK_APP_CODE应用代号string"my_app"支持支持BKPAAS_APP_IDBK_APP_SECRET应用密钥string"my_secret"支持支持BKPAAS_APP_SECRETDEFAULT_STAGE_MAPPINGS指定对应网关的默认环境dict{"my_gateway": "prod"}支持BK_API_CLIENT_ENABLE_SSL_VERIFY是否开启 SSL 证书验证boolTrueFalse支持BK_API_AUTHORIZATION_COOKIES_MAPPING指定 Cookie 和认证参数的映射关系dict{"key": "cookie"}{"bk_token": "bk_token"}支持BK_API_URL_TMPL网关地址模板，支持{api_name}占位符string"http://{api_name}.example.com"支持支持BK_COMPONENT_API_URL组件 API 网关地址string"http://esb.example.com"支持支持DEFAULT_BK_API_VER默认组件版本号string"v1""v2"支持支持BK_API_USE_TEST_ENV是否使用组件测试环境boolFalseFalse支持模型主要模型定义的类关系请参考class_diagram.mdSession在requests.Session的基础之上，增加特有业务逻辑封装：公共参数设置超时设置路径参数设置同时扩展原有 hooks 机制，为后续进阶需求提供扩展。
session 管理状态及完成每一个接口调用。Operation借用 openapi 概念，表示一个路径和方法绑定的操作，相当于网关中的资源及 ESB 中的组件（对应的某个方法），作为配置及调用入口，封装以下属性：方法路径默认配置Operation 不发起具体的请求，对应的请求会在调用时交给 Manager 完成。Manager管理 Session 和 Operation，作为整体的“门面”，可以扩展实现为一个 Client。
其本身不保存状态，而是提供封装，将状态转换成 Session 的基本属性。
其本身也不完成接口调用，而是管理调用流程，处理好请求创建，响应解析和异常处理等步骤。OperationGroupOperation 的分组，在 ESB 中，可以用系统名作为分组，而在网关中，即使不区分系统，但为了避免资源和 Client 自身属性的冲突，也使用默认分组管理。ClientManager 的子类，管理 OperationGroups 以及其定义的 Operations，针对具体的业务场景中，提供更符合业务流程的封装。易用性设计在现有的网关文档中，有较大的一类文档基于程序自动生成，其中虽有描述请求方法，认证方式，调用示例，但因为基于模板生成的原因，其内容较为死板和繁琐。如果由人去机械化地拼接接口的每个配置细节，因为这种方式是反人性的，会有较大的出错概率，由此会带来额外的不必要的咨询和反馈。因此希望 SDK 能够自动帮用户去处理这些机械化的配置，只需要关注核心的调用参数即可完成任务。此外，SDK 本身又可看做某个版本的离线文档，通过 SDK 合理的智能提示和补全，也可以免除用户的查找和排除成本。接口定义在接口的设计上，有以下目标：避免覆盖和重写__init__方法；使用静态显式的定义方式；为了减轻内存压力，使用懒加载进行初始化；没有具体的业务逻辑；因此接口定义使用类属性 + property 的方式进行：classGroup(OperationGroup):test=bind_property(Operation,name="test",method="GET",path="/test/")如上示例，声明了一个 API 分组Group。test是该分组下注册在网关的一个资源名称，其方法为GET，资源路径为/test/。classClient(APIGatewayClient):api=bind_property(Group)上方示例基于Group这个 api 分组定义了一个网关客户端，使用Client可直接调用这个网关下的所有资源接口。
在接口定义中，bind_property方法实现了懒加载属性的功能，在调用时自动初始化对应类型，同时基于类型注解实现了泛型，可以帮助 IDE 建立类型系统。IDE 优化智能补全得益于bind_property实现的泛型，IDE 可以完成Client -> Group -> Operation整个调用链的智能补全。而Operation自身的补全方式，完全基于Operation定义，仅需维护本项目即可。接口文档为了优化 Python3 的调用逻辑，同时兼容 Python2 的使用，SDK 生成定义的同时，也会生成对应的存根文件（.pyi），将接口文档作为 docstring，在 IDE 中引用即可看到文档：classGroup(OperationGroup):@propertydeftest(self)->Operation:"""test api"""classClient(APIGatewayClient):@propertydefapi(self)->Group:"""api resources"""存根文件在运行时不会被执行，因此使用等价的property描述资源定义，通过 docstring 暴露文档（也是唯一方式）。进阶使用统计指标启用前需安装额外依赖：pipinstallbkapi_client_core[monitor]在项目入口处，执行以下代码启用 prometheus 指标统计的功能：frombkapi_client_coreimportprometheusprometheus.enable()以上代码只需要执行一次，开启后，sdk 会对每次请求进行指标的统计，暴露到/metrics接口，指标如下：名称类型描述维度bkapi_requests_duration_secondsHistogram请求耗时operation,methodbkapi_requests_body_bytesHistogram请求体大小operation,methodbkapi_responses_body_bytesHistogram响应体大小operation,methodbkapi_responses_totalCounter响应总数operation,method,statusbkapi_failures_totalCounter请求失败总数operation,method,error