FastAPI Complete Guide

Bilkul Zero se Pro Level tak — Step by Step

✓ Beginner Friendly • Hindi-English • 20 Chapters
01

What is an API?

Sabse pehle — API kya hai?

API ka full form hai Application Programming Interface. Sunne mein complicated lagta hai, but actually bahut simple concept hai.

🍔 Restaurant Analogy (Best Way to Understand)

Imagine karo tum ek restaurant mein ho:

  • Tum = Customer (Client/Frontend)
  • Kitchen = Server (Backend/Database)
  • Waiter = API
  • Menu = API Documentation

Tum directly kitchen mein nahi jaate. Tum waiter ko bolo (request bhejo), waiter kitchen jaata hai (server), khaana laata hai (response). Waiter hi API hai!

Technically: API ek set of rules hai jo define karta hai ki do software ek doosre se kaise baat karenge.

APIs kyun exist karte hain?

Client-Server Concept

💻 Client (Browser/App) ----request----> 🌐 Server (Backend) <----response----

REST API Kya Hai?

REST = REpresentational State Transfer. Ye ek style hai APIs banana ka. Isme rules hain:

  1. Har cheez ka ek URL hota hai (jaise /users, /products)
  2. HTTP Methods use hote hain (GET, POST, PUT, DELETE)
  3. Data mostly JSON format mein aata hai
  4. Server ko yaad nahi rehta ki pehle kya hua — stateless
💡 Simple Yaad Rakho

API = Waiter jo tumhare aur kitchen ke beech kaam karta hai. Tum menu (docs) dekho, order do (request), khaana aaye (response).

02

What is FastAPI?

FastAPI ek Python framework hai jo tumhe APIs banana sikhata hai — bahut fast aur easy tarike se.

Isko Sebastián Ramírez ne banaya hai aur ye ab Python ka sabse popular API framework ban raha hai.

FastAPI vs Flask vs Django

FeatureFastAPIFlaskDjango
SpeedBahut FastMediumSlow
Async SupportBuilt-inNahi (extra lib)Limited
Auto DocsHaan (Swagger)NahiNahi (DRF mein hai)
Type HintsBuilt-inNahiNahi
Learning CurveEasyEasyHard
Data ValidationAutomatic (Pydantic)ManualSerializers
Best ForAPIsSmall AppsFull Websites

Key Features

1. Async Support

Jab tumhara code kisi slow kaam ka wait kar raha hai (database, external API), tab doosre requests handle kar sakta hai. Ye async/await se hota hai.

🍔 Analogy: Waiter Async hai

Ek waiter ek time pe ek hi table serve kare = Synchronous (slow).

Ek waiter sabko order le le, phir sabka khaana laaye = Asynchronous (fast!).

2. Auto Documentation (Swagger)

FastAPI automatically tumhare APIs ka documentation bana deta hai. Tumhe kuch extra nahi karna. Sirf code likho — docs ready!

3. Type Hints

Python mein type hints ka matlab hai batana ki variable ka type kya hai. FastAPI isko use karke automatic validation karta hai.

# Without type hints (Flask style)
def get_user(id):   # id kya hai? string? int? pata nahi!
    pass

# With type hints (FastAPI style)
def get_user(id: int):  # id MUST be integer — automatic check!
    pass

4. Speed

FastAPI NodeJS aur Go ke karib speed deta hai. Ye Starlette (web part) aur Pydantic (data validation) pe bana hai — dono blazing fast hain.

🚀 Summary

FastAPI = Fast (performance) + Fast (development speed) + Auto docs + Validation + Async. Beginner ke liye best choice.

03

Installation & Setup

Step 1: Python Install Karo

Sabse pehle check karo Python installed hai ya nahi:

python --version
# ya
python3 --version

Agar nahi hai to python.org se download karo. Python 3.8+ chahiye.

⚠️ Important

Install karte waqt "Add Python to PATH" checkbox zaroor tick karo. Nahi kiya to terminal mein python command nahi chalega.

Step 2: Virtual Environment Banao

Virtual Environment kya hai? Ye ek isolated box hai jisme tumhare project ke packages rehte hain. Har project ka apna alag box.

📦 Analogy

Virtual environment ek alag kamra hai. Ek kamre mein FastAPI hai, doosre mein Flask. Dono ek doosre ko disturb nahi karte.

# Apna project folder banao
mkdir my-fastapi-project
cd my-fastapi-project

# Virtual environment banao
python -m venv venv

# Activate karo
# Windows:
venv\Scripts\activate
# Mac/Linux:
source venv/bin/activate

# Tumhe dikhega: (venv) C:\my-fastapi-project>

Step 3: FastAPI Install Karo

pip install fastapi uvicorn

fastapi = ye framework hai. uvicorn = ye server hai jo tumhare code ko run karta hai.

💡 Analogy

FastAPI = tumhara khaana (code). Uvicorn = gas stove (server) jispe khaana pakta hai.

Step 4: Hello World API

Ek file banao main.py:

from fastapi import FastAPI

# FastAPI ka ek instance banao (ek naya app)
app = FastAPI()

# Ye tumhara pehla API endpoint hai!
@app.get("/")
def hello():
    return {"message": "Hello World! Mera pehla API kaam kar raha hai!"}

Isko samjho line by line:

Step 5: Server Run Karo

uvicorn main:app --reload

Isko samjho:

PartMatlab
uvicornServer start karo
mainFile ka naam (main.py)
:Separator
appFastAPI instance ka naam
--reloadCode change hone pe automatically restart ho (development ke liye)

