简体   繁体   中英

How to structure a FastAPI app that calls other API's

I've seen this post: What are the best practices for structuring a FastAPI project?

Which lays out a good baseline, but I was wondering where calling 3rd party API's would fall into place. Would creating a services folder inside the v1 folder here make sense. And then throwing modules in there for dealing with 3rd party API's.

There isn't really the best approach. It all depends on your use case and individual preferences/practices. With that said, I can give you a few options:

Implementation within the app

Develop a class, method, or whatever you might need in a separate submodule inside your application root directory. Name this submodule however you'd like (services, utils, 3rdparty, etc.). In the end, it doesn't really matter that much as long it's a meaningful name to you and other people involved in the project.

If this implementation is static, then you're good to go and can utilize it inside a particular controller by just doing a simple import.

If, on the other hand, you'll require to create a class object instance that should be accessible across the whole application, and you don't want to create a new object each time you'll execute it in the controller (For instance, you wouldn't want to have X HTTP client sessions opened). Then FastAPI event handlers can come in handy:

You can define event handlers (functions) that need to be executed before the application starts up, or when the application is shutting down. These functions can be declared with async def or normal def.

To give you a better example in my fastapi-mvc-template on startup event, I'm creating Redis and Aiohttp class object instance:

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()

which then can be used inside any controller without the need of creating them each time API method gets called:

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")

Separate package

If the implementation for dealing with 3rd party APIs is bigger than a few files/classes. Then maybe it's worth considering writing it as a separate Python package, or using 3rd party implementation for your language, if there is any. However, then you should be careful with this dependency version in requirements. Ideally hardcoded or locked to patch version (ex. 1.1.x).

Remote Procedure Call

IMHO an API calling another API may not be the best approach. Each time you implement a change to an API, you should version it for backward compatibility sake. I'd reckon 3rd party API providers will do the same as they improve theirs. And now, if you start to grow and scale rapidly, you might end up with a compatibility matrix web so complex that even spiderman would get a headache:).

A what is called Remote Procedure Call (RPC) + protocol buffers might be a better approach. There is currently one major framework in CNCF incubation : gRPC

Benefits of gRPC:

  • Binary on the wire
  • Bi-directional streaming and integrated auth
  • High performance
  • Works across languages and platforms (built-in code generation)
  • Simple service definition and backward compatibility with using protocol buffers

Of course, 3rd party services may not provide that option. N.netheless, it's worth researching the topic since its benefits and increasing popularity nowadays.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM