Most of the time, we will be using function-based dependencies only. However, at times, we need to pass custom arguments to our dependency. Since the arguments of function-based dependencies are set by the dependency injection system, So, we can't add our custom arguments. Let's understand it with an example.
We want to allow our website users to search for jobs by providing the job id. In case the job with that id does not exist, then instead of showing an error page, We want to show some featured/promoted jobs. To accomplish this task, we need to pass a custom argument named featured_job to the get_object_or_404 function.
# This implementation is not possible using function
from fastapi import FastAPI, Depends
app = FastAPI()
dummy_db = {
'1':"SDE1 at Google",
'2':"SDE2 at Amazon",
'3':"Backend Dev. at Spotify",
'4':"Senior Engineer at Alphabet",
'5':"Devops Eng. at Microsoft",
}
def get_object_or_featured(id:str, featured_job:str):
value = dummy_db.get(id)
if not value:
value = dummy_db.get("featured_job")
return value
@app.get("/job/{id}")
def get_job_by_id(job_title: str= Depends(get_object_or_featured('2'))):
return job_title
The problem with this implementation is that, if we pass '2' like this to the get_object_or_featured function, It would be assigned to the first argument and the function will complain about the 2nd argument. But, we can't pass the 2nd argument otherwise our implementation will be hardcoded and searching will not be possible.
In reality, the dependency injection system takes care of the task of getting the id from the path parameter "/job/{id}" and passing it to the dependency at runtime. Since we now manually called the function. That's why it is asking for both parameters but we don't have both at compile time! (Without user input, we don't know the id!)
The solution is to use classes. The FastAPI dependency injection system needs a callable for the dependencies. If we use the __call__ method, the class object becomes a valid callable. We can use the below code to resolve the issues.
from fastapi import FastAPI, Depends
app = FastAPI()
dummy_db = {
'1':"SDE1 at Google",
'2':"SDE2 at Amazon",
'3':"Backend Dev. at Spotify",
'4':"Senior Engineer at Alphabet",
'5':"Devops Eng. at Microsoft",
}
class GetObjectOrFeatured:
"""We let companies promote their jobs. The promoted job
is called featured_job"""
def __init__(self,featured_job:str):
self.featured_job = featured_job
def __call__(self,id:str)-> str:
value = dummy_db.get(id)
if not value:
value = dummy_db.get(self.featured_job)
return value
@app.get("/job/{id}")
def get_job_by_id(job_title: str= Depends(GetObjectOrFeatured('2'))):
return job_title
Now, if you visit the docs at http://127.0.0.1:8000/docs and try with an unknown key e.g. 8, You should see the featured job with the id of 2.
We can set class properties in the __init__ method. The __call__ method makes our object callable, which is a pre-requisite for FastAPI Dependencies. The logic in the __call__ will be run during runtime and will be able to fetch the featured_job id from the class properties using self.featured_job.
Brige the gap between Tutorial hell and Industry. We want to bring in the culture of Clean Code, Test Driven Development.
We know, we might make it hard for you but definitely worth the efforts.
© Copyright 2022-23 Team FastAPITutorial