python

examples

examples.py🐍
"""
Python Web Development - Examples
Demonstrates Flask and FastAPI web framework concepts
"""

from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
from dataclasses import dataclass, field
import json
import hashlib
import secrets


# ============================================================
# BASIC HTTP CONCEPTS
# ============================================================

print("=" * 60)
print("WEB DEVELOPMENT CONCEPTS")
print("=" * 60)


# --- HTTP Status Codes ---
print("\n--- HTTP Status Codes ---")

HTTP_STATUS = {
    # Success
    200: "OK - Request succeeded",
    201: "Created - Resource created",
    204: "No Content - Success, no response body",
    
    # Redirection
    301: "Moved Permanently",
    302: "Found - Temporary redirect",
    304: "Not Modified - Use cached version",
    
    # Client Errors
    400: "Bad Request - Invalid syntax",
    401: "Unauthorized - Authentication required",
    403: "Forbidden - No permission",
    404: "Not Found - Resource doesn't exist",
    405: "Method Not Allowed",
    422: "Unprocessable Entity - Validation error",
    
    # Server Errors
    500: "Internal Server Error",
    502: "Bad Gateway",
    503: "Service Unavailable",
}

print("Common HTTP Status Codes:")
for code, description in list(HTTP_STATUS.items())[:6]:
    print(f"  {code}: {description}")


# --- HTTP Methods ---
print("\n--- HTTP Methods ---")

HTTP_METHODS = {
    "GET": "Retrieve resource (safe, idempotent)",
    "POST": "Create resource (not idempotent)",
    "PUT": "Update/replace resource (idempotent)",
    "PATCH": "Partial update (not always idempotent)",
    "DELETE": "Remove resource (idempotent)",
    "HEAD": "Get headers only (safe)",
    "OPTIONS": "Get allowed methods (safe)",
}

for method, description in HTTP_METHODS.items():
    print(f"  {method}: {description}")


# ============================================================
# SIMULATED WEB FRAMEWORK
# ============================================================

print("\n" + "=" * 60)
print("SIMULATED WEB FRAMEWORK")
print("=" * 60)


# --- Request/Response Objects ---
print("\n--- Request and Response Objects ---")

@dataclass
class Request:
    """Simulated HTTP Request."""
    method: str = "GET"
    path: str = "/"
    headers: Dict[str, str] = field(default_factory=dict)
    query_params: Dict[str, str] = field(default_factory=dict)
    body: Optional[str] = None
    json_data: Optional[Dict] = None
    
    def get_json(self) -> Optional[Dict]:
        """Parse JSON body."""
        if self.json_data:
            return self.json_data
        if self.body:
            return json.loads(self.body)
        return None


@dataclass
class Response:
    """Simulated HTTP Response."""
    status_code: int = 200
    headers: Dict[str, str] = field(default_factory=dict)
    body: Any = None
    
    def json(self, data: Any) -> 'Response':
        """Set JSON response."""
        self.headers['Content-Type'] = 'application/json'
        self.body = json.dumps(data, default=str)
        return self
    
    def text(self, content: str) -> 'Response':
        """Set text response."""
        self.headers['Content-Type'] = 'text/plain'
        self.body = content
        return self
    
    def html(self, content: str) -> 'Response':
        """Set HTML response."""
        self.headers['Content-Type'] = 'text/html'
        self.body = content
        return self


# Demo
request = Request(
    method="POST",
    path="/api/users",
    headers={"Authorization": "Bearer token123"},
    json_data={"name": "Alice", "email": "alice@example.com"}
)

print(f"Request: {request.method} {request.path}")
print(f"Headers: {request.headers}")
print(f"Body: {request.get_json()}")


# --- Simple Router ---
print("\n--- Simple Router ---")

class Router:
    """Simple URL router."""
    
    def __init__(self):
        self.routes = {}
    
    def route(self, path: str, methods: List[str] = None):
        """Decorator to register routes."""
        methods = methods or ["GET"]
        
        def decorator(func):
            for method in methods:
                key = f"{method}:{path}"
                self.routes[key] = func
            return func
        return decorator
    
    def dispatch(self, request: Request) -> Response:
        """Dispatch request to handler."""
        key = f"{request.method}:{request.path}"
        
        if key in self.routes:
            handler = self.routes[key]
            result = handler(request)
            
            if isinstance(result, Response):
                return result
            elif isinstance(result, dict):
                return Response().json(result)
            else:
                return Response().text(str(result))
        
        return Response(status_code=404).json({"error": "Not Found"})
    
    def list_routes(self):
        """List all registered routes."""
        return list(self.routes.keys())


