Fast API Learning

1.API
2.FastAPI
3.FastAPI HTTP Status Codes
4.Pydantic
5.Dependencies
6.Security
1. 🌐 What is an API?
An API (Application Programming Interface) allows different software systems to communicate with each other using requests and responses, usually over HTTP.
1.The request library in python simplifies making http requests to API with methods GET,POST,PUT,DELETE
2.Install requests package using
pip install requests
3. Need to import requests package in program to request and get response
Request.Get(), request.post() supports sending and retrieving data from server and checking response.status_code to validate request status like success,created,notfound etc.
Example:
APIs are the backbone of web applications, mobile apps, and microservices.
2.⚡ What is FastAPI?
FastAPI is a modern, high‑performance Python framework for building APIs quickly and efficiently.
Why FastAPI? - 🚀 Very fast (built on Starlette & Pydantic) - ✅ Automatic request validation - 📄 Auto‑generated API documentation (Swagger & ReDoc) - 🧠 Easy to learn and developer‑friendly
Install Fast API : pip install fastapi[standard]
Execute Command: “ fastapi dev ./main.py “ or
“uvicorn filename-wihtoutextention:app --reload
Test/Run with OpenAPI/Swagger:
FastAPI_URL/docs provides Api services, where we can test/execute our services by providing inputs and observing request response
Note: If you use PyCharm as your editor, you can use the Pydantic PyCharm Plugin.
Tiny Example
from fastapi import FastAPI
app = FastAPI()
@app.get("/ping")
def ping():
return {"message": "API is working"}
🚀 First Steps
Create an app instance and define routes using decorators.
@app.get("/")
async def hello():
return {"message": "Hello World"}
📌 Path Parameters
Capture values directly from the URL path.
@app.get("/items/{item_id}")
async def get_item(item_id: int):
return {"item_id": item_id}
🔍 Query Parameters
Parameters passed after ? in the URL.
@app.get("/search/")
async def search(q: str | None = None):
return {"q": q}
📦 Request Body
Use Pydantic models to receive JSON data.
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
async def create_item(item: Item):
return item
🧵 Query String Validation
Add constraints to query parameters.
from fastapi import Query
@app.get("/items/")
async def read_items(q: str | None = Query(None, max_length=50)):
return {"q": q}
🔢 Path Parameter Validation
Validate numeric path parameters.
from fastapi import Path
@app.get("/users/{uid}")
async def get_user(uid: int = Path(..., gt=0)):
return {"uid": uid}
🧩 Query Parameter Models
Group query parameters using a model.
from pydantic import BaseModel, Field
class Filter(BaseModel):
limit: int = Field(10, gt=0)
sort: str = "asc"
@app.get("/items/")
async def list_items(filters: Filter = Query(...)):
return filters
🧠 Multiple Body Parameters
Accept multiple request bodies.
class User(BaseModel):
name: str
@app.put("/update/{id}")
async def update(id: int, item: Item, user: User):
return {"id": id, "item": item, "user": user}
🏷️ Body Fields Validation
Control validation using Field.
from pydantic import Field
class Product(BaseModel):
price: float = Field(gt=0)
🌳 Nested Models
Define complex JSON structures.
class Image(BaseModel):
url: str
class ItemWithImage(BaseModel):
name: str
image: Image
🍪 Cookie Parameters
Read cookie values in APIs.
from fastapi import Cookie
@app.get("/cookie/")
async def get_cookie(sess: str = Cookie(...)):
return {"session": sess}
➕ Extra Data Types
FastAPI supports UUID, datetime, Decimal, etc.
from uuid import UUID
@app.get("/uuid/{id}")
async def get_uuid(id: UUID):
return {"uuid": id}
✅ Summary
FastAPI simplifies API development with strong typing, automatic validation, and excellent performance—making it ideal for modern backend development.
3.📌 FastAPI HTTP Status Codes – Quick Reference
HTTP status codes are used by FastAPI to indicate the result of an API request. They help clients understand whether a request was successful, failed, or requires further action.
FastAPI provides the status module (from fastapi import status) to make status codes more readable and less error-prone.
✅ 2xx – Success Responses
| Status Code | Name | Description |
|---|---|---|
| 200 | OK | Request succeeded and response contains data (default for GET). |
| 201 | Created | Resource successfully created (commonly used in POST). |
| 202 | Accepted | Request accepted for processing but not completed yet. |
| 204 | No Content | Request succeeded but returns no response body. |
🔁 3xx – Redirection Responses
| Status Code | Name | Description |
|---|---|---|
| 301 | Moved Permanently | Resource URL has permanently changed. |
| 302 | Found | Temporary redirection to another URL. |
| 304 | Not Modified | Resource not changed since last request (used with caching). |
❌ 4xx – Client Error Responses
| Status Code | Name | Description |
|---|---|---|
| 400 | Bad Request | Invalid request data or parameters. |
| 401 | Unauthorized | Authentication required or failed. |
| 403 | Forbidden | Access denied (no permission). |
| 404 | Not Found | Requested resource does not exist. |
| 405 | Method Not Allowed | HTTP method not supported for this endpoint. |
| 409 | Conflict | Request conflicts with current server state. |
| 422 | Unprocessable Entity | Validation error (commonly returned by FastAPI). |
| 429 | Too Many Requests | Rate limit exceeded. |
💥 5xx – Server Error Responses
| Status Code | Name | Description |
|---|---|---|
| 500 | Internal Server Error | Generic server-side error. |
| 502 | Bad Gateway | Invalid response from upstream server. |
| 503 | Service Unavailable | Server temporarily unavailable. |
| 504 | Gateway Timeout | Upstream server did not respond in time. |
🧪 Commonly Used Status Codes in FastAPI
| Use Case | Recommended Status Code |
|---|---|
| Successful GET | 200 OK |
| Successful POST | 201 Created |
| Successful DELETE | 204 No Content |
| Invalid input data | 422 Unprocessable Entity |
| Invalid credentials | 401 Unauthorized |
| No access rights | 403 Forbidden |
| Resource missing | 404 Not Found |
🛠️ Using Status Codes in FastAPI
from fastapi import FastAPI, status
app = FastAPI()
@app.post("/items", status_code=status.HTTP_201_CREATED)
def create_item(item: dict):
return item
✅ Fast API HTTP Status Code Summary
HTTP status codes make FastAPI APIs clear, predictable, and REST-compliant, helping clients handle responses correctly and improving overall API design.
🧩 Pydantic in FastAPI
Pydantic is a Python library used by FastAPI to perform data validation, parsing, and serialization using Python type hints.
It ensures that incoming data is: -
✅ Type-safe -
✅ Automatically validated -
✅ Converted to correct Python objects -
✅ Clearly documented in Swagger UI
FastAPI deeply integrates Pydantic to handle request bodies, query parameters, path parameters, and application settings
🔢 Pydantic Core Concepts (Short & Practical)
1️⃣ BaseModel
Used to define structured data and validate inputs.
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
2️⃣ Field
Adds validation rules and metadata to model fields.
from pydantic import Field
class Product(BaseModel):
price: float = Field(gt=0)
3️⃣ BaseSettings
Used for managing configuration via environment variables.
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str
4️⃣ EmailStr, HttpUrl
Built-in types for validating emails and URLs.
from pydantic import EmailStr, HttpUrl
class Contact(BaseModel):
email: EmailStr
website: HttpUrl
5️⃣ field_validator
Validates and transforms individual fields.
from pydantic import field_validator
class User(BaseModel):
name: str
@field_validator("name")
def format_name(cls, v):
return v.title()
6️⃣ model_validator
Validates the entire model after field validation.
from pydantic import model_validator
class User(BaseModel):
age: int
@model_validator(mode="after")
def check_age(self):
if self.age < 18:
raise ValueError("Must be 18+")
return self
7️⃣ ConfigDict
Controls model behavior such as extra fields and strict mode.
from pydantic import ConfigDict
class User(BaseModel):
name: str
model_config = ConfigDict(extra="forbid")
8️⃣ RootModel
Used when the model wraps a single value or list.
from pydantic import RootModel
class Scores(RootModel[list[int]]):
pass
9️⃣ TypeAdapter
Validates data without defining a full model.
from pydantic import TypeAdapter
ta = TypeAdapter(int)
ta.validate_python("10")
✅ Pydantic Summary
Pydantic is the backbone of FastAPI’s validation system, making APIs reliable, readable, and safe with minimal code.
🔗 Dependencies in FastAPI
What is Dependency Injection?
Dependency Injection (DI) is a design pattern where required components (dependencies) are provided to a function instead of being created inside it.
FastAPI’s dependency system is simple, powerful, and developer‑friendly, making it easy to integrate reusable logic across your application.
✅ When to Use Dependencies
Use dependencies when you need to:
🔁 Share common logic across endpoints
🗄️ Share database connections or sessions
🔐 Enforce authentication, authorization, or role checks
📊 Add logging, monitoring, or rate‑limiting
♻️ Reduce code duplication
📥 Importing Depends
To use dependencies, import Depends from FastAPI:
from fastapi import Depends, FastAPI
🛠️ Function-Based Dependencies
Declare dependencies just like Body, Query, or Path parameters—using Depends() in function arguments.
Example
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: str | None = None,
skip: int = 0,
limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
CommonsDep = Annotated[dict, Depends(common_parameters)]
@app.get("/items")
async def read_items(commons: CommonsDep):
return commons
@app.get("/users")
async def read_users(commons: CommonsDep):
return commons
▶️ Run Command
uvicorn sampleFastAPI:app --reload
🔌 FastAPI Compatibility
FastAPI’s dependency system works seamlessly with: - Relational databases (PostgreSQL, MySQL, etc.) - NoSQL databases (MongoDB, Redis, etc.) - External packages - External APIs - Authentication & authorization systems - API usage monitoring tools - Response data injection systems
🧱 Classes as Dependencies
FastAPI also supports class‑based dependencies, not just functions.
When a class is used with Depends, FastAPI: 1. Creates an instance of the class 2. Injects request data into the init() method 3. Passes the instance to the path operation function
This is useful for grouping related parameters or logic together.
Example
from fastapi import Depends, FastAPI
app = FastAPI()
class CommonParams:
def init(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
def read_items(params: CommonParams = Depends()):
return params.__dict__
👍 Why Use Class-Based Dependencies?
· Cleaner and better‑organized code
· Easy reuse across multiple endpoints
· Ideal for growing logic (filters, auth, validation)
· Simple to extend later
📌 When to Prefer Them
· Shared query parameters
· Pagination and filtering logic
· Authentication or authorization helpers
🌍 Global Dependencies
Sometimes you want dependencies to apply to all endpoints in the application.
Example
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException
async def verify_token(x_token: Annotated[str, Header()]):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def verify_key(x_key: Annotated[str, Header()]):
if x_key != "fake-super-secret-key":
raise HTTPException(status_code=400, detail="X-Key header invalid")
return x_key
app = FastAPI(
dependencies=[Depends(verify_token), Depends(verify_key)]
)
@app.get("/items/")
async def read_items():
return [{"item": "Portal Gun"}, {"item": "Plumbus"}]
@app.get("/users/")
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
🔄 Dependencies with yield
FastAPI supports dependencies that need cleanup logic after request processing.
Use yield instead of return, and write cleanup code after it.
⚠️ Important: Use yield only once per dependency.
Example
from typing import Annotated
from fastapi import Depends, FastAPI, HTTPException
app = FastAPI()
DATA = {
"plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
"portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
}
class OwnerError(Exception):
pass
def get_username():
try:
yield "Rick"
except OwnerError as e:
raise HTTPException(
status_code=400,
detail=f"Owner error: {e}"
)
@app.get("/items/{item_id}")
def get_item(
item_id: str,
username: Annotated[str, Depends(get_username)]
):
if item_id not in DATA:
raise HTTPException(status_code=404, detail="Item not found")
item = DATA[item_id]
if item["owner"] != username:
raise OwnerError(username)
return item
Code Dependencies:
✅ Dependencies Summary
FastAPI dependencies help you write clean, reusable, and maintainable code by separating shared logic from business logic. They scale naturally from simple helpers to complex application-wide concerns.
5.🔐 FastAPI Security
Security in APIs generally involves authentication (who you are) and authorization (what you can access). FastAPI supports modern, standard-based security mechanisms that integrate cleanly with OpenAPI and Swagger UI.
🔑 Common Security Standards
OAuth2
OAuth2 is a widely used authorization framework. - Supports complex use cases - Allows third‑party login (Google, Facebook, GitHub, etc.) - Requires HTTPS in production
OAuth1
· Older and more complex
· Defines how to encrypt communication
· Rarely used in modern applications
OpenID Connect
· Built on top of OAuth2
· Clarifies ambiguous OAuth2 areas
· Used by providers like Google Login
📄 OpenAPI & FastAPI Security
FastAPI is built on the OpenAPI specification, which automatically documents API security.
With OpenAPI, FastAPI can: - Define security schemes (OAuth2, JWT Bearer, API Keys, HTTP Basic) - Describe authentication requirements clearly - Generate interactive Swagger UI with an Authorize button
Benefits
· Self‑documented security
· Easier frontend integration
· Fewer authentication misconfigurations🛠️ FastAPI Security Utilities
FastAPI provides built‑in tools inside the fastapi.security module to simplify security implementation.
Common utilities include: - OAuth2PasswordBearer - OAuth2PasswordRequestForm - HTTP Basic authentication - API key support
🔐 OAuth2 in FastAPI – Step by Step (Concise)
FastAPI mainly demonstrates security using the OAuth2 Password Flow, which works well for first‑party applications.
1️⃣ OAuth2 Password Flow – Basics
· Client sends username & password to /token
· Server returns an access token
· Client sends token in Authorization: Bearer header
· Protected endpoints validate the token
Swagger UI automatically provides an Authorize dialog.
2️⃣ Simple OAuth2 (Password + Bearer Token)
This example demonstrates OAuth2 mechanics using a fake token: - Credentials are extracted using OAuth2PasswordRequestForm - Response contains access_token and token_type - Focuses on understanding OAuth2 flow, not real security
3️⃣ OAuth2 with JWT & Password Hashing (Real‑World)
This approach adds production‑ready security: - Passwords are securely hashed (Argon2) - Tokens are JWTs (JSON Web Tokens) - JWTs contain user identity and expiry - Tokens are cryptographically signed
JWT allows stateless authentication, meaning the server doesn’t store sessions.
📦 Required Packages
Install required libraries:
pip install pyjwt
pip install pwdlib[argon2]
🧪 OAuth2 + JWT Complete Example
from datetime import datetime, timedelta, timezone
from typing import Annotated
import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jwt.exceptions import InvalidTokenError
from pwdlib import PasswordHash
from pydantic import BaseModel
# to get a string like this run:
# openssl rand -hex 32
SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "\(argon2id\)v=19\(m=65536,t=3,p=4\)wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc",
"disabled": False,
}
}
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: str | None = None
class User(BaseModel):
username: str
email: str | None = None
full_name: str | None = None
disabled: bool | None = None
class UserInDB(User):
hashed_password: str
password_hash = PasswordHash.recommended()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
def verify_password(plain_password, hashed_password):
return password_hash.verify(plain_password, hashed_password)
def get_password_hash(password):
return password_hash.hash(password)
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.now(timezone.utc) + expires_delta
else:
expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except InvalidTokenError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(
current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
@app.post("/token")
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return Token(access_token=access_token, token_type="bearer")
@app.get("/users/me/", response_model=User)
async def read_users_me(
current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
current_user: Annotated[User, Depends(get_current_active_user)],
):
return [{"item_id": "Foo", "owner": current_user.username}]
✅ Fast API Security Summary
FastAPI security is built on open standards like OAuth2, JWT, and OpenAPI. With minimal code, you get secure authentication, automatic documentation, and production‑ready patterns.




