真的没有最好的方法。这完全取决于您的用例和个人偏好/实践。话虽如此,我可以给你几个选择:
在应用内实现
在应用程序根目录中的单独子模块中开发一个类、方法或任何您可能需要的东西。随意命名此子模块(服务、实用程序、3rdparty 等)。最后,只要它对您和参与该项目的其他人来说是一个有意义的名字,这并不重要。
如果这个实现是静态的,那么你可以通过简单的导入在特定的控制器中使用它。
另一方面,如果您需要创建一个可以在整个应用程序中访问的类对象实例,并且您不希望每次在控制器中执行它时都创建一个新对象(例如,您不希望打开 X 个 HTTP 客户端会话)。那么FastAPI event handlers就可以派上用场了:
您可以定义在应用程序启动之前或应用程序关闭时需要执行的事件处理程序(函数)。
这些函数可以用 async def 或普通 def 声明。
为了在我的fastapi-mvc-template 启动事件中给你一个更好的例子,我正在创建 Redis 和 Aiohttp 类对象实例:
async def on_startup():
RedisClient.open_redis_client()
AiohttpClient.get_aiohttp_client()
async def on_shutdown():
await RedisClient.close_redis_client()
await AiohttpClient.close_aiohttp_client()
然后可以在任何控制器中使用,而无需在每次调用 API 方法时创建它们:
from fastapi_mvc_template.app.utils.redis import RedisClient
from fastapi_mvc_template.app.utils.aiohttp_client import AiohttpClient
response = RedisClient.get("Key")
response = AiohttpClient.get("http://foo.bar")
单独包装
如果处理 3rd 方 API 的实现大于几个文件/类。那么也许值得考虑将其编写为一个单独的 Python 包,或者为您的语言使用 3rd 方实现(如果有的话)。但是,您应该小心要求中的此依赖版本。理想情况下是硬编码或锁定到补丁版本(例如 1.1.x)。
远程过程调用
恕我直言,一个 API 调用另一个 API 可能不是最好的方法。每次对 API 进行更改时,为了向后兼容,都应该对其进行版本控制。我认为第 3 方 API 提供商会做同样的事情,因为他们会改进他们的 API。而现在,如果你开始快速增长和扩展,你最终可能会得到一个如此复杂的兼容性矩阵网络,以至于蜘蛛侠都会头疼:)。
所谓的远程过程调用 (RPC) + 协议缓冲区可能是更好的方法。目前CNCF incubation中有一个主要框架:gRPC
gRPC 的好处:
- 线上的二进制
- 双向流式传输和集成身份验证
- 高性能
- 跨语言和平台工作(内置代码生成)
- 简单的服务定义和使用协议缓冲区的向后兼容性
当然,第 3 方服务可能不提供该选项。尽管如此,这个话题还是值得研究的,因为它的好处和现在越来越受欢迎。