# Create app
app = Router()

@app.route("/")
def home(request: Request):
    return {"message": "Welcome to the API"}

@app.route("/users", methods=["GET"])
def list_users(request: Request):
    return {"users": ["Alice", "Bob", "Charlie"]}

@app.route("/users", methods=["POST"])
def create_user(request: Request):
    data = request.get_json()
    return Response(status_code=201).json({"created": data})

print("Registered routes:")
for route in app.list_routes():
    print(f"  {route}")

# Test dispatching
print("\nDispatching requests:")
response = app.dispatch(Request(method="GET", path="/"))
print(f"GET / -> {response.status_code}: {response.body}")

response = app.dispatch(Request(method="GET", path="/users"))
print(f"GET /users -> {response.status_code}: {response.body}")


# ============================================================
# DATA VALIDATION
# ============================================================

print("\n" + "=" * 60)
print("DATA VALIDATION")
print("=" * 60)


# --- Simple Validator ---
print("\n--- Validation Schema ---")

class ValidationError(Exception):
    """Validation error with details."""
    def __init__(self, errors: Dict[str, List[str]]):
        self.errors = errors
        super().__init__(str(errors))


class Schema:
    """Simple validation schema."""
    
    def __init__(self, **fields):
        self.fields = fields
    
    def validate(self, data: Dict) -> Dict:
        """Validate data against schema."""
        errors = {}
        validated = {}
        
        for field_name, rules in self.fields.items():
            value = data.get(field_name)
            field_errors = []
            
            # Check required
            if rules.get('required', False) and value is None:
                field_errors.append(f"{field_name} is required")
                continue
            
            if value is not None:
                # Check type
                expected_type = rules.get('type')
                if expected_type and not isinstance(value, expected_type):
                    field_errors.append(f"{field_name} must be {expected_type.__name__}")
                    continue
                
                # String validations
                if isinstance(value, str):
                    if 'min_length' in rules and len(value) < rules['min_length']:
                        field_errors.append(f"{field_name} must be at least {rules['min_length']} characters")
                    if 'max_length' in rules and len(value) > rules['max_length']:
                        field_errors.append(f"{field_name} must be at most {rules['max_length']} characters")
                    if 'pattern' in rules:
                        import re
                        if not re.match(rules['pattern'], value):
                            field_errors.append(f"{field_name} has invalid format")
                
                # Number validations
                if isinstance(value, (int, float)):
                    if 'min' in rules and value < rules['min']:
                        field_errors.append(f"{field_name} must be at least {rules['min']}")
                    if 'max' in rules and value > rules['max']:
                        field_errors.append(f"{field_name} must be at most {rules['max']}")
                
                validated[field_name] = value
            
            if field_errors:
                errors[field_name] = field_errors
        
        if errors:
            raise ValidationError(errors)
        
        return validated


# Define schema
user_schema = Schema(
    username={'type': str, 'required': True, 'min_length': 3, 'max_length': 20},
    email={'type': str, 'required': True, 'pattern': r'^[^@]+@[^@]+\.[^@]+$'},
    age={'type': int, 'required': False, 'min': 0, 'max': 150},
)

# Test validation
test_cases = [
    {"username": "alice", "email": "alice@example.com", "age": 25},
    {"username": "ab", "email": "invalid"},
    {"email": "test@test.com"},  # Missing username
]

print("Validation tests:")
for data in test_cases:
    try:
        validated = user_schema.validate(data)
        print(f"  ✓ {data} -> Valid")
    except ValidationError as e:
        print(f"  ✗ {data} -> Errors: {e.errors}")


# ============================================================
# AUTHENTICATION PATTERNS
# ============================================================

print("\n" + "=" * 60)
print("AUTHENTICATION PATTERNS")
print("=" * 60)


# --- Password Hashing ---
print("\n--- Password Hashing ---")

class PasswordHasher:
    """Simple password hasher (use passlib/bcrypt in production!)."""
    
    @staticmethod
    def hash(password: str, salt: Optional[str] = None) -> str:
        """Hash a password."""
        if salt is None:
            salt = secrets.token_hex(16)
        combined = f"{salt}:{password}"
        hashed = hashlib.sha256(combined.encode()).hexdigest()
        return f"{salt}:{hashed}"
    
    @staticmethod
    def verify(password: str, hashed: str) -> bool:
        """Verify a password against hash."""
        salt, _ = hashed.split(":", 1)
        return PasswordHasher.hash(password, salt) == hashed


