FastAPI HTTP Methods
HTTP methods (also called HTTP verbs) define the type of action that a client wants to perform on a resource. FastAPI provides a clean and intuitive way to implement these methods for building RESTful APIs. In this lesson, we'll explore how to use different HTTP methods in FastAPI and understand when to use each one.
Introduction to HTTP Methods
HTTP methods are standardized ways to indicate the desired action to be performed on a resource. When building APIs with FastAPI, understanding these methods is crucial for designing clear and predictable endpoints.
The most commonly used HTTP methods are:
- GET: Retrieve data
- POST: Create new data
- PUT: Update existing data (complete replacement)
- PATCH: Partially update existing data
- DELETE: Remove data
Implementing HTTP Methods in FastAPI
FastAPI provides dedicated decorators for each HTTP method, making it straightforward to define the behavior for different types of requests.
GET Method
The GET method is used to retrieve data from the server. It should be:
- Safe (doesn't modify resources)
- Idempotent (same request always returns same result)
- Cacheable
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items():
return {"items": ["Item 1", "Item 2", "Item 3"]}
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id, "name": f"Item {item_id}"}
When you access /items/
in your browser or with a GET request, you'll receive:
{
"items": ["Item 1", "Item 2", "Item 3"]
}
And when you access /items/5
:
{
"item_id": 5,
"name": "Item 5"
}
POST Method
The POST method is used to create new resources. It's neither safe nor idempotent, as each request creates a new resource.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = False
@app.post("/items/")
async def create_item(item: Item):
return {"item_name": item.name, "created": True}
To test this endpoint, you'd send a POST request with a JSON body:
POST /items/
Content-Type: application/json
{
"name": "Smartphone",
"price": 499.99,
"is_offer": true
}
Response:
{
"item_name": "Smartphone",
"created": true
}
PUT Method
The PUT method is used to update an existing resource by replacing it entirely. PUT should be idempotent - making the same request multiple times should have the same effect as making it once.
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
return {"item_id": item_id, "item_name": item.name, "updated": True}
Example request:
PUT /items/5
Content-Type: application/json
{
"name": "Updated Smartphone",
"price": 599.99,
"is_offer": false
}
Response:
{
"item_id": 5,
"item_name": "Updated Smartphone",
"updated": true
}
PATCH Method
The PATCH method is used for partial updates to a resource. Unlike PUT, which replaces the entire resource, PATCH only modifies specified fields.
from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel
app = FastAPI()
class ItemUpdate(BaseModel):
name: Optional[str] = None
price: Optional[float] = None
is_offer: Optional[bool] = None
@app.patch("/items/{item_id}")
async def partial_update(item_id: int, item: ItemUpdate):
return {"item_id": item_id, "updated_fields": item.dict(exclude_unset=True)}
Example request:
PATCH /items/5
Content-Type: application/json
{
"price": 449.99
}
Response:
{
"item_id": 5,
"updated_fields": {
"price": 449.99
}
}
DELETE Method
The DELETE method is used to remove resources. Like PUT, it should be idempotent.
@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
# In a real application, you would delete from a database here
return {"item_id": item_id, "deleted": True}
Example request:
DELETE /items/5
Response:
{
"item_id": 5,
"deleted": true
}
Less Common HTTP Methods
FastAPI also supports other HTTP methods that are less commonly used:
HEAD Method
Similar to GET, but returns only headers, not the body.
@app.head("/items/{item_id}")
async def head_item(item_id: int):
# FastAPI automatically handles the response -
# returns headers but not body
return {"item_id": item_id}
OPTIONS Method
Used to describe communication options for a resource.
@app.options("/items/{item_id}")
async def options_item(item_id: int):
return {"allowed_methods": ["GET", "PUT", "DELETE"]}
Real-World Example: Building a Task API
Let's build a simple task management API that demonstrates all the major HTTP methods working together:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional, List
import uuid
app = FastAPI()
# Our simple "database"
tasks = {}
class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False
class TaskUpdate(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
completed: Optional[bool] = None
class Task(BaseModel):
id: str
title: str
description: Optional[str] = None
completed: bool = False
# Create a new task (POST)
@app.post("/tasks/", response_model=Task)
async def create_task(task: TaskCreate):
task_id = str(uuid.uuid4())
task_dict = task.dict()
task_dict["id"] = task_id
tasks[task_id] = task_dict
return task_dict
# Get all tasks (GET)
@app.get("/tasks/", response_model=List[Task])
async def read_tasks():
return list(tasks.values())
# Get a specific task (GET)
@app.get("/tasks/{task_id}", response_model=Task)
async def read_task(task_id: str):
if task_id not in tasks:
raise HTTPException(status_code=404, detail="Task not found")
return tasks[task_id]
# Update a task completely (PUT)
@app.put("/tasks/{task_id}", response_model=Task)
async def update_task(task_id: str, task: TaskCreate):
if task_id not in tasks:
raise HTTPException(status_code=404, detail="Task not found")
task_dict = task.dict()
task_dict["id"] = task_id
tasks[task_id] = task_dict
return task_dict
# Update a task partially (PATCH)
@app.patch("/tasks/{task_id}", response_model=Task)
async def partial_update_task(task_id: str, task: TaskUpdate):
if task_id not in tasks:
raise HTTPException(status_code=404, detail="Task not found")
stored_task = tasks[task_id]
update_data = task.dict(exclude_unset=True)
for field, value in update_data.items():
stored_task[field] = value
return stored_task
# Delete a task (DELETE)
@app.delete("/tasks/{task_id}")
async def delete_task(task_id: str):
if task_id not in tasks:
raise HTTPException(status_code=404, detail="Task not found")
deleted_task = tasks.pop(task_id)
return {"message": f"Task '{deleted_task['title']}' deleted successfully"}
This example demonstrates:
- Creating a new task with POST
- Retrieving all tasks or a specific task with GET
- Updating a task with PUT (full update) or PATCH (partial update)
- Deleting a task with DELETE
Best Practices for HTTP Methods
-
Use the right method for the job:
- GET for retrieving data
- POST for creating new resources
- PUT for complete updates
- PATCH for partial updates
- DELETE for removing resources
-
Maintain idempotence where appropriate (GET, PUT, DELETE, HEAD, OPTIONS).
-
Return appropriate status codes:
- 200 OK for successful operations
- 201 Created when a resource is created
- 204 No Content for successful operations with no response body
- 404 Not Found when a resource doesn't exist
- 400 Bad Request for invalid inputs
-
Use consistent URL patterns:
- Collection:
/items/
(plural) - Individual item:
/items/{item_id}
(specific)
- Collection:
Summary
FastAPI makes it easy to implement different HTTP methods through its decorator system, enabling you to build RESTful APIs that follow standard conventions. By understanding when to use each HTTP method, you can design clean and intuitive APIs that are easy for clients to consume.
- GET: Use for retrieving data
- POST: Use for creating new resources
- PUT: Use for complete resource updates
- PATCH: Use for partial resource updates
- DELETE: Use for removing resources
Using the appropriate HTTP method for each operation makes your API more intuitive and follows REST principles, resulting in a better developer experience for API consumers.
Additional Resources
- FastAPI Official Documentation on HTTP Methods
- RESTful API Design Best Practices
- HTTP Methods MDN Documentation
Exercises
- Extend the Task API to include a search endpoint using query parameters.
- Implement a "mark all as completed" endpoint using appropriate HTTP method.
- Add proper validation to ensure tasks cannot be created with empty titles.
- Implement pagination for the GET /tasks/ endpoint.
- Add authentication to your API using FastAPI's security utilities.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)