Ab browser mein jao: http://127.0.0.1:8000

Tumhe dikhega:

{
  "message": "Hello World! Mera pehla API kaam kar raha hai!"
}
🎉 Congratulations!

Tumne apna pehla API bana liya! Ab http://127.0.0.1:8000/docs pe jao — Swagger documentation automatically ban gayi!

04

HTTP Methods (VERY DETAILED)

HTTP Methods batate hain ki tum server se kya karna chahte ho. Ye request ke sath jaata hai.

🍔 Restaurant Analogy Again
  • GET = "Menu dikhao" (data lao)
  • POST = "Ye order le lo" (naya data banao)
  • PUT = "Order change karo — pura" (full update)
  • PATCH = "Sirf extra cheese add karo" (partial update)
  • DELETE = "Order cancel karo" (delete)

GET — Data Laao

GET request data laane ke liye hota hai. Browser mein jab URL type karte ho, wo GET request hai.

@app.get("/users")
def get_all_users():
    return [
        {"id": 1, "name": "Shweta", "email": "shweta@email.com"},
        {"id": 2, "name": "Rahul", "email": "rahul@email.com"}
    ]

@app.get("/users/{user_id}")
def get_one_user(user_id: int):
    return {"id": user_id, "name": "Shweta"}

POST — Naya Data Banao

POST request naya data create karne ke liye hota hai. Body mein data bhejte ho.

from pydantic import BaseModel

class User(BaseModel):
    name: str
    email: str
    age: int

@app.post("/users")
def create_user(user: User):
    # Yahan database mein save karoge
    return {"message": "User created!", "user": user}

PUT — Pura Data Update Karo

PUT = Full replacement. Poora object bhejte ho, chahe sirf ek field change hui ho.

@app.put("/users/{user_id}")
def update_user(user_id: int, user: User):
    # Poora user object replace ho jaayega
    return {"message": f"User {user_id} updated!", "user": user}

PATCH — Partial Update

PATCH = Sirf jo change hua hai wo bhejo. Baaki cheezein same rahein.

from typing import Optional

class UserUpdate(BaseModel):
    name: Optional[str] = None
    email: Optional[str] = None
    age: Optional[int] = None

@app.patch("/users/{user_id}")
def partial_update(user_id: int, user: UserUpdate):
    return {"message": f"User {user_id} partially updated!"}

DELETE — Data Hatao

@app.delete("/users/{user_id}")
def delete_user(user_id: int):
    # Database se delete karo
    return {"message": f"User {user_id} deleted!"}

HTTP Status Codes

Har response ke sath ek number aata hai jo batata hai kya hua:

CodeNaamMatlab (Simple)
200OKSab theek hai, data aa gaya
201CreatedNaya data ban gaya
204No ContentDelete ho gaya, kuch return nahi
400Bad RequestTumne galat data bheja
401UnauthorizedLogin nahi kiya
403ForbiddenLogin kiya but permission nahi hai
404Not FoundYe URL exist nahi karta
500Internal Server ErrorServer mein kuch toot gaya (backend ka bug)
💡 Status Codes Yaad Kaise Rakhein
  • 2xx = Sab badhiya ✔
  • 4xx = Tumhari galti (client error)
  • 5xx = Server ki galti (backend error)

Headers Kya Hain?

Headers = request ya response ke sath extra information. Jaise letter ke sath envelope pe likha hota hai — sender, date, etc.

HeaderMatlab
Content-Type: application/jsonBody mein JSON data hai
Authorization: Bearer <token>Login ka proof (JWT token)
Accept: application/jsonMujhe JSON response chahiye
05

What is Postman? (Complete Guide)

Postman Kya Hai?

Postman ek tool hai jisse tum APIs ko test kar sakte ho bina frontend banaye.

💡 Analogy

Imagine karo tumne kitchen banayi (backend API). Ab tum khud test karna chahte ho ki khaana sahi ban raha hai ya nahi — bina restaurant open kiye. Postman wo taste-testing tool hai.

Why Postman?

Step-by-Step Postman Guide

Step 1

Download and Install

Go to postman.com/downloads → Download → Install → Open → Create free account (ya skip karke use karo).

Step 2

Interface Samjho

Jab Postman khulega, tum ye dekhoge:

  • Left side: Collections (saved requests ka folder)
  • Center top: URL bar + Method dropdown (GET/POST/etc.)
  • Center middle: Tabs for Params, Headers, Body, etc.
  • Bottom: Response area (server ka jawab yahan dikhega)
Step 3

GET Request Bhejo

  1. Pehle apna FastAPI server run karo: uvicorn main:app --reload
  2. Postman mein method dropdown se GET select karo
  3. URL mein type karo: http://127.0.0.1:8000/users
  4. Blue "Send" button dabao
  5. Neeche response dikhega — JSON data!
Step 4

POST Request Bhejo (Data Create Karo)

  1. Method dropdown se POST select karo
  2. URL: http://127.0.0.1:8000/users
  3. Neeche "Body" tab pe click karo
  4. "raw" select karo
  5. Right side mein dropdown se "JSON" select karo
  6. Body mein JSON likho:
{
    "name": "Shweta",
    "email": "shweta@email.com",
    "age": 25
}

Phir Send dabao. Response mein "User created!" dikhega.

Step 5

PUT Request (Update)

  1. Method: PUT
  2. URL: http://127.0.0.1:8000/users/1
  3. Body (raw JSON): Poora updated user object bhejo
  4. Send
Step 6

DELETE Request

  1. Method: DELETE
  2. URL: http://127.0.0.1:8000/users/1
  3. Body ki zaroorat nahi — sirf Send dabao