# Demo
password = "mysecretpassword"
hashed = PasswordHasher.hash(password)
print(f"Password: {password}")
print(f"Hashed: {hashed}")
print(f"Verify (correct): {PasswordHasher.verify(password, hashed)}")
print(f"Verify (wrong): {PasswordHasher.verify('wrongpassword', hashed)}")


# --- Token Authentication ---
print("\n--- Token Authentication ---")

class TokenAuth:
    """Simple token authentication."""
    
    def __init__(self, secret_key: str):
        self.secret_key = secret_key
        self.tokens = {}  # token -> user_id
    
    def create_token(self, user_id: str, expires_in: int = 3600) -> str:
        """Create authentication token."""
        token = secrets.token_urlsafe(32)
        expires = datetime.now() + timedelta(seconds=expires_in)
        self.tokens[token] = {
            'user_id': user_id,
            'expires': expires
        }
        return token
    
    def verify_token(self, token: str) -> Optional[str]:
        """Verify token and return user_id."""
        if token not in self.tokens:
            return None
        
        data = self.tokens[token]
        if datetime.now() > data['expires']:
            del self.tokens[token]
            return None
        
        return data['user_id']
    
    def revoke_token(self, token: str):
        """Revoke a token."""
        self.tokens.pop(token, None)


# Demo
auth = TokenAuth(secret_key="my-secret-key")
token = auth.create_token("user_123")
print(f"Token: {token}")
print(f"Verify: {auth.verify_token(token)}")
print(f"Invalid token: {auth.verify_token('fake-token')}")


# --- Simple JWT-like Token ---
print("\n--- JWT-like Token ---")

import base64
import hmac

class SimpleJWT:
    """Simplified JWT implementation (use python-jose in production!)."""
    
    def __init__(self, secret: str):
        self.secret = secret.encode()
    
    def encode(self, payload: Dict) -> str:
        """Create a token."""
        # Add expiration
        if 'exp' not in payload:
            payload['exp'] = (datetime.now() + timedelta(hours=1)).timestamp()
        
        # Encode payload
        payload_bytes = json.dumps(payload).encode()
        payload_b64 = base64.urlsafe_b64encode(payload_bytes).decode()
        
        # Create signature
        signature = hmac.new(
            self.secret,
            payload_b64.encode(),
            hashlib.sha256
        ).hexdigest()
        
        return f"{payload_b64}.{signature}"
    
    def decode(self, token: str) -> Optional[Dict]:
        """Decode and verify token."""
        try:
            payload_b64, signature = token.split(".")
            
            # Verify signature
            expected_sig = hmac.new(
                self.secret,
                payload_b64.encode(),
                hashlib.sha256
            ).hexdigest()
            
            if not hmac.compare_digest(signature, expected_sig):
                return None
            
            # Decode payload
            payload_bytes = base64.urlsafe_b64decode(payload_b64)
            payload = json.loads(payload_bytes)
            
            # Check expiration
            if datetime.now().timestamp() > payload.get('exp', 0):
                return None
            
            return payload
            
        except Exception:
            return None


# Demo
jwt = SimpleJWT(secret="my-secret-key")
token = jwt.encode({"user_id": "123", "role": "admin"})
print(f"Token: {token}")
print(f"Decoded: {jwt.decode(token)}")


# ============================================================
# REST API PATTERNS
# ============================================================

print("\n" + "=" * 60)
print("REST API PATTERNS")
print("=" * 60)


# --- CRUD API Simulation ---
print("\n--- CRUD API Simulation ---")

class CRUDResource:
    """Generic CRUD resource handler."""
    
    def __init__(self, name: str):
        self.name = name
        self.items = {}
        self.counter = 0
    
    def list_all(self, page: int = 1, per_page: int = 10) -> Dict:
        """List with pagination."""
        items = list(self.items.values())
        start = (page - 1) * per_page
        end = start + per_page
        
        return {
            "items": items[start:end],
            "total": len(items),
            "page": page,
            "per_page": per_page,
            "pages": (len(items) + per_page - 1) // per_page
        }
    
    def create(self, data: Dict) -> Dict:
        """Create new item."""
        self.counter += 1
        item = {
            "id": self.counter,
            **data,
            "created_at": datetime.now().isoformat(),
            "updated_at": datetime.now().isoformat()
        }
        self.items[self.counter] = item
        return item
    
    def read(self, item_id: int) -> Optional[Dict]:
        """Read single item."""
        return self.items.get(item_id)
    
    def update(self, item_id: int, data: Dict) -> Optional[Dict]:
        """Update item."""
        if item_id not in self.items:
            return None
        
        self.items[item_id].update(data)
        self.items[item_id]["updated_at"] = datetime.now().isoformat()
        return self.items[item_id]
    
    def delete(self, item_id: int) -> bool:
        """Delete item."""
        if item_id in self.items:
            del self.items[item_id]
            return True
        return False


