Reader small image

You're reading from  Building Data Science Applications with FastAPI

Product typeBook
Published inOct 2021
Reading LevelBeginner
PublisherPackt
ISBN-139781801079211
Edition1st Edition
Languages
Concepts
Right arrow
Author (1)
François Voron
François Voron
author image
François Voron

François Voron graduated from the University of Saint-Étienne (France) and the University of Alicante (Spain) with a master's degree in machine learning and data mining. A full stack web developer and a data scientist, François has a proven track record working in the SaaS industry, with a special focus on Python backends and REST APIs. He is also the creator and maintainer of FastAPI Users, the #1 authentication library for FastAPI, and is one of the top experts in the FastAPI community.
Read more about François Voron

Right arrow

Chapter 5: Dependency Injections in FastAPI

In this chapter, we'll focus on one of the most interesting parts of FastAPI: dependency injections. You'll see that it is a powerful and readable approach to reuse logic across your project. Indeed, it will allow you to create complex building blocks for your project that you'll be able to use everywhere in your logic. An authentication system, a query parameters' validator, or a rate-limiter are typical use cases for dependencies. In FastAPI, a dependency injection can even call another one recursively, allowing you to build high-level blocks from basic features. By the end of this chapter, you'll be able to create your own dependencies for FastAPI and use them at several levels of your project.

In this chapter, we're going to cover the following main topics:

  • What is dependency injection?
  • Creating and using a function dependency
  • Creating and using a parameterized dependency with a class
  • ...

Technical requirements

You'll need a Python virtual environment, as we set up in Chapter 1, Python Development Environment Setup.

You'll find all the code examples of this chapter in the dedicated GitHub repository: https://github.com/PacktPublishing/Building-Data-Science-Applications-with-FastAPI/tree/main/chapter5.

What is dependency injection?

Generally speaking, dependency injection is a system able to automatically instantiate objects and the ones they depend on. The responsibility of developers is then to only provide a declaration of how an object should be created, and let the system resolve all the dependency chains and create the actual objects at runtime.

FastAPI allows you to declare the objects and variables you wish to have at hand only by declaring them in the path operation function arguments. Actually, we already used dependency injection in the previous chapters. In the following example, we use the Header function to retrieve the user-agent header:

chapter5_what_is_dependency_injection_01.py

from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/")
async def header(user_agent: str = Header(...)):
    return {"user_agent": user_agent}

Creating and using a function dependency

In FastAPI, a dependency can be defined either as a function or as a callable class. In this section, we'll focus on the functions, which are the ones you'll probably work with most of the time.

As we said, a dependency is a way to wrap some logic that will retrieve some sub-values or sub-objects, make something with them, and finally return a value that will be injected into the endpoint calling it.

Let's look at a first example where we define a function dependency to retrieve the pagination query parameters, skip and limit:

chapter5_function_dependency_01.py

async def pagination(skip: int = 0, limit: int = 10) -> Tuple[int, int]:
    return (skip, limit)
@app.get("/items")
async def list_items(p: Tuple[int, int] = Depends(pagination)):
    skip, limit = p
    return {"skip": skip, "limit": limit}

Creating and using a parameterized dependency with a class

In the previous section, we defined dependencies as regular functions, which works well in most cases. Still, you may need to set some parameters on a dependency to finely tune its behavior. Since the arguments of the function are set by the dependency injection system, we can't add an argument to the function.

In the pagination example, we added some logic to cap the limit value at 100. If we wanted to set this maximum limit dynamically, how would we do that?

The solution is to create a class that will be used as a dependency. This way, we can set class properties, with the __init__ method, for example, and use them in the logic of the dependency itself. This logic will be defined in the __call__ method of the class. If you remember what we learned in the Callable object section of Chapter 2, Python Programming Specificities, you know that it makes the object callable, meaning it can be called like a regular function...

Using dependencies at a path, router, and global level

As we said, dependencies are the recommended way to create building blocks in a FastAPI project, allowing you to reuse logic across endpoints while maintaining maximum code readability. Until now, we've applied them on a single endpoint, but couldn't we expand this approach to a whole router? Or even a whole FastAPI application? Actually, we can!

The main motivation for this is to be able to apply some global request validation or perform side logic on several routes without the need to add the dependency on each endpoint. Typically, an authentication method or a rate-limiter could be very good candidates for this use case.

To show you how it works, we'll implement a simple dependency that we will use across all the following examples. You can see it in the following example:

chapter5_path_dependency_01.py

def secret_header(secret_header: Optional[str] = Header(None)) -> None:
    ...

Summary

Well done! You should now be comfortable with one of the most iconic features of FastAPI: dependency injections. By implementing your own dependencies, you'll be able to keep common logic that you wish to reuse across your API separate from the endpoints' logic. This will make your project clean and maintainable while retaining maximum readability: dependencies just need to be declared as arguments of the path operation functions, which will help to understand the intent without having to read the body of the function.

Those dependencies can be both simple wrappers to retrieve and validate request parameters, or complex services performing machine learning tasks. Thanks to the class-based approach, you can indeed set dynamic parameters or keep a local state for your most advanced tasks.

Finally, those dependencies can also be used at a router or global level, allowing you to perform common logic or checks for a set of routes or a whole application.

That&apos...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Building Data Science Applications with FastAPI
Published in: Oct 2021Publisher: PacktISBN-13: 9781801079211
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
François Voron

François Voron graduated from the University of Saint-Étienne (France) and the University of Alicante (Spain) with a master's degree in machine learning and data mining. A full stack web developer and a data scientist, François has a proven track record working in the SaaS industry, with a special focus on Python backends and REST APIs. He is also the creator and maintainer of FastAPI Users, the #1 authentication library for FastAPI, and is one of the top experts in the FastAPI community.
Read more about François Voron