Step 7

Headers Add Karna

"Headers" tab pe click karo. Key-value pairs add karo:

KeyValue
Content-Typeapplication/json
AuthorizationBearer your-jwt-token-here
Step 8

Response Padhna

Neeche response area mein ye dekhoge:

  • Body: Server ka response data (JSON)
  • Status: 200 OK, 404 Not Found, etc.
  • Time: Kitna time laga (ms mein)
  • Size: Response kitna bada hai
Step 9

Collections Mein Save Karo

  1. Request bhejne ke baad "Save" button dabao (ya Ctrl+S)
  2. "Create Collection" pe click karo
  3. Collection ka naam do: "My FastAPI Project"
  4. Request ka naam do: "Get All Users"
  5. Save karo — ab left side mein dikhai dega

Aise sabhi requests save karo. Baad mein ek click mein phir test kar sakte ho!

💡 Pro Tip

FastAPI ka /docs bhi Postman jaisa kaam karta hai! Browser mein http://127.0.0.1:8000/docs kholo — wahaan se bhi test kar sakte ho, bina Postman ke.

06

Path Parameters & Query Parameters

Path Parameters

Path parameter URL ke andar hota hai. Ye ek specific cheez identify karta hai.

# /users/5 — yahan 5 ek path parameter hai
@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id, "name": "Shweta"}

# /products/laptop — yahan "laptop" path parameter hai
@app.get("/products/{product_name}")
def get_product(product_name: str):
    return {"product": product_name}

Query Parameters

Query parameter URL ke baad ? ke baad aate hain. Ye filtering/searching ke liye use hote hain.

# /users?name=shweta&age=25
@app.get("/users")
def search_users(name: str = None, age: int = None):
    return {"name": name, "age": age}

# /products?category=electronics&min_price=1000&max_price=5000
@app.get("/products")
def filter_products(
    category: str = None,
    min_price: float = 0,
    max_price: float = 999999
):
    return {
        "category": category,
        "price_range": f"{min_price} - {max_price}"
    }

Difference Table

FeaturePath ParameterQuery Parameter
URL mein kahan/users/5/users?name=shweta
Required?Haan, alwaysNahi, optional ho sakta
Kab use karoSpecific item (by ID)Filter/Search/Pagination
ExampleUser #5 laaoSab users jinka age > 20

Dono Sath Mein

# /users/5/orders?status=delivered&page=1
@app.get("/users/{user_id}/orders")
def get_user_orders(
    user_id: int,        # path parameter
    status: str = None,  # query parameter (optional)
    page: int = 1       # query parameter (default=1)
):
    return {
        "user_id": user_id,
        "status_filter": status,
        "page": page
    }
💡 Rule of Thumb

Agar ek specific cheez chahiye → Path Parameter (/users/5). Agar filter/search karna hai → Query Parameter (/users?age=25).

07

Request Body (Pydantic Models)

Request Body Kya Hai?

Jab tum POST ya PUT request bhejte ho, tumhe data bhejna hota hai. Wo data request body mein jaata hai. Ye JSON format mein hota hai.

📦 Analogy

Path/Query parameters = envelope pe likha address. Request Body = envelope ke andar ka letter (actual content).

Pydantic Kya Hai?

Pydantic ek library hai jo data validate karti hai. Matlab check karti hai ki data sahi format mein hai ya nahi.

FastAPI mein BaseModel se class banate ho — ye tumhara data ka template hai.

from pydantic import BaseModel

class User(BaseModel):
    name: str          # name MUST be string
    email: str         # email MUST be string
    age: int           # age MUST be integer
    is_active: bool = True  # default True, optional

Ab agar koi age: "hello" bheje, FastAPI automatically error dega! Tumhe kuch check nahi karna.

Using in Routes

@app.post("/users")
def create_user(user: User):
    # user.name, user.email, user.age — sab accessible hai
    return {
        "message": f"Welcome {user.name}!",
        "data": user.model_dump()  # dict mein convert
    }

Postman se test karo:

// Body → raw → JSON
{
    "name": "Shweta",
    "email": "shweta@email.com",
    "age": 25
}

Field Validation

from pydantic import BaseModel, Field

class User(BaseModel):
    name: str = Field(
        min_length=2,
        max_length=50,
        description="User ka naam"
    )
    email: str = Field(
        pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$",
        description="Valid email address"
    )
    age: int = Field(
        ge=1,       # greater than or equal to 1
        le=120,     # less than or equal to 120
        description="Age 1-120 ke beech"
    )
    salary: float = Field(
        gt=0,       # greater than 0
        description="Positive salary"
    )

Optional Fields

from typing import Optional

class UserUpdate(BaseModel):
    name: Optional[str] = None       # bhejo ya na bhejo
    email: Optional[str] = None
    age: Optional[int] = None
    phone: str = "Not provided"   # default value

Nested Models (Model ke andar Model)

class Address(BaseModel):
    street: str
    city: str
    pincode: str

class User(BaseModel):
    name: str
    email: str
    address: Address  # Nested model!

JSON body aise dikhegi:

{
    "name": "Shweta",
    "email": "shweta@email.com",
    "address": {
        "street": "MG Road",
        "city": "Mumbai",
        "pincode": "400001"
    }
}
08

Response Models

response_model Kya Hai?

Jab tum data bhejte ho response mein, response_model batata hai ki kaunsa data bhejana hai aur kaunsa nahi.

💡 Analogy

Database mein password stored hai. Lekin response mein password nahi bhejna — response_model filter ka kaam karta hai.

