Advertisement
🌐 Real-World

Python API Development – Build REST APIs

APIs are the backbone of modern web services. Python offers FastAPI for high performance and Flask for simplicity to build production-ready REST APIs quickly.

⏱️ 20 min read🎯 Real-WorldπŸ“… Updated 2026

FastAPI – Quick Start

Python
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float
    in_stock: bool = True

items_db = {}

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id not in items_db:
        return {"error": "Not found"}
    return items_db[item_id]

@app.post("/items/{item_id}")
def create_item(item_id: int, item: Item):
    items_db[item_id] = item
    return {"message": "Created", "item": item}

@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
    items_db[item_id] = item
    return {"message": "Updated"}

@app.delete("/items/{item_id}")
def delete_item(item_id: int):
    items_db.pop(item_id, None)
    return {"message": "Deleted"}

Running the API

Bash
pip install fastapi uvicorn
uvicorn main:app --reload
# Visit http://localhost:8000/docs for Swagger UI

Flask Alternative

Python
from flask import Flask, request, jsonify

app = Flask(__name__)
items = {}

@app.route("/items/<int:item_id>", methods=["GET"])
def get_item(item_id):
    return jsonify(items.get(item_id, {"error": "Not found"}))

@app.route("/items/<int:item_id>", methods=["POST"])
def create_item(item_id):
    data = request.get_json()
    items[item_id] = data
    return jsonify({"message": "Created"}), 201

if __name__ == "__main__":
    app.run(debug=True)

Token Authentication

Python
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import secrets

security = HTTPBearer()
API_KEY = "secret-token-123"

def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
    if not secrets.compare_digest(credentials.credentials, API_KEY):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
    return credentials.credentials

@app.get("/secure", dependencies=[Depends(verify_token)])
def secure_endpoint():
    return {"data": "Protected resource"}

Pydantic Validation

Python
from pydantic import BaseModel, validator, Field

class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=50)
    email: str
    age: int = Field(..., ge=0, le=150)

    @validator("email")
    def validate_email(cls, v):
        if "@" not in v:
            raise ValueError("Invalid email")
        return v.lower()

@app.post("/users/")
def create_user(user: UserCreate):
    return {"created": user.dict()}
Tip: Use FastAPI for new projects β€” auto-generated Swagger docs at /docs, async support, and Pydantic validation built-in.

Building an API: Resources, Methods, Status Codes

An API lets programs talk to your app over HTTP. A well-designed REST API models resources (nouns) as URLs and uses HTTP methods (verbs) for actions β€” a predictable convention clients already understand.

MethodActionExample
GETreadGET /users/5
POSTcreatePOST /users
PUT/PATCHupdatePATCH /users/5
DELETEremoveDELETE /users/5
@app.post("/users")
def create_user(user: User):
    saved = db.save(user)
    return saved, 201        # 201 Created β€” the RIGHT status for a new resource

Status codes carry meaning β€” use them correctly: 200 OK, 201 Created, 400 bad request (client's fault), 401/403 auth, 404 not found, 500 server error. Returning 200 for everything (with an error buried in the body) forces clients to guess. Design principles: use nouns for URLs (/users, not /getUsers) and let the method express the verb; make GET safe (no side effects) and PUT/DELETE idempotent (repeating them changes nothing further); version your API (/v1/) so you can evolve without breaking clients. Security: validate every input, authenticate protected endpoints, and never trust the client.

πŸ‹οΈ Practical Exercise

Build a small API:

  1. Create a FastAPI app with a GET /health route returning {"status": "ok"}.
  2. Add a POST /items route that accepts a Pydantic model and echoes it back.
  3. Protect a route with a simple token check that returns 401 on failure.
  4. Run it with uvicorn and test it via the /docs page.

πŸ”₯ Challenge Exercise

Develop a small β€œnotes” API with create, list, and get-by-id endpoints, using Pydantic models for validation and proper HTTP status codes (201 on create, 404 when missing). Add token authentication so write operations require a valid header, and return clear JSON error bodies. Bonus: write a couple of automated tests for the endpoints using TestClient.

πŸ“‹ Summary

  • An API exposes functionality over HTTP using clear endpoints and predictable responses.
  • Use the right HTTP methods (GET, POST, PUT, PATCH, DELETE) for each operation.
  • Return meaningful status codes: 200/201 for success, 400/401/404 for client errors, 500 for server errors.
  • Validate request bodies (e.g. with Pydantic) to reject bad data early.
  • Protect endpoints with authentication such as tokens or API keys.
  • Auto-generated docs (Swagger/ReDoc in FastAPI) keep the API self-describing.

Interview Questions on API Development

  • What is an API and what makes a good API design?
  • What are common HTTP methods and what does each represent?
  • What HTTP status codes should an API return for success and errors?
  • How do you validate incoming request data?
  • How do you secure an API endpoint?
  • What is the difference between authentication and authorization?
  • How do you document an API?

FAQ

What is the difference between authentication and authorization? +

Authentication verifies who you are (e.g. checking a token or password). Authorization decides what you are allowed to do (e.g. whether you can delete a resource). An API typically does both.

Which status code should I return when creating a resource? +

Return 201 Created for a successful creation, ideally with the new resource in the body and a Location header. Use 200 OK for ordinary successful reads and updates.

How do I validate incoming data? +

Define a schema β€” with Pydantic in FastAPI, for example β€” so the framework automatically checks types and required fields, converts values, and returns a clear error response when data is invalid.

Should I build my API with Flask, FastAPI, or Django? +

FastAPI is excellent for modern, async, well-documented APIs. Flask suits small or highly custom services. Django REST Framework fits when you already use Django and want a full-featured, batteries-included toolkit.