To make a properly documented Python API Using FastAPI, we can use fastapi’s Path and Query module to pass in more parameters that give more context to that the path and query variables that we use. For example from previous posts if we consider this little excerpt
PATH PARAMETERS
@app.get("/routers/hostname/{hostname}")
def get_router(hostname:str): return { "data" : router for router in routers if router['hostname']== hostname }
And now if we go to the API docs by going to “http://127.0.0.1:8000/docs”, we can see that there is no title or description given to the hostname field. We can add the description here by using Path parameters and to do so we need to import Path() from fastapi.
from fastapi import Path @app.get("/routers/hostname/{hostname}")
def get_router(hostname: Optional[str] = Path( None, description = 'Enter hostname of the device you want to search', example='rtr-indi-ce01')): return { "data" : router for router in routers if router['hostname']== hostname }
And now if we reload the API page, we can see the updated description field.
You can see what all parameters this method supports by looking at the function definition and the extract is also shown below.
def Path( # noqa: N802 default: Any, *, alias: Optional[str] = None, title: Optional[str] = None, description: Optional[str] = None, gt: Optional[float] = None, ge: Optional[float] = None, lt: Optional[float] = None, le: Optional[float] = None, min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any,
)
QUERY PARAMETERS
Instead of defining the route like “@app.get(“/routers/hostname/{hostname}”)” where we are passing the value of the hostname we want to fetch the details for, we can leverage the URL structure to pass in query parameters instead. You probably would have seen a question mark in the URL multiple times like
http://example.com/path?name=Branch&products=[Journeys,Email]
where we are passing name = Branch and products = [‘Journeys’, ‘Email’] thereby allowing us more flexibility with our API code. Defining a query parameter is quite similar to defining Path variables except in this case we don’t need to define the variable in the app.get route.
@app.get("/routers/hostname")
def get_router(hostname: str): return { "data" : router for router in routers if router['hostname']== hostname }
We are still accepting the hostname variable in the function definition but there is no such declaration in the app.get decorator and this syntax by default tells fastapi to consider hostname as a query parameter and not a path parameter.
Integrating the above function into our existing code, we can execute queries like below and get responses.
This flexibility allows us to pass multiple query parameters like below
@app.get("/routers/")
def get_router(hostname: str, model: str): return { "data" : router for router in routers if router['hostname']== hostname and router['model']== model }
At the moment, both the query parameters are defined as mandatory but we can always make either of them optional if we need to.
@app.get("/routers/")
def get_router(hostname: str, model: Optional[str] = None): if model: return { "data" : router for router in routers if router['hostname']== hostname and router['model']== model } else: return { "data" : router for router in routers if router['hostname']== hostname}
We can define the model field as optional using python’s typing module and setting the default to None in this case as an example. We are also modifying the code a little bit to stop python from complaining when model = None because there is no entry in the database with None value for the model field. So now, even if you don’t pass the model field in the query parameter string, it will still return the output.
Ofcourse, nothing stops you from combining the Path and Query parameters together in the same definition.
@app.get("/routers/{hostname}/")
def get_router(hostname: str, model: Optional[str] = None): if model: return { "data" : router for router in routers if router['hostname']== hostname and router['model']== model } else: return { "data" : router for router in routers if router['hostname']== hostname}
hostname is defined as path parameter above and model is optional query parameter. Just like we defined metadata for Path variables using fastapi’s Path() module, we can do the exact same for query parameters using Query() module.
@app.get("/routers/{hostname}/")
def get_router(hostname: str, model: Optional[str] = Query( None, description = 'optional model number field')): if model: return { "data" : router for router in routers if router['hostname']== hostname and router['model']== model } else: return { "data" : router for router in routers if router['hostname']== hostname}
the model field is still defined as optional with a default value of None inside Query() and is also given a description. Another way you can validate this is by using the SWAGGER UI of your API.
There is a lot more flexibility that comes along with query parameters like passing in a list of values instead of strings of query parameters.
Here are some of the query parameters that you can leverage just like for Path parameters
def Query( # noqa: N802 default: Any, *, alias: Optional[str] = None, title: Optional[str] = None, description: Optional[str] = None, gt: Optional[float] = None, ge: Optional[float] = None, lt: Optional[float] = None, le: Optional[float] = None, min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, **extra: Any,
)
We have been seeing how to use the READ operation from CRUD stack of operations. In the next section of this post we will see how to configure other CRUD operations like Create / Update / Delete.
The post Python API Using FASTAPI – For Network Engineers – Path and Query Parameters – Part III appeared first on Network Automation.