HTTP methods and REST principles form the foundation of modern API communication between clients and servers. HTTP methods such as GET, POST, PUT, DELETE, and PATCH define clear actions for interacting with resources, while REST provides a structured architectural style that promotes statelessness, resource-based URLs, and standardized interactions. Together, they help backend systems expose data and functionality in a consistent and scalable way.
What Are HTTP Methods?
HTTP methods (also called verbs) define the action a client wants to perform on a server resource. They turn the web into a dynamic platform beyond just reading pages. Each method has a specific purpose, safety level (read-only or not), and idempotency (repeatable without side effects).
.png)
Key Concepts
1. Safe methods (like GET) don't change server state—browsers and caches love them.
2. Idempotent methods (GET, PUT, DELETE) yield the same result if repeated, preventing accidental duplicates.
Deep Dive into Each HTTP Method
GET: Read Data
Use GET to fetch resources without side effects. Append query parameters for filtering, e.g., /users?id=123.
Example in FastAPI
from fastapi import FastAPI
app = FastAPI()
users_db = [{"id": 1, "name": "Alice", "email": "alice@example.com"}]
@app.get("/users/{user_id}")
async def get_user(user_id: int):
user = next((u for u in users_db if u["id"] == user_id), None)
if not user:
return {"error": "User not found"}, 404
return userTest it: GET /users/1 returns {"id":1,"name":"Alice","email":"alice@example.com"}.
POST: Create Resources
POST submits data to create new items. The server assigns the ID, and responses often include 201 Created with a Location header.
Example
@app.post("/users/")
async def create_user(name: str, email: str):
new_user = {"id": len(users_db) + 1, "name": name, "email": email}
users_db.append(new_user)
return new_user, 201 # Include Location: /users/{id} in productionTest: POST /users/ with {"name":"Bob","email":"bob@example.com"}.
PUT: Full Replace
PUT updates or creates a resource by replacing it entirely. Send the full resource body—if partial, it overwrites missing fields with defaults/null.
Example
@app.put("/users/{user_id}")
async def update_user(user_id: int, name: str, email: str):
for user in users_db:
if user["id"] == user_id:
user["name"] = name
user["email"] = email
return user
return {"error": "User not found"}, 404DELETE: Remove Resources
DELETE removes a resource permanently. Return 204 No Content on success.
Example:
@app.delete("/users/{user_id}")
async def delete_user(user_id: int):
global users_db
users_db = [u for u in users_db if u["id"] != user_id]
return None, 204PATCH: Partial Updates
PATCH modifies only specified fields, ideal for large resources. Use JSON Patch (RFC 6902) or merge semantics.
Example (using Pydantic for partial updates)
from pydantic import BaseModel
from typing import Optional
class UserUpdate(BaseModel):
name: Optional[str] = None
email: Optional[str] = None
@app.patch("/users/{user_id}")
async def patch_user(user_id: int, update: UserUpdate):
user = next((u for u in users_db if u["id"] == user_id), None)
if not user:
return {"error": "User not found"}, 404
if update.name:
user["name"] = update.name
if update.email:
user["email"] = update.email
return userTest: PATCH /users/1 with {"email": "new@example.com"}—name stays unchanged.
REST Principles: Building Clean APIs
REST (Representational State Transfer) is an architectural style for APIs, popularized by Roy Fielding. It leverages HTTP to create predictable, scalable services. Follow these 6 constraints for true RESTfulness:
1. Client-Server Separation: Clients (frontend) and servers (API) evolve independently.
2. Stateless: Each request contains all needed info—no server session state. Use tokens (JWT) for auth.
3. Cacheable: Mark responses as cacheable (e.g., GET with Cache-Control headers) to boost performance.
4. Uniform Interface
Resource identification via URLs (e.g., /users/1).
Manipulate via HTTP methods.
Self-descriptive messages (use proper status codes: 200 OK, 404 Not Found).
HATEOAS (Hypermedia as Engine of Application State): Include links, e.g., {"user": {...}, "_links": {"self": "/users/1"}}.
5. Layered System: Proxies, load balancers sit between client/server transparently.
6. Code on Demand (optional): Servers send executable code (rare in APIs).
RESTful URL Design Tips
1. Nouns for resources: /users, /users/1/orders.
2. Avoid verbs: Bad /getUser/1, Good /users/1.
3. Plural: /users over /user.
4. Nested: /users/1/posts/5.
Status Codes to Master
1. 400 Bad Request, 401 Unauthorized, 403 Forbidden.
2. 404 Not Found, 500 Internal Server Error.
Best Practices and Common Pitfalls
1. Validate inputs always—use Pydantic in FastAPI.
2. Version your API: /v1/users to evolve without breaking clients.
3. Handle errors gracefully: Return JSON {"error": "msg", "code": 400}.
4. Pitfall: Don't use GET for mutations (e.g., no GET /delete/1).
5. Security: Enable CORS, rate limiting; HTTPS everywhere.
6. Pagination: For lists, add ?page=1&limit=20.
7. Full FastAPI Example (Run with uvicorn main:app):
Combine all methods into one app for testing via /docs.