# Ye model data RECEIVE karne ke liye (input)
class UserCreate(BaseModel):
    name: str
    email: str
    password: str   # password input mein aayega

# Ye model data SEND karne ke liye (output)
class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    # password NAHI hai — response mein nahi jaayega!

@app.post("/users", response_model=UserResponse)
def create_user(user: UserCreate):
    # Database mein save karo (including password)
    # But response mein sirf name, email jaayega
    new_user = {"id": 1, "name": user.name, "email": user.email}
    return new_user

List Response

from typing import List

@app.get("/users", response_model=List[UserResponse])
def get_all_users():
    return [
        {"id": 1, "name": "Shweta", "email": "s@e.com"},
        {"id": 2, "name": "Rahul", "email": "r@e.com"}
    ]
💡 Key Point

Input model (request) aur Output model (response) alag rakho. Kabhi password response mein mat bhejo!

09

Database Connection (SQLAlchemy)

ORM Kya Hai?

ORM = Object Relational Mapping. Ye ek tarika hai database ke sath kaam karne ka bina SQL likhein.

💡 Analogy

Bina ORM: SELECT * FROM users WHERE id = 5 (raw SQL)

ORM se: db.query(User).filter(User.id == 5).first() (Python!)

ORM tumhare Python objects ko automatically SQL queries mein convert karta hai.

Install Packages

# SQLAlchemy (ORM) + SQLite (database)
pip install sqlalchemy

# MySQL ke liye extra
pip install pymysql

# PostgreSQL ke liye extra
pip install psycopg2-binary

database.py — Database Setup

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# SQLite (file-based, easy, no setup needed)
SQLALCHEMY_DATABASE_URL = "sqlite:///./myapp.db"

# MySQL example:
# SQLALCHEMY_DATABASE_URL = "mysql+pymysql://user:password@localhost/dbname"

# Engine = database se connection
engine = create_engine(
    SQLALCHEMY_DATABASE_URL,
    connect_args={"check_same_thread": False}  # sirf SQLite ke liye
)

# Session = ek conversation with database
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# Base = sabhi models ka parent
Base = declarative_base()

models.py — Database Tables

from sqlalchemy import Column, Integer, String, Boolean
from database import Base

class User(Base):
    __tablename__ = "users"  # table ka naam

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(50), nullable=False)
    email = Column(String(100), unique=True, index=True)
    password = Column(String(100))
    is_active = Column(Boolean, default=True)

Session Management (Dependency)

# main.py mein
from database import SessionLocal, engine, Base

# Tables create karo (pehli baar)
Base.metadata.create_all(bind=engine)

# Har request ke liye ek session do, baad mein band karo
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
💡 SQLite vs MySQL

SQLite = Ek file hai (myapp.db), koi setup nahi. Learning ke liye perfect.

MySQL = Alag server chalta hai, production ke liye better. Connection string change karo bas.

10

CRUD Operations (Complete Working Example)

CRUD = Create, Read, Update, Delete. Ye har application ka base hai.

schemas.py (Pydantic Models)

from pydantic import BaseModel
from typing import Optional

class UserCreate(BaseModel):
    name: str
    email: str
    password: str

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    is_active: bool

    class Config:
        from_attributes = True  # SQLAlchemy object se convert

class UserUpdate(BaseModel):
    name: Optional[str] = None
    email: Optional[str] = None

main.py (All CRUD Routes)

from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
import models, schemas
from database import SessionLocal, engine, Base

Base.metadata.create_all(bind=engine)
app = FastAPI()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# ==========================================
# CREATE - Naya user banao
# ==========================================
@app.post("/users", response_model=schemas.UserResponse, status_code=201)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    # Check: email pehle se toh nahi hai?
    existing = db.query(models.User).filter(
        models.User.email == user.email
    ).first()
    if existing:
        raise HTTPException(status_code=400, detail="Email already registered")

    # Naya user banao
    new_user = models.User(
        name=user.name,
        email=user.email,
        password=user.password  # real mein hash karo!
    )
    db.add(new_user)
    db.commit()
    db.refresh(new_user)
    return new_user

# ==========================================
# READ ALL - Sab users laao (with pagination)
# ==========================================
@app.get("/users", response_model=List[schemas.UserResponse])
def get_all_users(
    skip: int = 0,    # kitne skip karo (pagination)
    limit: int = 10,  # kitne laao (max)
    db: Session = Depends(get_db)
):
    users = db.query(models.User).offset(skip).limit(limit).all()
    return users

