HTTP Methods

Difficulty: Beginner

HTTP methods (also called HTTP verbs) define the type of action a client wants to perform on a resource. In REST API design, each method has a specific semantic meaning, and using them correctly is fundamental to building well-designed APIs. FastAPI provides a decorator for each HTTP method, making it easy to create properly structured RESTful endpoints.

GET is the most common HTTP method. It requests data from a server without modifying anything. GET requests should be idempotent (calling them multiple times produces the same result) and safe (they do not change server state). In FastAPI, you use @app.get() for GET endpoints. GET requests should never have a request body - all parameters should be passed via the URL (path or query parameters).

POST is used to create new resources. When you submit a form or send data to create a new user, you use POST. POST requests typically include a request body with the data for the new resource. They are not idempotent - sending the same POST request twice usually creates two resources. In FastAPI, use @app.post() and accept a Pydantic model as a parameter to receive the request body.

PUT is used to replace an existing resource entirely. If you update a user profile with PUT, you must send the complete user object - any fields you omit will be set to their defaults or null. PUT is idempotent: sending the same PUT request multiple times produces the same result. Use @app.put() in FastAPI.

PATCH is used for partial updates. Unlike PUT, PATCH only requires the fields that are being changed. If you want to update just the email of a user, you send only the email field. This is more efficient than PUT for minor changes. Use @app.patch() in FastAPI.

DELETE removes a resource. It should be idempotent - deleting a resource that is already deleted should not cause an error (though returning 404 is also acceptable). Use @app.delete() in FastAPI.

FastAPI also supports less common methods like OPTIONS (used by browsers for CORS preflight), HEAD (like GET but returns only headers, no body), and TRACE (echoes the request for debugging). Most APIs only need GET, POST, PUT, PATCH, and DELETE.

A well-designed REST API maps CRUD operations to HTTP methods consistently: Create = POST, Read = GET, Update = PUT/PATCH, Delete = DELETE. The URL identifies the resource (like /users/42), and the HTTP method identifies the action. This convention makes APIs predictable and self-documenting.

Code examples

All CRUD Operations

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class UserCreate(BaseModel):
    name: str
    email: str

class UserUpdate(BaseModel):
    name: str | None = None
    email: str | None = None

users_db: dict[int, dict] = {}
next_id = 1

@app.get("/users")
def list_users():
    """GET: Retrieve all users"""
    return list(users_db.values())

@app.get("/users/{user_id}")
def get_user(user_id: int):
    """GET: Retrieve a single user"""
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    return users_db[user_id]

@app.post("/users", status_code=201)
def create_user(user: UserCreate):
    """POST: Create a new user"""
    global next_id
    new_user = {"id": next_id, user.model_dump()}
    users_db[next_id] = new_user
    next_id += 1
    return new_user

@app.put("/users/{user_id}")
def replace_user(user_id: int, user: UserCreate):
    """PUT: Replace a user entirely"""
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    users_db[user_id] = {"id": user_id, user.model_dump()}
    return users_db[user_id]

@app.patch("/users/{user_id}")
def update_user(user_id: int, user: UserUpdate):
    """PATCH: Partially update a user"""
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    stored = users_db[user_id]
    update_data = user.model_dump(exclude_unset=True)
    users_db[user_id] = {stored, update_data}
    return users_db[user_id]

@app.delete("/users/{user_id}", status_code=204)
def delete_user(user_id: int):
    """DELETE: Remove a user"""
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="User not found")
    del users_db[user_id]

This demonstrates all five CRUD operations. Note how PUT requires all fields (uses UserCreate) while PATCH accepts partial data (uses UserUpdate with optional fields). The model_dump(exclude_unset=True) method ensures only explicitly provided fields are updated.

Method Semantics Summary

# HTTP Method Semantics
#
# Method   | CRUD    | Idempotent | Safe  | Has Body
# ---------|---------|------------|-------|----------
# GET      | Read    | Yes        | Yes   | No
# POST     | Create  | No         | No    | Yes
# PUT      | Replace | Yes        | No    | Yes
# PATCH    | Update  | No*        | No    | Yes
# DELETE   | Delete  | Yes        | No    | No
#
# * PATCH can be idempotent depending on implementation
#
# Idempotent: same request repeated = same result
# Safe: does not modify server state

from fastapi import FastAPI

app = FastAPI()

# You can also handle multiple methods on one route
@app.api_route("/multi", methods=["GET", "POST"])
def multi_method():
    return {"message": "This handles both GET and POST"}

Understanding method semantics helps you design APIs correctly. GET is the only safe method. GET, PUT, and DELETE are idempotent. POST is neither safe nor idempotent. The api_route decorator can handle multiple methods if needed.

Docstrings Become API Documentation

from fastapi import FastAPI

app = FastAPI()

@app.get("/users", summary="List all users", tags=["Users"])
def list_users():
    """Retrieve a list of all registered users.

    Returns a JSON array of user objects, each containing
    id, name, and email fields.
    """
    return []

@app.post(
    "/users",
    summary="Create a user",
    description="Register a new user in the system",
    tags=["Users"],
    response_description="The newly created user",
)
def create_user():
    return {}

Function docstrings and decorator parameters automatically appear in the Swagger UI documentation. Use summary for a short description, description for detailed info, tags for grouping endpoints, and response_description for the response section.

Key points

Concepts covered

GET, POST, PUT, DELETE, PATCH, HTTP Semantics