Upgrade to Pro — share decks privately, control downloads, hide ads and more …

5 Things we've learned building large APIs with FastAPI

5 Things we've learned building large APIs with FastAPI

FastAPI follows the UNIX philosophy of "do one thing, and do it well". By using Starlette and Pydantic, FastAPI provides you with powerful tools to build a beautiful API. This gives you a lot of freedom to decide how you organise the rest of your codebase. The level of freedom also comes with some challenges once a codebase grows.

In this talk we explore some of the common challenges in building FastAPI apps, and share how we solved them:

1. Minimizing the global state with dependency injection
2. Reducing the complexity of testing a FastAPI app
3. Pitfalls of async FastAPI
4. Supporting multiple authentication schemes
5. Modelling the relations between patch, response and database models

Maarten Huijsmans

April 14, 2022
Tweet

Other Decks in Technology

Transcript

  1. @lukin0110 Who am I? Maarten Huijsmans Python Developer @ InvestSuite

    twitter/lukin0110 github.com/lukin0110 linkedin.com/in/mhuijsmans
  2. A suite of modern wealthtech solutions Built with Python and

    FastAPI Wealthtech as a service investsuite.com
  3. @lukin0110 • Relatively new python web framework • Built on

    top of Starlette (ASGI) • 43.8k Github stars • Created by Sebastián Ramirez (@tiangolo) • Excellent documentation ❤ https://fastapi.tiangolo.com/
  4. 5 Things we've learned building large APIs with FastAPI @lukin0110

    I assume that you’re familiar with: • The basics of FastAPI • Pydantic • Web / API development • Python 😎 Assumptions
  5. 5 Things we've learned building large APIs with FastAPI @lukin0110

    1. 🥳 Minimizing the global state with dependency injection 2. 󰟜 Reducing the complexity of testing a FastAPI app 3. 😎 Pitfalls of async Python/FastAPI 4. 🔐 Supporting multiple authentication schemes 5. 💾 Modelling the relations between patch, response and database models Goal of the next 30 minutes
  6. Minimizing the global state with dependency injection 🥳 5 Things

    we've learned building large APIs with FastAPI
  7. 🥳 1. Minimizing the global state with dependency injection •

    Generally bad practice • You easily end up there because FastAPI itself lives in the global state • Hard to patch in unit tests Global state, que?
  8. Reducing the complexity of testing a FastAPI app 󰟜 5

    Things we've learned building large APIs with FastAPI
  9. 󰟜 2. Reducing the complexity of testing a FastAPI app

    See the previous learning 󰤇 Reduce/avoid the global state. It will make you happy 😎 Lesson learned
  10. 󰟜 2. Reducing the complexity of testing a FastAPI app

    • Override configs • Mock/patch functions • Setup a TestClient Things to deal with when testing an API …
  11. 󰟜 2. Reducing the complexity of testing a FastAPI app

    Use BaseSettings to centralize app config
  12. 󰟜 2. Reducing the complexity of testing a FastAPI app

    Pure python classes / functions • Forces you to not rely directly on environment variables • Dependencies are cached • Endpoints can be lightweight wrappers around business logic
  13. 😎 3. Pitfalls of async Python/FastAPI • asyncio is not

    as easy as it looks like • GIL: Global Interpreter Lock • “Sync” libraries Async python is an event loop. A single-thread in a single-process. The pitfalls
  14. 😎 3. Pitfalls of async Python/FastAPI • A lot of

    python libraries are not asyncio compatible. Or not battle tested. • You easily end up with a blocking application. Not always clear what is blocking it in a large codebase. Lessons learned
  15. 😎 3. Pitfalls of async Python/FastAPI • Remove all `async`

    prefixes => application becomes multi-threaded • Offloading CPU-bound operations to: ◦ a ProcessPoolExecutor => moves GIL troubles to another process and FastAPI remains responsive ◦ AWS Lambda => multi-process by default ◦ Queuing systems (RabbitMQ, Redis, Kafka, etc) and process asynchronously on another server. What can you do …
  16. 🔐 4. Supporting multiple authentication schemes Be able to support

    2 different auth schemes at the same time. • JWT • API Keys Want did we want
  17. 🔐 4. Supporting multiple authentication schemes • Provides a lot

    of utilities ◦ For API Keys, Basic Auth, Oauth2, … • Utilities integrate very well with OpenAPI specs and Swagger/Redoc • Extensive documentation • Various code samples FastAPI & Security
  18. 🔐 4. Supporting multiple authentication schemes • Not with batteries

    included • Actual implementation/integration of flows you need to do yourself • FastAPI auth is different from Starlette auth Things to keep in mind
  19. 🔐 4. Supporting multiple authentication schemes A simple solution auto_error=False

    However… • Need to repeat this on every endpoint. • If you specify it on router level you don’t have access to a user anymore.
  20. 🔐 4. Supporting multiple authentication schemes Maybe a middleware approach

    is better suited for authentication. • Decouple auth schemes from routers/views. • User is available on the request object. • Flexibility at router level to decide which schemes to use. Lessons learned
  21. Modelling the relations between patch, response and database models 💾

    5 Things we've learned building large APIs with FastAPI
  22. 💾 5. Modelling the relations between patch, response and database

    models • Automatic type checking • Validation of input and output models out of the box • Generates beautiful documentation. OpenAPI, Swagger, & ReDoc FastAPI + Pydantic = Powerful 🚀
  23. 💾 5. Modelling the relations between patch, response and database

    models 1. Used inheritance to define patch, response and DB models 2. Fully documented our DB models 3. Exposed a subset of each DB model in the API How did we build CRUD APIs?
  24. 💾 5. Modelling the relations between patch, response and database

    models Patch Model ⊆ Response Model ⊆ DB Model
  25. 💾 5. Modelling the relations between patch, response and database

    models • DB models are hard to read in code • Hard to change an API contract without a DB migration 󰤇 • Hard to change a DB model without breaking the API contract However, some lessons learned here 🤯
  26. 💾 5. Modelling the relations between patch, response and database

    models • Investigating decoupling DB models from API models 😎 • Investigating “Annotated” fields to reuse documentation Next steps