Request Data and Parameters
In this tutorial, you will build a robust API endpoint that extracts and validates data from various parts of an HTTP request, including the path, query strings, headers, cookies, and the request body.
Prerequisites
To follow this tutorial, ensure you have the following installed:
fastapipydanticpython-multipart(required for handling form data and file uploads)
Step 1: Define Path and Query Parameters
Path parameters are part of the URL path, while query parameters appear after the ? in the URL. You can use Annotated with Path and Query to add validation and metadata.
Create a file named main.py:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)],
q: Annotated[str | None, Query(alias="item-query", max_length=50)] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
In this example:
item_idis a Path parameter. It is always required. We added a numeric validationge=1(greater than or equal to 1) and a title for documentation.qis a Query parameter. It is optional (defaults toNone). We used analiasso the client sendsitem-queryinstead ofqin the URL.
Step 2: Handle JSON Body Parameters
For complex data, you use Pydantic models. If you have multiple models or extra fields in the body, you use the Body parameter.
Update your main.py:
from fastapi import Body
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
class User(BaseModel):
username: str
full_name: str | None = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Item,
user: User,
importance: Annotated[int, Body()]
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
return results
When you declare multiple body parameters:
- FastAPI expects a JSON body where each parameter name is a key. For example:
{"item": {...}, "user": {...}, "importance": 5}. - If you want a single Pydantic model to be the entire body but still wrapped in a key, use
Body(embed=True).
Step 3: Extract Headers and Cookies
FastAPI allows you to extract metadata from the request using Header and Cookie.
from fastapi import Cookie, Header
@app.get("/info/")
async def read_info(
user_agent: Annotated[str | None, Header()] = None,
ads_id: Annotated[str | None, Cookie()] = None,
):
return {
"User-Agent": user_agent,
"ads_id": ads_id
}
- Headers: By default,
Headerconverts underscores to hyphens. A parameter nameduser_agentwill automatically look for theUser-AgentHTTP header. - Cookies:
Cookieworks exactly likeQueryandPathbut looks for values in the request cookies.
Step 4: Upload Files and Form Data
To receive form fields instead of JSON, use Form. To receive uploaded files, use File and UploadFile.
from fastapi import File, Form, UploadFile
@app.post("/files/")
async def create_file(
file: Annotated[bytes, File()],
fileb: Annotated[UploadFile, File()],
token: Annotated[str, Form()],
):
return {
"file_size": len(file),
"token": token,
"fileb_content_type": fileb.content_type,
"filename": fileb.filename,
}
bytes: If you declare the file parameter asbytes, FastAPI will read the entire file into memory. This is suitable for small files.UploadFile: This is preferred for large files. It uses a "spooled" file (stored in memory up to a limit, then on disk) and provides an async interface (read(),write(),seek(),close()).Form: Declares a field to be extracted fromapplication/x-www-form-urlencodedormultipart/form-data.
Complete Result
Your final API can now handle a wide variety of request data types with built-in validation and automatic documentation.
from typing import Annotated
from fastapi import FastAPI, Path, Query, Body, Cookie, Header, File, Form, UploadFile
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/complete/{item_id}")
async def complete_request(
item_id: Annotated[int, Path(ge=1)],
q: Annotated[str | None, Query()] = None,
item: Annotated[Item, Body(embed=True)],
user_agent: Annotated[str | None, Header()] = None,
session_id: Annotated[str | None, Cookie()] = None,
token: Annotated[str, Form()],
upload_file: Annotated[UploadFile, File()],
):
return {
"item_id": item_id,
"query": q,
"item": item,
"user_agent": user_agent,
"session_id": session_id,
"token": token,
"filename": upload_file.filename,
}
By combining these parameters, you can precisely define the interface of your API. FastAPI handles the extraction, validation, and generation of the OpenAPI schema (visible at /docs) automatically.