Ojasa Mirai

Ojasa Mirai

FastAPI

Loading...

Learning Level

🟢 Beginner🔵 Advanced
🚀 What is FastAPI📚 Creating Your First API📚 Running the Server📚 HTTP Methods📚 API Endpoints📚 Request and Response📚 Documentation📚 Testing Basics
Fastapi/Api Basics/Http Methods

HTTP Methods — Advanced Semantics and Patterns 🏗️

Understanding HTTP method semantics deeply is essential for building RESTful, scalable APIs.

Idempotency

Idempotent: Multiple calls have same effect as single call.

Safe/Idempotent Methods

# GET - Safe and idempotent
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # Call 100 times = same result
    return db.get(user_id)

# DELETE - Idempotent (already deleted = deleted)
@app.delete("/users/{user_id}")
async def delete_user(user_id: int):
    # Call 100 times = same effect as 1 call
    db.delete(user_id)
    return {"deleted": True}

# PUT - Idempotent (replaces with same data)
@app.put("/users/{user_id}")
async def replace_user(user_id: int, user: User):
    # Call 100 times with same data = 1 call
    db.replace(user_id, user)
    return user

Non-Idempotent Methods

# POST - Not idempotent (creates new each time)
@app.post("/orders")
async def create_order(order: Order):
    # Call 100 times = 100 orders created!
    return db.create(order)

# PATCH - Usually not idempotent (depends on state)
@app.patch("/users/{user_id}")
async def increment_score(user_id: int):
    # Call 100 times = score incremented 100 times!
    db.increment_score(user_id)
    return db.get(user_id)

Designing RESTful APIs

from fastapi import FastAPI, HTTPException, status

app = FastAPI()

# Collections
@app.get("/items")  # List
async def list_items(skip: int = 0, limit: int = 10):
    return {"items": db.list(skip, limit)}

@app.post("/items")  # Create
async def create_item(item: Item):
    new_item = db.create(item)
    return {"id": new_item.id, **new_item.dict()}

# Specific resources
@app.get("/items/{item_id}")  # Get
async def get_item(item_id: int):
    item = db.get(item_id)
    if not item:
        raise HTTPException(status_code=404)
    return item

@app.put("/items/{item_id}")  # Full update
async def replace_item(item_id: int, item: Item):
    if not db.exists(item_id):
        raise HTTPException(status_code=404)
    return db.replace(item_id, item)

@app.patch("/items/{item_id}")  # Partial update
async def update_item(item_id: int, update: ItemUpdate):
    return db.patch(item_id, update)

@app.delete("/items/{item_id}")  # Delete
async def delete_item(item_id: int):
    if not db.exists(item_id):
        raise HTTPException(status_code=404)
    db.delete(item_id)
    return None

Handling Multiple Methods on Same Route

from fastapi import Request

# Option 1: Separate decorators
@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return db.get(user_id)

@app.put("/users/{user_id}")
async def update_user(user_id: int, user: User):
    return db.replace(user_id, user)

# Option 2: Combined route (less common)
@app.api_route("/users/{user_id}", methods=["GET", "PUT"])
async def user_endpoint(request: Request, user_id: int):
    if request.method == "GET":
        return db.get(user_id)
    elif request.method == "PUT":
        body = await request.json()
        return db.replace(user_id, body)

Bulk Operations

from typing import List

@app.post("/items/bulk")
async def create_multiple(items: List[Item]):
    '''Create multiple items'''
    return [db.create(item) for item in items]

@app.put("/items/bulk")
async def update_multiple(updates: List[dict]):
    '''Update multiple items (idempotent)'''
    return [db.replace(u["id"], u) for u in updates]

@app.delete("/items")
async def delete_multiple(ids: List[int]):
    '''Delete multiple items (idempotent)'''
    for id in ids:
        db.delete(id)
    return {"deleted": len(ids)}

Error Handling by Method

from fastapi import HTTPException, status

@app.get("/items/{item_id}")
async def get_item(item_id: int):
    item = db.get(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Not found")
    return item

@app.post("/items")
async def create_item(item: Item):
    if db.exists(item.name):
        raise HTTPException(status_code=409, detail="Already exists")
    return db.create(item)

@app.put("/items/{item_id}")
async def replace_item(item_id: int, item: Item):
    if not db.exists(item_id):
        raise HTTPException(status_code=404)
    return db.replace(item_id, item)

@app.patch("/items/{item_id}")
async def patch_item(item_id: int, update: dict):
    if not db.exists(item_id):
        raise HTTPException(status_code=404)
    return db.patch(item_id, update)

🔑 Key Takeaways

  • ✅ GET/DELETE are idempotent (safe to retry)
  • ✅ POST creates new (not idempotent)
  • ✅ PUT is idempotent for replacement
  • ✅ Each method has semantic meaning
  • ✅ Design for REST principles
  • ✅ Handle errors appropriately per method

Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn