FastAPI β Quick Start
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
pip install fastapi uvicorn
uvicorn main:app --reload
# Visit http://localhost:8000/docs for Swagger UIFlask Alternative
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
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
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()}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.
| Method | Action | Example |
|---|---|---|
| GET | read | GET /users/5 |
| POST | create | POST /users |
| PUT/PATCH | update | PATCH /users/5 |
| DELETE | remove | DELETE /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:
- Create a FastAPI app with a
GET /healthroute returning{"status": "ok"}. - Add a
POST /itemsroute that accepts a Pydantic model and echoes it back. - Protect a route with a simple token check that returns 401 on failure.
- Run it with uvicorn and test it via the
/docspage.
π₯ 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?
Related Topics
FAQ
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.
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.
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.
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.