# ==========================================
# READ ONE - Ek specific user laao (by ID)
# ==========================================
@app.get("/users/{user_id}", response_model=schemas.UserResponse)
def get_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(models.User).filter(models.User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

# ==========================================
# UPDATE - User ko update karo
# ==========================================
@app.put("/users/{user_id}", response_model=schemas.UserResponse)
def update_user(
    user_id: int,
    user_data: schemas.UserUpdate,
    db: Session = Depends(get_db)
):
    user = db.query(models.User).filter(models.User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    # Sirf wo fields update karo jo bheje hain
    update_data = user_data.model_dump(exclude_unset=True)
    for key, value in update_data.items():
        setattr(user, key, value)

    db.commit()
    db.refresh(user)
    return user

# ==========================================
# DELETE - User ko delete karo
# ==========================================
@app.delete("/users/{user_id}", status_code=204)
def delete_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(models.User).filter(models.User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    db.delete(user)
    db.commit()
    return None
🚀 Test Karo Postman Se!

POST /users → user banao → GET /users → sab dekho → GET /users/1 → ek dekho → PUT /users/1 → update → DELETE /users/1 → delete.

11

Error Handling

HTTPException

Jab kuch galat ho, tum HTTPException raise karte ho. Ye ek error response bhejta hai proper status code ke sath.

from fastapi import HTTPException

@app.get("/users/{user_id}")
def get_user(user_id: int):
    if user_id < 1:
        raise HTTPException(
            status_code=400,
            detail="User ID must be positive"
        )
    if user_id > 1000:
        raise HTTPException(
            status_code=404,
            detail="User not found"
        )
    return {"id": user_id, "name": "Shweta"}

Custom Error Response

raise HTTPException(
    status_code=403,
    detail={
        "error": "Access Denied",
        "message": "Tumhe isko access karne ki permission nahi hai"
    },
    headers={"X-Error": "Permission denied"}
)

Validation Errors (Automatic!)

Agar koi galat data bheje (jaise age mein string), FastAPI automatically 422 error dega:

{
    "detail": [
        {
            "loc": ["body", "age"],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

Try-Except in Routes

@app.get("/divide/{a}/{b}")
def divide(a: int, b: int):
    try:
        result = a / b
        return {"result": result}
    except ZeroDivisionError:
        raise HTTPException(
            status_code=400,
            detail="Zero se divide nahi kar sakte bhai!"
        )

Global Exception Handler

from fastapi import Request
from fastapi.responses import JSONResponse

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    return JSONResponse(
        status_code=500,
        content={
            "error": "Internal Server Error",
            "message": "Kuch toh gadbad hai! Hum check kar rahe hain."
        }
    )
12

Middleware

Middleware Kya Hai?

Middleware ek security guard hai jo har request aur response ke beech baitha hai. Har request middleware se hokar jaati hai.

Client → [Middleware] → Route Handler → [Middleware] → Client (request check) (response modify)

CORS Middleware (Most Important!)

CORS = Cross-Origin Resource Sharing. Jab tumhara frontend (localhost:3000) backend (localhost:8000) se baat kare, browser block kar deta hai. CORS middleware allow karta hai.

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],  # frontend URL
    allow_credentials=True,
    allow_methods=["*"],   # GET, POST, PUT, DELETE sab allow
    allow_headers=["*"],   # sab headers allow
)

Custom Middleware (Logging)

import time
from fastapi import Request

@app.middleware("http")
async def log_requests(request: Request, call_next):
    # Request aane se PEHLE
    start_time = time.time()
    method = request.method
    url = request.url.path

    # Route handler ko call karo
    response = await call_next(request)

    # Response jaane se PEHLE
    duration = time.time() - start_time
    print(f"{method} {url} - {response.status_code} - {duration:.3f}s")

    return response
💡 Kab Use Karo
  • CORS — Jab frontend alag port pe ho
  • Logging — Har request log karna ho
  • Authentication — Har request mein token check karna ho
  • Rate Limiting — Too many requests rok na ho
13

Authentication (JWT)

Authentication vs Authorization

Authentication (Kaun ho tum?)

Ye verify karta hai ki tum kaun ho.

Example: Login karna (username + password)

Authorization (Kya kar sakte ho?)

Ye check karta hai ki tumhe permission hai ya nahi.

Example: Admin page access sirf admin ko mile

JWT Token Kya Hai?

JWT = JSON Web Token. Ye ek pass hai jo login ke baad milta hai.

🎢 Analogy: Movie Ticket

Tum ticket counter pe jaate ho (login), ID dikhate ho (password), ticket milti hai (JWT token). Ab har theater hall mein ticket dikhate ho (har request mein token bhejte ho). Security check karta hai ticket valid hai ya nahi.

Install Packages

pip install python-jose[cryptography] passlib[bcrypt]

Password Hashing

from passlib.context import CryptContext

# Password hasher setup
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Password hash karo (save karne se pehle)
def hash_password(password: str) -> str:
    return pwd_context.hash(password)

# Password verify karo (login ke time)
def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)
⚠️ NEVER Store Plain Passwords!

Kabhi bhi password directly database mein mat save karo. Hamesha hash karo. Hash = one-way encryption. "password123" → "$2b$12$LJ3..."

JWT Token Create & Verify

from jose import JWTError, jwt
from datetime import datetime, timedelta

SECRET_KEY = "tumhara-secret-key-bahut-lamba-rakho"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    token = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return token

def verify_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except JWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

Login Route

from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")

@app.post("/login")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # Database se user dhoondho
    user = find_user_by_email(form_data.username)  # implement karo
    if not user or not verify_password(form_data.password, user.password):
        raise HTTPException(status_code=401, detail="Galat email ya password")

    # Token banao
    token = create_access_token({"sub": user.email})
    return {"access_token": token, "token_type": "bearer"}

# Protected Route
def get_current_user(token: str = Depends(oauth2_scheme)):
    payload = verify_token(token)
    email = payload.get("sub")
    if not email:
        raise HTTPException(status_code=401, detail="Invalid token")
    return email

@app.get("/profile")
def my_profile(current_user: str = Depends(get_current_user)):
    return {"email": current_user, "message": "Welcome to your profile!"}
Login Flow: 1. User bhejta hai: email + password 2. Server check karta hai password 3. Sahi hai → JWT token return karo 4. User har request mein token bhejta hai (Header: Authorization: Bearer <token>) 5. Server token verify karta hai 6. Valid hai → data do. Invalid → 401 error
14

File Upload

Install Extra

pip install python-multipart

Basic File Upload

from fastapi import UploadFile, File
import shutil
from pathlib import Path

# Uploads folder banao
UPLOAD_DIR = Path("uploads")
UPLOAD_DIR.mkdir(exist_ok=True)

@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
    # File ko disk pe save karo
    file_path = UPLOAD_DIR / file.filename
    with open(file_path, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)

    return {
        "filename": file.filename,
        "size": file.size,
        "content_type": file.content_type,
        "message": "File uploaded successfully!"
    }

File Validation (Size + Type)

ALLOWED_TYPES = ["image/jpeg", "image/png", "image/gif"]
MAX_SIZE = 5 * 1024 * 1024  # 5 MB

@app.post("/upload-image")
async def upload_image(file: UploadFile = File(...)):
    # Type check
    if file.content_type not in ALLOWED_TYPES:
        raise HTTPException(
            status_code=400,
            detail=f"Sirf images allowed hain! (JPEG, PNG, GIF)"
        )

    # Size check
    contents = await file.read()
    if len(contents) > MAX_SIZE:
        raise HTTPException(
            status_code=400,
            detail="File 5MB se badi hai!"
        )

    # Save
    file_path = UPLOAD_DIR / file.filename
    with open(file_path, "wb") as f:
        f.write(contents)

    return {"message": "Image uploaded!", "filename": file.filename}

Multiple Files

from typing import List

@app.post("/upload-multiple")
async def upload_many(files: List[UploadFile] = File(...)):
    filenames = []
    for file in files:
        file_path = UPLOAD_DIR / file.filename
        with open(file_path, "wb") as buffer:
            shutil.copyfileobj(file.file, buffer)
        filenames.append(file.filename)

    return {"uploaded": filenames, "count": len(filenames)}
15

Dependency Injection

DI Kya Hai? (Simple Explanation)

Dependency Injection = Kisi cheez ko function ke andar automatically dena, bina baar baar likhein.

💡 Analogy

Har room mein light switch hai. Tum switch dabate ho, bijli aati hai. Tumhe bijli station se wire nahi laani. Bijli automatically inject hoti hai.

Waise hi Depends(get_db) se database session automatically inject hota hai har route mein.

Database Session as Dependency

from fastapi import Depends

# Ye dependency hai — har route ko db session deta hai
def get_db():
    db = SessionLocal()
    try:
        yield db       # db session do
    finally:
        db.close()    # kaam hone pe band karo

# Route mein use karo — db automatically milta hai!
@app.get("/users")
def get_users(db: Session = Depends(get_db)):
    return db.query(User).all()

Custom Dependencies

# Pagination dependency
def pagination_params(page: int = 1, size: int = 10):
    return {"skip": (page - 1) * size, "limit": size}

@app.get("/products")
def get_products(pagination: dict = Depends(pagination_params)):
    # pagination = {"skip": 0, "limit": 10}
    return db.query(Product).offset(pagination["skip"]).limit(pagination["limit"]).all()

# Auth dependency — har protected route mein use karo
def require_admin(current_user = Depends(get_current_user)):
    if current_user.role != "admin":
        raise HTTPException(status_code=403, detail="Admin only!")
    return current_user

@app.delete("/admin/users/{id}")
def admin_delete(id: int, admin = Depends(require_admin)):
    # Sirf admin yahan aa sakta hai
    pass
💡 DI Kyun Use Karo?
  • DRY — Same code baar baar nahi likhna (database connection, auth check)
  • Testable — Testing mein dependency ko mock kar sakte ho
  • Clean — Route function sirf apna kaam kare, baaki Depends handle kare
16

Project Structure (Best Practice)

Jab project bada hota hai, sab kuch ek file mein nahi rakh sakte. Files ko organize karo:

my-fastapi-project/ ├── main.py # App entry point, routes include karo ├── database.py # Database connection setup ├── models.py # SQLAlchemy models (database tables) ├── schemas.py # Pydantic models (request/response) ├── auth.py # JWT + password hashing ├── requirements.txt # Sab packages ki list ├── .env # Secret keys, database URL ├── routes/ # Alag alag routes ka folder │ ├── users.py # /users ke sab routes │ ├── products.py # /products ke sab routes │ └── auth.py # /login, /register routes ├── services/ # Business logic │ ├── user_service.py │ └── product_service.py └── uploads/ # Uploaded files

Router Use Karo (Alag files mein routes)

routes/users.py

from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session

router = APIRouter(
    prefix="/users",    # sab routes /users se start honge
    tags=["Users"]      # Swagger docs mein group dikhega
)

@router.get("/")
def get_users(db: Session = Depends(get_db)):
    return db.query(User).all()

@router.post("/")
def create_user(user: UserCreate, db: Session = Depends(get_db)):
    # ... create logic
    pass

main.py

from fastapi import FastAPI
from routes import users, products, auth

app = FastAPI(title="My Awesome API")

# Routers include karo
app.include_router(users.router)
app.include_router(products.router)
app.include_router(auth.router)

@app.get("/")
def root():
    return {"message": "API is running!"}
💡 Kyun Alag Files?
  • Organization — Users ka code users.py mein, products ka products.py mein
  • Team Work — Ek banda users pe kaam kare, doosra products pe
  • Readability — 100-line file padhna easy hai, 5000-line file mushkil
17

Swagger UI / Docs

Auto Documentation

FastAPI ka sabse amazing feature — documentation automatically banti hai! Kuch nahi karna.

URLKya HaiUse
/docsSwagger UIInteractive — test bhi kar sakte ho
/redocReDocBeautiful read-only documentation
/openapi.jsonOpenAPI SchemaRaw JSON schema (tools ke liye)

Swagger Se API Test Kaise Karo

  1. Browser mein http://127.0.0.1:8000/docs kholo
  2. Tumhe sab routes dikhenge, colors ke sath (GET=green, POST=blue, etc.)
  3. Kisi bhi route pe click karo → expand hoga
  4. "Try it out" button dabao
  5. Agar body chahiye to JSON bharo
  6. "Execute" dabao
  7. Neeche response dikhega — status code, body, headers sab

Docs Customize Karo

app = FastAPI(
    title="Shweta's API",
    description="Mera pehla FastAPI project! Sab kuch yahan hai.",
    version="1.0.0",
    docs_url="/docs",       # ya None to disable
    redoc_url="/redoc",     # ya None to disable
)
💡 Pro Tip

Swagger docs = free Postman! Bina Postman install kiye browser mein hi sab test kar sakte ho. Plus ye automatically update hota hai jab code change hota hai.

18

Deployment Basics

Uvicorn Kya Hai?

Uvicorn = ASGI server. Ye tumhare Python code ko HTTP requests handle karne laayak banata hai. Development mein directly use karte hain.

# Development
uvicorn main:app --reload --host 0.0.0.0 --port 8000

Gunicorn Kya Hai?

Gunicorn = Production server. Ye Uvicorn ke manager jaisa hai — multiple workers chalata hai.

# Production (4 workers)
pip install gunicorn
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

Uvicorn (Development)

Single process. --reload supported. Fast to start. Good for coding.

Gunicorn (Production)

Multiple workers. No reload. Handles more traffic. Crash recovery.

Docker Basics

Docker = tumhara code ek box mein pack karo. Kisi bhi machine pe chalega, bina "mere machine pe toh chal raha tha" wala problem.

requirements.txt

fastapi==0.109.0
uvicorn==0.27.0
sqlalchemy==2.0.25
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.6

Dockerfile

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# Docker image banao
docker build -t my-fastapi-app .

# Container chalao
docker run -p 8000:8000 my-fastapi-app

Environment Variables

import os
from dotenv import load_dotenv

load_dotenv()  # .env file se variables load karo

SECRET_KEY = os.getenv("SECRET_KEY", "default-key")
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./app.db")

.env file

SECRET_KEY=mera-bahut-lamba-secret-key-yahan
DATABASE_URL=mysql+pymysql://user:pass@localhost/mydb
DEBUG=True
⚠️ NEVER commit .env to git!

.gitignore mein .env zaroor dalo. Secret keys git mein nahi jaani chahiye.

19

Common Interview Questions (Top 20)

Q1: FastAPI kya hai aur Flask se kaise different hai?
FastAPI ek modern Python web framework hai jo high-performance APIs banana ke liye use hota hai. Flask se different hai kyunki: (1) Built-in async support hai, (2) Automatic data validation via Pydantic, (3) Auto-generated Swagger docs, (4) Type hints se request/response automatically validate hoti hai. Speed wise FastAPI Flask se bahut fast hai.
Q2: ASGI aur WSGI mein kya fark hai?
WSGI (Web Server Gateway Interface) synchronous hai — ek request aaye, process ho, phir doosri. Flask aur Django WSGI use karte hain. ASGI (Asynchronous Server Gateway Interface) async hai — multiple requests simultaneously handle kar sakta hai. FastAPI ASGI use karta hai (Uvicorn ke sath).
Q3: Pydantic kya hai aur FastAPI mein kaise use hota hai?
Pydantic ek data validation library hai. FastAPI mein BaseModel classes se request/response ka structure define karte hain. Ye automatic type checking, validation, aur serialization karta hai. Agar koi galat data bheje to automatically 422 error deta hai.
Q4: Path parameters aur query parameters mein kya fark hai?
Path parameter URL ka part hai (/users/5) — required hota hai, specific resource identify karta hai. Query parameter URL ke baad ? ke baad aata hai (/users?age=25) — optional hota hai, filtering/searching ke liye use hota hai.
Q5: Dependency Injection FastAPI mein kya hai?
DI ek pattern hai jisme function ko apni dependencies khud banane ki zaroorat nahi hoti — wo automatically inject hoti hain. FastAPI mein Depends() function se dependencies inject karte hain. Common use: database session, authentication, pagination parameters.
Q6: FastAPI mein async/await kab use karo?
Jab I/O operations ho — database queries, external API calls, file read/write — tab async def use karo. CPU-heavy kaam (calculations) ke liye normal def better hai. Async se server busy hone pe bhi doosri requests handle kar sakta hai.
Q7: HTTPException kya hai?
HTTPException FastAPI ka built-in error raiser hai. Jab kuch galat ho — user na mile, permission na ho — tab raise HTTPException(status_code=404, detail="Not found") karte hain. Ye proper HTTP error response bhejta hai.
Q8: Middleware kya hai aur kab use hota hai?
Middleware ek layer hai jo har request/response ke beech process hota hai. Use cases: CORS (cross-origin requests allow karna), logging (har request log karna), authentication check, rate limiting. @app.middleware("http") se custom middleware bana sakte ho.
Q9: response_model kyun use karte hain?
response_model define karta hai ki response mein kaunsa data jaayega. Iska main use: sensitive data (jaise password) ko response se filter karna. Plus automatic documentation mein response ka structure dikhata hai.
Q10: FastAPI mein CORS kya hai?
CORS (Cross-Origin Resource Sharing) browser ka security feature hai. Jab frontend (localhost:3000) backend (localhost:8000) se request kare, browser block karta hai. CORSMiddleware add karke specific origins ko allow karte hain.
Q11: JWT authentication ka flow samjhao.
1) User email+password bhejta hai (POST /login). 2) Server password verify karta hai. 3) Sahi hone pe JWT token generate karke return karta hai. 4) User har agle request mein token bhejta hai (Authorization header). 5) Server token verify karta hai. 6) Valid hai to request process hoti hai, nahi to 401 error.
Q12: SQLAlchemy ORM kya hai?
ORM (Object Relational Mapping) Python objects ko database tables se map karta hai. SQL likhne ki zaroorat nahi — Python code se CRUD operations karte hain. db.query(User).filter(User.id == 5).first() internally SELECT * FROM users WHERE id = 5 ban jaata hai.
Q13: FastAPI mein file upload kaise karte hain?
UploadFile class se. python-multipart package install karo. Route mein file: UploadFile = File(...) parameter do. File attributes: filename, content_type, size. file.read() se content padho aur disk pe save karo.
Q14: APIRouter kya hai?
APIRouter se routes ko alag files mein organize karte hain. Har module (users, products) ka apna router hota hai. Main app mein app.include_router(users.router) se include karte hain. Prefix aur tags bhi set kar sakte hain.
Q15: Background Tasks kya hain?
Kuch kaam hain jo response ke baad ho sakte hain — email bhejna, log file likhna. BackgroundTasks se ye kaam schedule kar sakte ho. Response pehle jaata hai, kaam background mein hota hai. User ko wait nahi karna padta.
Q16: Uvicorn kya hai?
Uvicorn ek ASGI server hai. Ye tumhare FastAPI code ko run karta hai aur HTTP requests ko handle karta hai. Development mein --reload flag se auto-restart hota hai. Production mein Gunicorn ke sath use karte hain multiple workers ke liye.
Q17: Status codes ka kya matlab hai?
2xx = success (200 OK, 201 Created, 204 No Content). 4xx = client error (400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 422 Validation Error). 5xx = server error (500 Internal Error). FastAPI mein status_code parameter se set karte hain.
Q18: FastAPI mein testing kaise karte hain?
TestClient use karte hain (from fastapi.testclient). Ye internally requests library use karta hai. client = TestClient(app) bana ke client.get("/users") se test karte hain. Pytest framework ke sath commonly use hota hai.
Q19: Pydantic mein Optional field kaise banate hain?
from typing import Optional import karke field_name: Optional[str] = None likhte hain. Ye field optional ban jaata hai — request mein bhejo ya na bhejo, dono chalega. Default value None hogi agar nahi bheja.
Q20: FastAPI mein error handling best practices kya hain?
1) HTTPException use karo proper status codes ke sath. 2) Custom exception handlers banao for global error handling. 3) Pydantic validation errors ko customize karo. 4) Try-except mein specific exceptions catch karo (bare except nahi). 5) Meaningful error messages do. 6) Production mein stack traces client ko mat bhejo.
20

