Location>code7788 >text

Parameter design for FastAPI projects in Python using Annotated

Popularity:942 ℃/2024-08-01 12:19:02

In FastAPI, you can use PEP 593'sAnnotatedtype 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 SupportAnnotatedtype, 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

  1. 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.
  2. pithy

    • The code is clean and easy to read through type hinting and dependency injection.
    • Developers can do more with less code.
  3. 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.
  4. data validation

    • Based on Pydantic, FastAPI provides powerful data validation capabilities.
    • Supports complex data validation and data parsing.
  5. Type Hints

    • Take advantage of Python 3.6+'s type hints to help developers write and maintain code.
  6. 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:

  1. We imported FastAPI andQueryclass, andAnnotatedType.
  2. We created a FastAPI application instance.
  3. We define a path manipulation functionread_itemsIt has a query parameterq
  4. We useAnnotatedType as query parameterqAdded metadata which includes description, minimum length, maximum length, etc.
  5. Annotated's first argument is the type hint, and the second argument is the metadata associated with this type.

AnnotatedTypes 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 theAnnotatedTypes 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:

  1. We define a dependency functioncommon_parameters, which returns a query containing the query parametersqThe dictionary.
  2. We useAnnotatedgenre andDependsInject this dependency into the path manipulation functionread_itemsCenter.
  3. read_itemsfunction 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_idThe query parameterq and request body parametersitemand 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.