python
exercises
exercises.py🐍python
"""
Python Web Development - Exercises
Practice building web applications and APIs
"""
from typing import Dict, List, Optional, Any, Callable
from dataclasses import dataclass, field
from datetime import datetime, timedelta
import json
import re
import hashlib
import secrets
# ============================================================
# EXERCISE 1: HTTP Request Parser
# ============================================================
"""
Parse raw HTTP request text into a structured object.
"""
@dataclass
class ParsedRequest:
"""Parsed HTTP request."""
method: str
path: str
version: str
headers: Dict[str, str]
body: Optional[str]
def parse_http_request(raw_request: str) -> ParsedRequest:
"""
Parse a raw HTTP request string.
Example:
>>> raw = '''GET /users HTTP/1.1
... Host: example.com
... Content-Type: application/json
...
... {"name": "Alice"}'''
>>> req = parse_http_request(raw)
>>> req.method
'GET'
>>> req.path
'/users'
>>> req.headers['Host']
'example.com'
"""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 2: URL Router with Parameters
# ============================================================
"""
Build a URL router that supports path parameters like /users/:id
"""
class Router:
"""
URL router with path parameter support.
Example:
>>> router = Router()
>>> @router.get("/users/:user_id")
... def get_user(user_id):
... return {"user_id": user_id}
>>>
>>> handler, params = router.match("GET", "/users/123")
>>> handler(**params)
{'user_id': '123'}
"""
def __init__(self):
self.routes: List[tuple] = [] # (method, pattern, handler)
def add_route(self, method: str, path: str, handler: Callable):
"""Add a route with optional path parameters."""
# YOUR CODE HERE
pass
def get(self, path: str):
"""Decorator for GET routes."""
# YOUR CODE HERE
pass
def post(self, path: str):
"""Decorator for POST routes."""
# YOUR CODE HERE
pass
def match(self, method: str, path: str) -> tuple:
"""
Match a request to a handler.
Returns (handler, params) or (None, None) if no match.
"""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 3: Request Validator
# ============================================================
"""
Create a validator for API request bodies with various rules.
"""
class Field:
"""Field definition with validation rules."""
def __init__(
self,
field_type: type = str,
required: bool = True,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
min_value: Optional[float] = None,
max_value: Optional[float] = None,
pattern: Optional[str] = None,
choices: Optional[List] = None,
default: Any = None
):
self.field_type = field_type
self.required = required
self.min_length = min_length
self.max_length = max_length
self.min_value = min_value
self.max_value = max_value
self.pattern = pattern
self.choices = choices
self.default = default
class RequestValidator:
"""
Validate request data against a schema.
Example:
>>> validator = RequestValidator({
... 'username': Field(str, min_length=3, max_length=20),
... 'email': Field(str, pattern=r'^[^@]+@[^@]+[.][^@]+$'),
... 'age': Field(int, required=False, min_value=0, max_value=150),
... 'role': Field(str, choices=['admin', 'user', 'guest'])
... })
>>>
>>> data = {'username': 'alice', 'email': 'alice@test.com', 'role': 'user'}
>>> validated = validator.validate(data)
"""
def __init__(self, schema: Dict[str, Field]):
self.schema = schema
def validate(self, data: Dict) -> Dict:
"""
Validate data against schema.
Returns validated data or raises ValidationError.
"""
# YOUR CODE HERE
pass
class ValidationError(Exception):
"""Validation error with field-level errors."""
def __init__(self, errors: Dict[str, List[str]]):
self.errors = errors
super().__init__(str(errors))
# ============================================================
# EXERCISE 4: Session Manager
# ============================================================
"""
Implement server-side session management.
"""
@dataclass
class Session:
"""Session data container."""
id: str
data: Dict[str, Any]
created_at: datetime
last_accessed: datetime
expires_at: datetime
class SessionManager:
"""
Server-side session management.
Example:
>>> manager = SessionManager(max_age=3600)
>>> session_id = manager.create()
>>> manager.set(session_id, 'user_id', 123)
>>> manager.get(session_id, 'user_id')
123
>>> manager.destroy(session_id)
"""
def __init__(self, max_age: int = 3600):
self.max_age = max_age
self.sessions: Dict[str, Session] = {}
def create(self) -> str:
"""Create a new session and return its ID."""
# YOUR CODE HERE
pass
def get(self, session_id: str, key: str, default: Any = None) -> Any:
"""Get a value from session."""
# YOUR CODE HERE
pass
def set(self, session_id: str, key: str, value: Any):
"""Set a value in session."""
# YOUR CODE HERE
pass
def destroy(self, session_id: str):
"""Destroy a session."""
# YOUR CODE HERE
pass
def cleanup_expired(self) -> int:
"""Remove expired sessions, return count removed."""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 5: Rate Limiter Middleware
# ============================================================
"""
Implement a rate limiter for API endpoints.
"""
class RateLimiter:
"""
Token bucket rate limiter.
Example:
>>> limiter = RateLimiter(max_requests=10, window_seconds=60)
>>> limiter.is_allowed("user_123") # True
>>> # ... 10 more requests ...
>>> limiter.is_allowed("user_123") # False (rate limited)
"""
def __init__(self, max_requests: int = 100, window_seconds: int = 60):
self.max_requests = max_requests
self.window_seconds = window_seconds
self.requests: Dict[str, List[datetime]] = {}
def is_allowed(self, key: str) -> bool:
"""Check if request is allowed for given key."""
# YOUR CODE HERE
pass
def get_remaining(self, key: str) -> int:
"""Get remaining requests for key."""
# YOUR CODE HERE
pass
def get_reset_time(self, key: str) -> Optional[datetime]:
"""Get when the rate limit resets for key."""
# YOUR CODE HERE
pass
def rate_limit(limiter: RateLimiter, key_func: Callable):
"""
Rate limit decorator.
Example:
>>> @rate_limit(limiter, lambda req: req.headers.get('X-API-Key'))
... def api_handler(request):
... return {"data": "..."}
"""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 6: JWT Authentication
# ============================================================
"""
Implement JWT token creation and verification.
"""
class JWTAuth:
"""
JWT authentication handler.
Example:
>>> auth = JWTAuth(secret="my-secret-key")
>>> token = auth.create_token({"user_id": 123, "role": "admin"})
>>> payload = auth.verify_token(token)
>>> payload['user_id']
123
"""
def __init__(self, secret: str, algorithm: str = "HS256"):
self.secret = secret
self.algorithm = algorithm
def create_token(
self,
payload: Dict[str, Any],
expires_in: int = 3600
) -> str:
"""Create a JWT token."""
# YOUR CODE HERE
# Hint: Use base64 encoding and HMAC for signature
pass
def verify_token(self, token: str) -> Optional[Dict[str, Any]]:
"""Verify and decode a JWT token."""
# YOUR CODE HERE
pass
def refresh_token(self, token: str, expires_in: int = 3600) -> Optional[str]:
"""Refresh an existing token with new expiration."""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 7: REST Resource Handler
# ============================================================
"""
Create a generic REST resource handler with CRUD operations.
"""
class RESTResource:
"""
Generic REST resource with CRUD operations.
Example:
>>> users = RESTResource("users")
>>> user = users.create({"name": "Alice", "email": "alice@test.com"})
>>> users.read(user['id'])
{'id': 1, 'name': 'Alice', 'email': 'alice@test.com', ...}
>>> users.update(1, {"name": "Alice Smith"})
>>> users.delete(1)
"""
def __init__(self, name: str, validator: Optional[RequestValidator] = None):
self.name = name
self.validator = validator
self.items: Dict[int, Dict] = {}
self.counter = 0
def list(
self,
page: int = 1,
per_page: int = 10,
filters: Optional[Dict] = None,
sort_by: Optional[str] = None,
sort_order: str = "asc"
) -> Dict:
"""
List resources with pagination, filtering, and sorting.
"""
# YOUR CODE HERE
pass
def create(self, data: Dict) -> Dict:
"""Create a new resource."""
# YOUR CODE HERE
pass
def read(self, resource_id: int) -> Optional[Dict]:
"""Read a single resource."""
# YOUR CODE HERE
pass
def update(self, resource_id: int, data: Dict, partial: bool = False) -> Optional[Dict]:
"""Update a resource (full or partial)."""
# YOUR CODE HERE
pass
def delete(self, resource_id: int) -> bool:
"""Delete a resource."""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 8: Middleware Chain
# ============================================================
"""
Implement a middleware chain for request processing.
"""
@dataclass
class Request:
"""HTTP request object."""
method: str = "GET"
path: str = "/"
headers: Dict[str, str] = field(default_factory=dict)
body: Optional[Dict] = None
context: Dict[str, Any] = field(default_factory=dict)
@dataclass
class Response:
"""HTTP response object."""
status_code: int = 200
headers: Dict[str, str] = field(default_factory=dict)
body: Any = None
class MiddlewareStack:
"""
Middleware stack for request/response processing.
Example:
>>> stack = MiddlewareStack()
>>> stack.use(logging_middleware)
>>> stack.use(auth_middleware)
>>> stack.use(timing_middleware)
>>>
>>> response = stack.handle(request, final_handler)
"""
def __init__(self):
self.middlewares: List[Callable] = []
def use(self, middleware: Callable):
"""Add middleware to stack."""
# YOUR CODE HERE
pass
def handle(self, request: Request, handler: Callable) -> Response:
"""Process request through middleware stack."""
# YOUR CODE HERE
pass
# Example middleware to implement
def create_logging_middleware():
"""Create logging middleware."""
# YOUR CODE HERE
pass
def create_auth_middleware(token_validator: Callable):
"""Create authentication middleware."""
# YOUR CODE HERE
pass
def create_cors_middleware(allowed_origins: List[str]):
"""Create CORS middleware."""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 9: WebSocket Handler (Simulated)
# ============================================================
"""
Simulate WebSocket connection handling.
"""
class WebSocketConnection:
"""Simulated WebSocket connection."""
def __init__(self, id: str):
self.id = id
self.messages: List[str] = []
self.is_open = True
def send(self, message: str):
"""Send message to client."""
if self.is_open:
self.messages.append(f"SENT: {message}")
def receive(self) -> Optional[str]:
"""Receive message from client (simulated)."""
return None
def close(self):
"""Close connection."""
self.is_open = False
class WebSocketHub:
"""
WebSocket connection hub for managing multiple connections.
Example:
>>> hub = WebSocketHub()
>>> conn1 = hub.connect("user_1")
>>> conn2 = hub.connect("user_2")
>>> hub.broadcast("Hello everyone!")
>>> hub.send_to("user_1", "Private message")
>>> hub.join_room("user_1", "chat_room_1")
>>> hub.broadcast_to_room("chat_room_1", "Room message")
"""
def __init__(self):
self.connections: Dict[str, WebSocketConnection] = {}
self.rooms: Dict[str, set] = {}
def connect(self, user_id: str) -> WebSocketConnection:
"""Create new connection for user."""
# YOUR CODE HERE
pass
def disconnect(self, user_id: str):
"""Disconnect user."""
# YOUR CODE HERE
pass
def send_to(self, user_id: str, message: str):
"""Send message to specific user."""
# YOUR CODE HERE
pass
def broadcast(self, message: str, exclude: Optional[List[str]] = None):
"""Broadcast message to all connected users."""
# YOUR CODE HERE
pass
def join_room(self, user_id: str, room: str):
"""Add user to a room."""
# YOUR CODE HERE
pass
def leave_room(self, user_id: str, room: str):
"""Remove user from a room."""
# YOUR CODE HERE
pass
def broadcast_to_room(self, room: str, message: str, exclude: Optional[List[str]] = None):
"""Broadcast message to all users in a room."""
# YOUR CODE HERE
pass
# ============================================================
# EXERCISE 10: API Application
# ============================================================
"""
Build a complete mini API application combining all concepts.
"""
class MiniAPI:
"""
Mini API framework combining router, middleware, and resources.
Example:
>>> api = MiniAPI()
>>> api.use(logging_middleware)
>>>
>>> users = api.resource("/users", validator=user_validator)
>>>
>>> @api.get("/health")
... def health_check():
... return {"status": "ok"}
>>>
>>> response = api.handle(Request(method="GET", path="/users"))
"""
def __init__(self):
self.router = Router()
self.middlewares: List[Callable] = []
self.resources: Dict[str, RESTResource] = {}
def use(self, middleware: Callable):
"""Add middleware."""
# YOUR CODE HERE
pass
def get(self, path: str):
"""Register GET route."""
# YOUR CODE HERE
pass
def post(self, path: str):
"""Register POST route."""
# YOUR CODE HERE
pass
def resource(self, path: str, validator: Optional[RequestValidator] = None) -> RESTResource:
"""Register a REST resource."""
# YOUR CODE HERE
pass
def handle(self, request: Request) -> Response:
"""Handle incoming request."""
# YOUR CODE HERE
pass
# ============================================================
# SOLUTIONS (Uncomment to check your work)
# ============================================================
"""
# Solution 4: Session Manager
class SessionManager:
def __init__(self, max_age: int = 3600):
self.max_age = max_age
self.sessions: Dict[str, Session] = {}
def create(self) -> str:
session_id = secrets.token_urlsafe(32)
now = datetime.now()
self.sessions[session_id] = Session(
id=session_id,
data={},
created_at=now,
last_accessed=now,
expires_at=now + timedelta(seconds=self.max_age)
)
return session_id
def get(self, session_id: str, key: str, default: Any = None) -> Any:
session = self.sessions.get(session_id)
if not session or datetime.now() > session.expires_at:
return default
session.last_accessed = datetime.now()
return session.data.get(key, default)
def set(self, session_id: str, key: str, value: Any):
session = self.sessions.get(session_id)
if session and datetime.now() <= session.expires_at:
session.data[key] = value
session.last_accessed = datetime.now()
def destroy(self, session_id: str):
self.sessions.pop(session_id, None)
def cleanup_expired(self) -> int:
now = datetime.now()
expired = [sid for sid, s in self.sessions.items() if now > s.expires_at]
for sid in expired:
del self.sessions[sid]
return len(expired)
# Solution 5: Rate Limiter
class RateLimiter:
def __init__(self, max_requests: int = 100, window_seconds: int = 60):
self.max_requests = max_requests
self.window_seconds = window_seconds
self.requests: Dict[str, List[datetime]] = {}
def is_allowed(self, key: str) -> bool:
now = datetime.now()
window_start = now - timedelta(seconds=self.window_seconds)
if key not in self.requests:
self.requests[key] = []
# Clean old requests
self.requests[key] = [t for t in self.requests[key] if t > window_start]
if len(self.requests[key]) < self.max_requests:
self.requests[key].append(now)
return True
return False
def get_remaining(self, key: str) -> int:
now = datetime.now()
window_start = now - timedelta(seconds=self.window_seconds)
if key not in self.requests:
return self.max_requests
valid = [t for t in self.requests[key] if t > window_start]
return max(0, self.max_requests - len(valid))
# Solution 7: REST Resource
class RESTResource:
def __init__(self, name: str, validator: Optional[RequestValidator] = None):
self.name = name
self.validator = validator
self.items: Dict[int, Dict] = {}
self.counter = 0
def list(self, page: int = 1, per_page: int = 10, filters: Optional[Dict] = None,
sort_by: Optional[str] = None, sort_order: str = "asc") -> Dict:
items = list(self.items.values())
# Filter
if filters:
for key, value in filters.items():
items = [i for i in items if i.get(key) == value]
# Sort
if sort_by:
items.sort(key=lambda x: x.get(sort_by, ''), reverse=(sort_order == "desc"))
# Paginate
total = len(items)
start = (page - 1) * per_page
items = items[start:start + per_page]
return {"items": items, "total": total, "page": page, "per_page": per_page}
def create(self, data: Dict) -> Dict:
if self.validator:
data = self.validator.validate(data)
self.counter += 1
now = datetime.now().isoformat()
item = {"id": self.counter, **data, "created_at": now, "updated_at": now}
self.items[self.counter] = item
return item
def read(self, resource_id: int) -> Optional[Dict]:
return self.items.get(resource_id)
def update(self, resource_id: int, data: Dict, partial: bool = False) -> Optional[Dict]:
if resource_id not in self.items:
return None
if partial:
self.items[resource_id].update(data)
else:
self.items[resource_id] = {"id": resource_id, **data}
self.items[resource_id]["updated_at"] = datetime.now().isoformat()
return self.items[resource_id]
def delete(self, resource_id: int) -> bool:
if resource_id in self.items:
del self.items[resource_id]
return True
return False
"""
if __name__ == "__main__":
print("Web Development Exercises")
print("=" * 50)
print("\nComplete the exercises above to practice:")
print("- HTTP request/response handling")
print("- URL routing with parameters")
print("- Request validation")
print("- Session management")
print("- Rate limiting")
print("- JWT authentication")
print("- REST API design")
print("- Middleware patterns")
print("- WebSocket handling")
print("- Building complete APIs")
print("\nUncomment the solutions to check your work!")