In FastAPI, you can use PEP 593'sAnnotated
type to add metadata to the type hint. This feature is very useful because it allows you to add more contextual information such as descriptions, default values, or other custom metadata to the type hint.
FastAPI SupportAnnotated
type, which allows you to provide additional metadata for the parameters of path manipulation functions, such as dependencies, descriptions of query parameters, aliases, and so on.
Introduction to FastAPI
FastAPI is a modern, fast (high-performance) web framework for building APIs, based on Python type hints. Its main features include automatic generation of OpenAPI and JSON Schema documentation , fast code writing , clean code structure , efficient performance , etc. FastAPI uses Starlette as the core of the web framework , and uses Pydantic for data validation .
Key Features of FastAPI
-
speedy:
- FastAPI's performance is very close to that of faster languages like NodeJS and Go, and much faster than other Python-based frameworks like Flask and Django.
-
pithy:
- The code is clean and easy to read through type hinting and dependency injection.
- Developers can do more with less code.
-
Automatic Document Generation:
- FastAPI automatically generates OpenAPI-compliant documentation that can be viewed through the built-in Swagger UI and ReDoc UI.
- Automatic JSON Schema generation.
-
data validation:
- Based on Pydantic, FastAPI provides powerful data validation capabilities.
- Supports complex data validation and data parsing.
-
Type Hints:
- Take advantage of Python 3.6+'s type hints to help developers write and maintain code.
-
dependency injection:
- FastAPI provides a simple but powerful dependency injection system that makes it easy to manage dependencies.
FastAPI also supports the following features:
- File Upload
- Security (OAuth2, JWT, etc.)
- Back-office tasks
- Streaming Response
- GraphQL
- SQL (via SQLAlchemy, etc.)
- Database transactions
- Back-office tasks
Install FastAPI and Uvicorn
pip install fastapi pip install "uvicorn[standard]"
FastAPI is a very modern and efficient framework that is ideal for building high-performance APIs, with features such as automatic document generation, data validation, and dependency injection that enable developers to write code faster, more securely, and provide a great user experience.
1, Query parameters - query parameters
Query parameter is the query parameter we have in the URL such as url/items?q=123&b=234 type format.
Suppose we want to create an API where the query parameters need to come with descriptions and default values:
from fastapi import FastAPI, Query from typing import Annotated app = FastAPI() @("/items/") async def read_items( q: Annotated[str, Query(description="Query string", min_length=3, max_length=50)] = "default" ): return {"q": q}
In this example:
- We imported FastAPI and
Query
class, andAnnotated
Type. - We created a FastAPI application instance.
- We define a path manipulation function
read_items
It has a query parameterq
。 - We use
Annotated
Type as query parameterq
Added metadata which includes description, minimum length, maximum length, etc. -
Annotated
's first argument is the type hint, and the second argument is the metadata associated with this type.
Annotated
Types allow you to associate additional metadata with type hints, which is particularly useful when creating APIs as it can help generate richer API documentation and ensure parameter validation.
Here's a more complex example that shows how to use theAnnotated
Types are combined with dependencies:
from fastapi import Depends def common_parameters( q: Annotated[str, Query(description="Query string", min_length=3, max_length=50)] = "default" ): return {"q": q} @("/items/") async def read_items(params: Annotated[dict, Depends(common_parameters)]): return params
In this example:
- We define a dependency function
common_parameters
, which returns a query containing the query parametersq
The dictionary. - We use
Annotated
genre andDepends
Inject this dependency into the path manipulation functionread_items
Center. -
read_items
function returns a dictionary of arguments taken from the dependent functions.
This approach not only simplifies the definition of parameters for path manipulation functions, but also makes the code more readable and maintainable.
2, Path parameters - path parameters
The path parameter is typically used to extract information from a URL path. For example, if you have a path to get information about a user/users/{user_id}
, you can define the path parameter like this:
from fastapi import FastAPI from import Path from typing import Annotated app = FastAPI() @("/users/{user_id}") async def read_user(user_id: Annotated[int, Path(..., title="The ID of the user to get")]): return {"user_id": user_id}
In this example, theAnnotated[int, Path(..., title="The ID of the user to get")]
indicateuser_id
is an integer and it is a parameter extracted from the path. In addition, we add a title to this parameter for generating API documentation.
3. Body parameter - request body parameter
The request body parameter is used to handle complex data structures, such as JSON request bodies. You can use the Pydantic model to define the structure of the request body and use theAnnotated
to further annotate these parameters. Example:
from fastapi import FastAPI from pydantic import BaseModel from typing import Annotated app = FastAPI() class User(BaseModel): name: str age: int @("/users/") async def create_user(user: Annotated[User, Body(..., title="The user to create")]): return {"user": user}
In this example, theAnnotated[User, Body(..., title="The user to create")]
indicateuser
The parameter is aUser
model instance and it comes from the request body. We add a title to this parameter as well.
Sometimes we can use the path parameter in combination with the request body parameter, as in the following example:
from fastapi import FastAPI, Path, Body from pydantic import BaseModel from typing import Annotated app = FastAPI() class User(BaseModel): name: str age: int @("/users/{user_id}") async def update_user( user_id: Annotated[int, Path(..., title="The ID of the user to update")], user: Annotated[User, Body(..., title="The new user data")] ): return {"user_id": user_id, "user": user}
In this synthesized example, the path parameteruser_id
and request body parametersuser
Both use theAnnotated
annotated to clarify their origin and intent, while providing more contextual information for the generated API documentation.
Complex request bodies often include nested structures that can be defined using the Pydantic model. Example:
from fastapi import FastAPI from pydantic import BaseModel from typing import List, Annotated app = FastAPI() class Address(BaseModel): street: str city: str state: str zip: str class User(BaseModel): name: str age: int addresses: List[Address] @("/users/") async def create_user(user: Annotated[User, Body(..., title="The user to create")]): return {"user": user}
In this example, theUser
The model contains a nestedAddress
list so that you can handle complex nested data structures in the request body.
A complex example combining path parameters, query parameters and request body parameters:
from fastapi import FastAPI, Path, Query, Body from pydantic import BaseModel from typing import Annotated app = FastAPI() class Item(BaseModel): name: str description: str | None = None price: float tax: float | None = None @("/items/{item_id}") async def update_item( item_id: Annotated[int, Path(..., title="The ID of the item to update")], q: Annotated[str | None, Query(None, max_length=50, title="Query string")], item: Annotated[Item, Body(..., title="The item to update")] ): result = {"item_id": item_id, "item": item} if q: ({"q": q}) return result
In this synthesized example, we use the path parameteritem_id
The query parameterq
and request body parametersitem
and throughAnnotated
Annotate these parameters to clarify their sources and constraints.
Applying the above processing solution, we apply FastApi to build the document in our project as shown below.