调用HTTP接口 ============ 一般来说,推荐使用 ``deepfos.elements`` 中封装好的元素功能。 在以下情况,您可能需要直接调用HTTP接口。 - 现有元素功能不能满足需要,但是有合适的接口 - 元素功能引入了额外的接口调用,您希望优化性能 在阅读本节文档前,预设读者有基础的HTTP通信的相关知识,并且有一定的Python开发经验。 如果您认为您将要使用HTTP接口实现的功能有相当的通用性,欢迎您向deepfos提交PR。 流程可以参考这篇文档: :doc:`如何贡献 <../contribute>`。 前言 ---- deepfos对HTTP接口的封装是多层级的。 例如一个web服务提供以下接口: .. code-block:: GET controller-1/resource-a GET controller-1/resource-b GET controller-2/resource-c GET controller-2/resource-d 那么deepfos中会对应封装出以下方法: .. code-block:: api.controller_1.get_resource_a api.controller_1.get_resource_b api.controller_2.get_resource_c api.controller_2.get_resource_d Package ``deepfos.api`` 中所有对外的api都以上述形式组织。 HTTP接口分为系统接口和组件接口两大类。仅实例化方法略有不同,使用逻辑是完全一致的。 .. _call_sys_api : 调用系统接口 ------------ 已封装的接口可以在文档: :ref:`HTTP接口 ` 中看到。 .. panels:: :container: container pb-1 img-auto-width :column: col-lg-12 p-0 :body: p-0 .. image:: ../images/http_api_doc.png 所有可以实例化的接口都会在此处展示。 简单例子 ~~~~~~~~ 以AppAPI为例,如果需要调用下图中的 ``get_server_names`` 方法 .. panels:: :container: container pb-1 img-auto-width :column: col-lg-12 p-0 :body: p-0 .. image:: ../images/doc_appapi.png 则可以使用 .. code-block:: python from deepfos.api.app import AppAPI from deepfos.api.models.app import QueryElementInfoByTypeDto api = AppAPI() api.element_info.get_server_names([ QueryElementInfoByTypeDto(elementType='PY', elementName='test', path='/'), QueryElementInfoByTypeDto(elementType='SML', elementName='test', path='/'), ]) 所有的接口函数都有完整的类型提示,绝大多数情况下,您只要通过查看函数签名,不需要查看接口的swagger文档就可以完成一个接口的调用。 使用原生python对象 ~~~~~~~~~~~~~~~~~~ 有时候为了调用一个简单接口而特意组装一个python对象有些大费周章。您可能更熟悉python的原生数据结构,如 ``list``, ``dict`` 等。 接口函数允许您不按照函数签名,而直接传入一个更接近 ``json`` 数据的参数。 同样以 ``get_server_names`` 方法为例,您还可以这样调用: .. code-block:: python :emphasize-lines: 2,3 api.element_info.get_server_names([ {'elementName': 'test', 'elementType': 'PY', 'path': '/'}, {'elementName': 'test', 'elementType': 'SML', 'path': '/'}, ]) 尽管IDE可能会给您一些警告,但实际上这不会有任何问题,甚至比第一种调用方式性能更高! 隐藏的接口参数 ~~~~~~~~~~~~~~ 除了签名所含有的参数外,接口函数还能够接收一些 **“隐藏参数”** :resp_model: 接口的返回模型 :retries: 接口调用失败时的重试次数 ``resp_model`` 可以影响接口函数的返回。 按照签名, ``get_server_names`` 应该返回 ``List[ModuleServerNameVO]`` 对象,但假如希望拿到原始的 ``json`` 对象, 可以这样调用: .. code-block:: python :emphasize-lines: 4 r = api.element_info.get_server_names([ {'elementName': 'test', 'elementType': 'PY', 'path': '/'}, {'elementName': 'test', 'elementType': 'SML', 'path': '/'}, ], resp_model=None) assert isinstance(r, list) assert isinstance(r[0], dict) 此时函数将返回 ``List[Dict]`` 类型的对象。 您也可以传入其他有效的 Pydantic Model,如果能成功解析,返回的结果将会符合您定义的数据模型。 调用组件接口 ------------ 调用组件接口与 调用系统接口_ 逻辑一致。但是由于组件可能存在多版本,实例化时必须指定组件版本。 .. code-block:: python :emphasize-lines: 1 api = MySQLAPI(version=1.0) r = api.dml.run_sql('select 1') 异步调用接口 ------------ 接口函数不仅能够同步调用,也可以异步调用: .. code-block:: python :emphasize-lines: 1 import asyncio async def run_sql(): api = MySQLAPI(version=1.0, sync=False) r = await api.dml.run_sql('select 1') asyncio.run(run_sql()) 所有API在实例化时还接受一个可选参数 ``sync``,其默认值为 ``True``,即同步调用。 当传入 ``False`` 时,所有接口函数将变成异步函数。 异步编程常用于解决 ``I/O`` 并发问题,相较于线程,协程开销更小,切换更快,执行顺序明确, 而且只要内存允许,能够达到极高的并发量。 并发调用接口示例: .. code-block:: python import asyncio async def concurrently_run_sqls(): api = MySQLAPI(version=1.0, sync=False) r = await asyncio.gather( api.dml.run_sql('select 1'), api.dml.run_sql('select 2'), api.dml.run_sql('select 3'), api.dml.run_sql('select 4'), ) asyncio.run(concurrently_run_sqls()) 配置项 ------ 有些配置项能够全局影响接口的行为。 :OPTION\.api\.verify_ssl: 是否开启ssl校验 :OPTION\.api\.timeout: 默认超时时间 :OPTION\.api\.dump_on_failure: 是否在调用接口失败时输出curl命令 :OPTION\.api\.dump_always: 是否在所有接口调用时输出curl命令