FastAPI Essentials

Course Content

FastAPI Essentials

1 sections · 32 lessons

Can you give me an example of how to use HTTP methods with routes in FastAPI?


What each method promisesyesyes200nono201noyes200nonot always200noyes204safeidempotentstatusGETPOSTPUTPATCHDELETE
PUT replaces the whole resource and is safe to retry; POST is neither, which is why retried POSTs need an idempotency key.

What you need to know

MethodPurposeSafe (no change)?Idempotent?Typical status
GETReadYesYes200
POSTCreate, or run an actionNoNo201 or 200
PUTReplace the whole resourceNoYes200
PATCHChange some fieldsNoNot guaranteed200
DELETERemoveNoYes204

A prompt-template service built on one router:

Python
from fastapi import APIRouter, FastAPI, HTTPExceptionrouter = APIRouter(prefix="/templates", tags=["prompts"])@router.get("")def list_templates(limit: int = 20) -> list[Template]:    return list(DB.values())[:limit]@router.post("", status_code=201)def create_template(body: TemplateIn) -> Template:    t = Template(id=len(DB) + 1, **body.model_dump())    DB[t.id] = t    return t@router.put("/{tid}")def replace_template(tid: int, body: TemplateIn) -> Template:    DB[tid] = Template(id=tid, **body.model_dump())    return DB[tid]@router.patch("/{tid}")def update_template(tid: int, body: TemplatePatch) -> Template:    if tid not in DB:        raise HTTPException(404, "Template not found")    changes = body.model_dump(exclude_unset=True)     # only the fields the client sent    DB[tid] = DB[tid].model_copy(update=changes)    return DB[tid]@router.delete("/{tid}", status_code=204)def delete_template(tid: int) -> None:    DB.pop(tid, None)app = FastAPI()app.include_router(router)

TemplateIn has name, text and temperature (default 0.2). TemplatePatch has the same fields, all optional. Real responses:

Text
POST   /templates {"name": "refund", "text": "..."}      -> 201 {... 'temperature': 0.2, 'id': 1}PATCH  /templates/1 {"temperature": 0.7}                  -> 200 {'name': 'refund', ..., 'temperature': 0.7}PUT    /templates/1 {"name": "refund-v2", "text": "Be brief."} -> 200 {..., 'temperature': 0.2}DELETE /templates/1                                       -> 204 b''DELETE /templates/1 (again)                               -> 204PUT    /templates                                         -> 405

Look at PUT: the client did not send temperature, so it went back to the default 0.2. PUT replaces. PATCH with exclude_unset=True changed only the field that was sent. The second DELETE also returned 204 — idempotent. A method the path does not support returns 405.

A real-life example

A marketing team edits prompt templates from an internal tool. A developer implemented "edit" as PUT but the front end sent only the changed field. Every edit silently reset temperature and max_tokens to defaults, and product descriptions became noticeably more random for a week before anyone connected the two.

The fix was to use PATCH with exclude_unset=True for partial edits and keep PUT for "save the whole form". A second fix came from the idempotency rule: the tool retried failed POSTs automatically, which created duplicate templates. The team added an Idempotency-Key header, stored with each created template, so a retried POST returns the first result instead of creating another.

Follow-up questions to expect

  • "Why is /predict a POST, not a GET?" — The input is large and often private; URLs have length limits and are written to access logs and browser history. POST puts the input in the body.
  • "What status code for a successful DELETE?" — 204 No Content, with an empty body. FastAPI sends no body when you set status_code=204.
  • "How do you make a POST safe to retry?" — Accept an idempotency key from the client, store it with the result, and return the stored result for a repeated key.