Quick Reference Card (Cheat Sheet)

Decorators

@app.get("/path") @app.post("/path") @app.put("/path") @app.patch("/path") @app.delete("/path") @app.middleware("http") @app.exception_handler(Exc) @app.on_event("startup") @app.on_event("shutdown")

Common Imports

from fastapi import FastAPI from fastapi import Depends from fastapi import HTTPException from fastapi import APIRouter from fastapi import UploadFile, File from fastapi import Query, Path, Body from fastapi import BackgroundTasks from pydantic import BaseModel, Field from typing import Optional, List

Status Codes

200 OK (GET success) 201 Created (POST success) 204 No Content (DELETE success) 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 422 Validation Error 500 Internal Server Error

Pydantic Quick

name: str age: int price: float is_active: bool tags: List[str] name: Optional[str] = None age: int = Field(ge=1, le=120) email: str = Field(pattern=r"...") user.model_dump()

Database (SQLAlchemy)

db.query(Model).all() db.query(Model).first() db.query(M).filter(M.id==x) db.add(new_object) db.commit() db.refresh(object) db.delete(object) .offset(skip).limit(limit)

Terminal Commands

pip install fastapi uvicorn uvicorn main:app --reload python -m venv venv source venv/bin/activate pip freeze > requirements.txt pip install -r requirements.txt docker build -t app . docker run -p 8000:8000 app

Quick CRUD Template

from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from typing import Optional, List

app = FastAPI()

# ---- Schema ----
class ItemCreate(BaseModel):
    name: str
    price: float

class ItemResponse(BaseModel):
    id: int
    name: str
    price: float

# ---- In-memory DB (testing ke liye) ----
items_db = []
counter = 0

# ---- Routes ----
@app.post("/items", response_model=ItemResponse, status_code=201)
def create(item: ItemCreate):
    global counter
    counter += 1
    new = {"id": counter, **item.model_dump()}
    items_db.append(new)
    return new

@app.get("/items", response_model=List[ItemResponse])
def read_all():
    return items_db

@app.get("/items/{id}", response_model=ItemResponse)
def read_one(id: int):
    item = next((i for i in items_db if i["id"] == id), None)
    if not item:
        raise HTTPException(404, "Not found")
    return item

@app.delete("/items/{id}", status_code=204)
def delete(id: int):
    global items_db
    items_db = [i for i in items_db if i["id"] != id]
🎉 Congratulations! Guide Complete!

Ab tum FastAPI ke sab basics jaante ho. Practice karo, projects banao, aur interview mein rock karo! 💪

Made with care. Keep learning, keep building.