# Demo
products = CRUDResource("products")

# Create
p1 = products.create({"name": "Laptop", "price": 999.99})
p2 = products.create({"name": "Mouse", "price": 29.99})
p3 = products.create({"name": "Keyboard", "price": 79.99})

print("Created products:")
for item in products.list_all()["items"]:
    print(f"  {item['id']}: {item['name']} - ${item['price']}")

# Read
print(f"\nProduct 1: {products.read(1)['name']}")

# Update
products.update(1, {"price": 899.99})
print(f"Updated price: ${products.read(1)['price']}")

# Delete
products.delete(2)
print(f"After delete: {len(products.list_all()['items'])} products")


# ============================================================
# MIDDLEWARE PATTERN
# ============================================================

print("\n" + "=" * 60)
print("MIDDLEWARE PATTERN")
print("=" * 60)

class MiddlewareChain:
    """Simple middleware chain."""
    
    def __init__(self):
        self.middlewares = []
    
    def add(self, middleware):
        """Add middleware to chain."""
        self.middlewares.append(middleware)
    
    def process(self, request: Request, handler) -> Response:
        """Process request through middleware chain."""
        
        def create_next(index):
            if index >= len(self.middlewares):
                # End of chain, call actual handler
                return lambda req: handler(req)
            
            def next_handler(req):
                middleware = self.middlewares[index]
                return middleware(req, create_next(index + 1))
            
            return next_handler
        
        return create_next(0)(request)


# Example middleware functions
def logging_middleware(request: Request, next_handler):
    """Log requests."""
    print(f"  [LOG] {request.method} {request.path}")
    response = next_handler(request)
    print(f"  [LOG] Response: {response.status_code}")
    return response

def timing_middleware(request: Request, next_handler):
    """Add timing header."""
    import time
    start = time.time()
    response = next_handler(request)
    duration = time.time() - start
    response.headers['X-Response-Time'] = f"{duration*1000:.2f}ms"
    return response

def auth_middleware(request: Request, next_handler):
    """Check authentication."""
    if 'Authorization' not in request.headers:
        return Response(status_code=401).json({"error": "Unauthorized"})
    return next_handler(request)


# Setup chain
chain = MiddlewareChain()
chain.add(logging_middleware)
chain.add(timing_middleware)

def final_handler(request):
    return Response().json({"message": "Hello!"})

# Process request
print("Processing request through middleware:")
request = Request(method="GET", path="/api/data")
response = chain.process(request, final_handler)
print(f"Final response: {response.body}")
print(f"Headers: {response.headers}")


# ============================================================
# ERROR HANDLING
# ============================================================

print("\n" + "=" * 60)
print("ERROR HANDLING")
print("=" * 60)

class HTTPException(Exception):
    """HTTP exception with status code."""
    
    def __init__(self, status_code: int, detail: str):
        self.status_code = status_code
        self.detail = detail


def error_handler(func):
    """Decorator to handle exceptions."""
    def wrapper(request):
        try:
            return func(request)
        except HTTPException as e:
            return Response(status_code=e.status_code).json({
                "error": e.detail
            })
        except ValidationError as e:
            return Response(status_code=422).json({
                "error": "Validation Error",
                "details": e.errors
            })
        except Exception as e:
            return Response(status_code=500).json({
                "error": "Internal Server Error",
                "message": str(e)
            })
    return wrapper


@error_handler
def protected_handler(request):
    """Handler that might raise exceptions."""
    if not request.headers.get("Authorization"):
        raise HTTPException(401, "Authentication required")
    
    data = request.get_json()
    if not data:
        raise HTTPException(400, "Request body required")
    
    return Response().json({"status": "ok"})


# Test error handling
print("Testing error handling:")

test_requests = [
    Request(method="POST", path="/protected"),  # No auth
    Request(method="POST", path="/protected", headers={"Authorization": "Bearer x"}),  # No body
    Request(method="POST", path="/protected", headers={"Authorization": "Bearer x"}, json_data={"test": 1}),  # OK
]

for req in test_requests:
    response = protected_handler(req)
    print(f"  {req.path}: {response.status_code} - {response.body}")


print("\n" + "=" * 60)
print("All web development examples completed!")
print("=" * 60)
print("\nFor real web development, install:")
print("  pip install flask        # Flask framework")
print("  pip install fastapi      # FastAPI framework")
print("  pip install uvicorn      # ASGI server")
print("  pip install sqlalchemy   # Database ORM")
Examples - Python Tutorial | DeepML