Module 1 • 50 min read

Python for Backend Development

Learn Python fundamentals and build your first REST API with FastAPI.

What You'll Learn

  • Python syntax, data types, and functions
  • Object-oriented programming in Python
  • Building REST APIs with FastAPI
  • Database integration with SQLAlchemy

1. Python Basics

Python is a versatile, readable language perfect for backend development. Let's start with the fundamentals you'll use every day.

Variables and Data Types

# Variables (no type declaration needed)
name = "Alice"
age = 30
is_developer = True
salary = 75000.50

# Lists (mutable, ordered)
languages = ["Python", "JavaScript", "Go"]
languages.append("Rust")

# Dictionaries (key-value pairs)
user = {
    "name": "Alice",
    "email": "alice@example.com",
    "role": "developer"
}

# Tuples (immutable)
coordinates = (10.5, 20.3)

# Sets (unique values)
tags = {"python", "backend", "api"}

# Type hints (recommended for clarity)
def greet(name: str) -> str:
    return f"Hello, {name}!"

# List comprehensions (powerful and concise)
squares = [x**2 for x in range(10)]
even_numbers = [x for x in range(20) if x % 2 == 0]

2. Functions and Classes

Functions and OOP

# Functions with default arguments
def create_user(name: str, role: str = "user", active: bool = True):
    return {
        "name": name,
        "role": role,
        "active": active
    }

# *args and **kwargs
def log_event(event: str, *tags, **metadata):
    print(f"Event: {event}")
    print(f"Tags: {tags}")
    print(f"Metadata: {metadata}")

log_event("user_login", "auth", "success", user_id=123, ip="192.168.1.1")

# Classes
class User:
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email
        self._password = None  # Private attribute
    
    def set_password(self, password: str):
        # In real app, hash the password
        self._password = password
    
    def check_password(self, password: str) -> bool:
        return self._password == password
    
    def __str__(self):
        return f"User({self.name}, {self.email})"

# Inheritance
class Admin(User):
    def __init__(self, name: str, email: str, permissions: list):
        super().__init__(name, email)
        self.permissions = permissions
    
    def has_permission(self, permission: str) -> bool:
        return permission in self.permissions

# Usage
admin = Admin("Bob", "bob@example.com", ["read", "write", "delete"])
print(admin.has_permission("write"))  # True

3. Building a REST API with FastAPI

FastAPI is a modern, fast framework for building APIs. It includes automatic documentation, type validation, and async support out of the box.

Your First FastAPI Application

# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI(title="User API", version="1.0.0")

# Pydantic models for request/response validation
class UserCreate(BaseModel):
    name: str
    email: str
    age: Optional[int] = None

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

# In-memory database (use real DB in production)
users_db: List[User] = []
next_id = 1

@app.get("/")
def read_root():
    return {"message": "Welcome to User API"}

@app.post("/users", response_model=User, status_code=201)
def create_user(user: UserCreate):
    global next_id
    new_user = User(
        id=next_id,
        name=user.name,
        email=user.email,
        age=user.age
    )
    users_db.append(new_user)
    next_id += 1
    return new_user

@app.get("/users", response_model=List[User])
def get_users(skip: int = 0, limit: int = 10):
    return users_db[skip:skip + limit]

@app.get("/users/{user_id}", response_model=User)
def get_user(user_id: int):
    for user in users_db:
        if user.id == user_id:
            return user
    raise HTTPException(status_code=404, detail="User not found")

@app.put("/users/{user_id}", response_model=User)
def update_user(user_id: int, user_update: UserCreate):
    for i, user in enumerate(users_db):
        if user.id == user_id:
            updated_user = User(
                id=user_id,
                name=user_update.name,
                email=user_update.email,
                age=user_update.age
            )
            users_db[i] = updated_user
            return updated_user
    raise HTTPException(status_code=404, detail="User not found")

@app.delete("/users/{user_id}")
def delete_user(user_id: int):
    for i, user in enumerate(users_db):
        if user.id == user_id:
            users_db.pop(i)
            return {"message": "User deleted"}
    raise HTTPException(status_code=404, detail="User not found")

# Run with: uvicorn main:app --reload
# Docs available at: http://localhost:8000/docs

4. Database Integration

SQLAlchemy with FastAPI

# database.py
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "sqlite:///./users.db"

engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

# models.py
class UserModel(Base):
    __tablename__ = "users"
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    email = Column(String, unique=True, index=True)
    age = Column(Integer, nullable=True)

Base.metadata.create_all(bind=engine)

# main.py (updated)
from fastapi import Depends
from sqlalchemy.orm import Session

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

@app.post("/users", response_model=User)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
    db_user = UserModel(
        name=user.name,
        email=user.email,
        age=user.age
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

@app.get("/users", response_model=List[User])
def get_users(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    users = db.query(UserModel).offset(skip).limit(limit).all()
    return users

5. Authentication & Security

JWT Authentication

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key-here"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password: str) -> str:
    return pwd_context.hash(password)

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

async def get_current_user(token: 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])
        email: str = payload.get("sub")
        if email is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    
    # Get user from database
    user = get_user_by_email(email)
    if user is None:
        raise credentials_exception
    return user

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password"
        )
    access_token = create_access_token(data={"sub": user.email})
    return {"access_token": access_token, "token_type": "bearer"}

@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

Key Takeaways

  • Python is readable and powerful for backend development
  • FastAPI provides automatic validation and documentation
  • Pydantic models ensure type safety and data validation
  • SQLAlchemy is the standard ORM for database operations
  • JWT tokens are the modern standard for API authentication
  • Always hash passwords and use environment variables for secrets

Practice Exercises

Build These Projects

  1. 1. Blog API: Create a REST API for a blog with posts, comments, and tags.
  2. 2. Task Manager: Build a todo API with user authentication and task categories.
  3. 3. E-commerce Backend: Design an API for products, cart, and orders.
  4. 4. Real-time Chat: Implement WebSocket support for a chat application.

Continue Learning

Next: Advanced API Patterns

Learn about middleware, background tasks, and API optimization.

Practice on HalfGrade

Try coding challenges to reinforce your Python skills.

Advertisement