Route Class Documentation¶
The Route class represents an individual route definition in the PyWeber framework. It encapsulates all the configuration needed to handle HTTP requests for a specific URL pattern, including templates, methods, middleware, and response settings.
Dependencies¶
import inspect
import re
from string import punctuation
from typing import Union, Callable, Any
from pyweber.core.element import Element
from pyweber.core.template import Template
from pyweber.utils.types import ContentTypes, HTTPStatusCode
from pyweber.models.routes import RedirectRoute
from pyweber.exceptions import InvalidRouteFormatError
Route Class¶
Constructor¶
def __init__(
self,
route: str,
template: Union[RedirectRoute, Template, Element, Callable, dict, str],
group: str = None,
methods: list[str] = None,
name: str = None,
middlewares: list[Callable] = None,
status_code: int = None,
content_type: ContentTypes = None,
title: str = '',
process_response: bool = True,
callback: Callable[..., Any] = None,
**kwargs
):
Parameters:
- route: URL pattern for the route (must start with '/')
- template: Content to serve (Template, Element, Callable, dict, str, or RedirectRoute)
- group: Optional group name for organizing routes
- methods: List of allowed HTTP methods (default: ['GET'])
- name: Optional name for the route (used for URL generation)
- middlewares: List of middleware functions to apply
- status_code: HTTP status code to return (default: 200)
- content_type: Response content type (default: ContentTypes.html)
- title: Page title for HTML responses
- process_response: Whether to wrap response in full template
- callback: Function to call when route is accessed
- **kwargs: Additional route parameters
Properties¶
callback (Property with Setter)¶
Gets or sets the callback function for the route.
Getter Returns: Callable function that processes the route
Setter Parameters:
- callback: Callable function or None
Behavior: - If callback is provided, validates it's callable - If no callback provided, uses template as callback if it's callable - Otherwise creates lambda that returns the template
full_route (Read-only Property)¶
Returns the complete route path including group prefix.
Returns: Full route string with group prefix
Logic:
- If group is not default group, prepends /{group}{route}
- Otherwise returns route as-is
middlewares (Property with Setter)¶
Gets or sets the middleware functions for the route.
Getter Returns: List of middleware functions
Setter Parameters:
- middlewares: List of callable functions
Validation: - Must be a list - All items must be callable functions
Raises:
- TypeError: If middlewares is not a list
- ValueError: If any middleware is not callable
methods (Property with Setter)¶
Gets or sets the allowed HTTP methods for the route.
Getter Returns: List of uppercase HTTP method strings
Setter Parameters:
- methods: List of HTTP method strings
Validation: - Must be a list - All methods must be in allowed methods list - Automatically converts to uppercase
Raises:
- TypeError: If methods is not a list
- ValueError: If any method is not allowed
status_code (Property with Setter)¶
Gets or sets the HTTP status code for the route.
Getter Returns: HTTP status code integer
Setter Parameters:
- value: HTTP status code integer
Validation: - Defaults to 200 if None provided - Must be a valid HTTP status code
Raises:
- ValueError: If status code is not valid
content_type (Property with Setter)¶
Gets or sets the response content type.
Getter Returns: ContentTypes enum value
Setter Parameters:
- value: ContentTypes enum value
Validation: - Cannot be None or empty - Must be ContentTypes instance
Raises:
- ValueError: If content_type is empty
- TypeError: If not ContentTypes instance
group (Property with Setter)¶
Gets or sets the route group name.
Getter Returns: Group name string
Setter Parameters:
- value: Group name string
Validation: - Processes through get_group() method - Cannot contain punctuation symbols (except underscore)
Raises:
- ValueError: If group contains invalid symbols
route (Property with Setter)¶
Gets or sets the route URL pattern.
Getter Returns: Route URL string
Setter Parameters:
- value: Route URL string
Validation: - Must start with '/' - Converted to string if not already
Raises:
- InvalidRouteFormatError: If route doesn't start with '/'
Static Methods¶
paramaters_types() -> dict¶
Returns mapping of Python types to OpenAPI parameter types.
Returns: Dictionary mapping Python type names to OpenAPI types
argument_types() -> dict¶
Returns mapping of Python types to OpenAPI argument types (includes collections).
Returns: Dictionary mapping Python type names to OpenAPI types
{
'int': 'integer', 'str': 'string', 'float': 'number',
'list': 'array', 'dict': 'object', 'set': 'array', 'tuple': 'array'
}
get_group(group: str) -> str¶
Processes group name, returning default if None provided.
Parameters:
- group: Group name or None
Returns: Processed group name or default group
default_group() -> str¶
Returns the default group name.
Returns: '__pyweber'
default_method() -> list[str]¶
Returns the default HTTP methods.
Returns: ['GET']
allowed_methods() -> list[str]¶
Returns list of all allowed HTTP methods.
Returns: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']
Class Methods¶
get_callback_parameters(cls, callback: Callable[..., Any]) -> dict¶
Extracts parameter information from a callback function.
Parameters:
- callback: Function to analyze
Returns: Dictionary with parameter names as keys and parameter info as values
get_query_parameters(cls, route: str, callback: Callable) -> dict¶
Analyzes route and callback to generate OpenAPI parameter specification.
Parameters:
- route: Route URL pattern with parameters
- callback: Callback function to analyze
Returns: Dictionary with parameters and body specifications
{
'parameters': {
'param_name': {
'type': 'string',
'required': True,
'default': None
}
},
'body': {
'description': '',
'required': True,
'content': {...}
}
}
Process:
1. Extracts URL parameters using regex pattern {\s*(.*?)\s*}
2. Matches parameters with callback function signature
3. Determines parameter types and requirements
4. Generates request body schema for non-URL parameters
Magic Methods¶
__repr__() -> str¶
Returns string representation of the Route instance.
Returns: Formatted string with key route information
Usage Examples¶
Basic Route Creation¶
from pyweber.models.routes import Route
from pyweber.utils.types import ContentTypes
# Simple HTML route
route = Route(
route="/",
template="<h1>Welcome to PyWeber!</h1>",
title="Home Page"
)
# API route with JSON response
api_route = Route(
route="/api/users",
template={"users": [], "total": 0},
content_type=ContentTypes.json,
methods=["GET", "POST"]
)
print(route)
# Route(group=__pyweber, route=/, full_route=/, name=None, methods=['GET'], status_code=200)
Route with Parameters¶
# Route with URL parameters
user_route = Route(
route="/users/{user_id}",
template=lambda user_id: f"<h1>User {user_id}</h1>",
methods=["GET"]
)
# Route with multiple parameters and types
product_route = Route(
route="/products/{category}/{product_id}",
template=get_product_template,
methods=["GET"],
callback=get_product_data
)
def get_product_data(category: str, product_id: int):
return f"Product {product_id} in {category}"
Route with Middleware¶
def auth_middleware(request):
if not request.headers.get("Authorization"):
return Response(content="Unauthorized", status_code=401)
return None
def logging_middleware(request):
print(f"Accessing: {request.path}")
return None
# Protected route with middleware
protected_route = Route(
route="/admin/dashboard",
template="<h1>Admin Dashboard</h1>",
middlewares=[auth_middleware, logging_middleware],
methods=["GET"]
)
Route Groups¶
# API routes group
api_users = Route(
route="/users",
template=get_users,
group="api",
content_type=ContentTypes.json,
methods=["GET", "POST"]
)
api_posts = Route(
route="/posts",
template=get_posts,
group="api",
content_type=ContentTypes.json,
methods=["GET", "POST"]
)
print(api_users.full_route) # /api/users
print(api_posts.full_route) # /api/posts
Different Template Types¶
from pyweber.core.template import Template
from pyweber.core.element import Element
# Template object
template_route = Route(
route="/template-page",
template=Template(
template="<h1>{{title}}</h1>",
context={"title": "Template Page"}
)
)
# Element object
element_route = Route(
route="/element-page",
template=Element(
tag="div",
content="<h1>Element Page</h1>"
)
)
# Callable template
def dynamic_template(**kwargs):
return f"<h1>Dynamic content: {kwargs}</h1>"
dynamic_route = Route(
route="/dynamic/{message}",
template=dynamic_template
)
# Dictionary (JSON) template
json_route = Route(
route="/api/status",
template={"status": "ok", "timestamp": "2024-01-01"},
content_type=ContentTypes.json
)
Route with Custom Status Codes¶
# Created response
create_route = Route(
route="/api/users",
template=create_user,
methods=["POST"],
status_code=201,
content_type=ContentTypes.json
)
# Not found response
not_found_route = Route(
route="/missing",
template="<h1>This page doesn't exist</h1>",
status_code=404
)
# Redirect response
redirect_route = Route(
route="/old-page",
template="<h1>Moved</h1>",
status_code=301
)
Form Handling Routes¶
# Form display route
form_route = Route(
route="/contact",
template='''
<form method="POST" action="/contact">
<input type="text" name="name" placeholder="Name" required>
<input type="email" name="email" placeholder="Email" required>
<textarea name="message" placeholder="Message" required></textarea>
<button type="submit">Send</button>
</form>
''',
methods=["GET"]
)
# Form processing route
def process_contact(name: str, email: str, message: str):
# Process form data
return f"<h1>Thank you {name}!</h1><p>We'll contact you at {email}</p>"
form_handler = Route(
route="/contact",
template=process_contact,
methods=["POST"],
callback=process_contact
)
File Upload Routes¶
# File upload form
upload_form = Route(
route="/upload",
template='''
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">Upload</button>
</form>
''',
methods=["GET"]
)
# File processing
def handle_upload(file):
if file:
return f"<h1>File uploaded: {file.filename}</h1>"
return "<h1>No file uploaded</h1>"
upload_handler = Route(
route="/upload",
template=handle_upload,
methods=["POST"],
callback=handle_upload
)
Static File Routes¶
# CSS file route
css_route = Route(
route="/static/style.css",
template="body { background-color: #f0f0f0; }",
content_type=ContentTypes.css
)
# JavaScript file route
js_route = Route(
route="/static/app.js",
template="console.log('PyWeber app loaded');",
content_type=ContentTypes.js
)
# Image route (serving from file)
def serve_image():
with open("static/logo.png", "rb") as f:
return f.read()
image_route = Route(
route="/static/logo.png",
template=serve_image,
content_type=ContentTypes.png
)
Advanced Callback Usage¶
# Async callback
async def async_handler(user_id: int):
# Simulate async operation
await asyncio.sleep(0.1)
return f"<h1>Async User {user_id}</h1>"
async_route = Route(
route="/async/{user_id}",
template=async_handler,
callback=async_handler
)
# Callback with complex parameters
def complex_handler(
user_id: int,
category: str = "general",
limit: int = 10,
filters: dict = None
):
filters = filters or {}
return {
"user_id": user_id,
"category": category,
"limit": limit,
"filters": filters
}
complex_route = Route(
route="/api/users/{user_id}",
template=complex_handler,
callback=complex_handler,
content_type=ContentTypes.json,
methods=["GET", "POST"]
)
Error Handling in Routes¶
def safe_handler(user_id: int):
try:
# Some operation that might fail
user = get_user_from_db(user_id)
return f"<h1>User: {user.name}</h1>"
except UserNotFound:
return "<h1>User not found</h1>", 404
except Exception as e:
return f"<h1>Error: {str(e)}</h1>", 500
error_route = Route(
route="/safe/{user_id}",
template=safe_handler,
callback=safe_handler
)
Route Parameter Analysis¶
def analyze_route_params():
route = Route(
route="/api/users/{user_id}/posts/{post_id}",
template=get_user_post,
callback=get_user_post
)
# Get parameter information
params = Route.get_query_parameters(
route.route,
route.callback
)
print("URL Parameters:", params['parameters'])
print("Request Body:", params['body'])
def get_user_post(user_id: int, post_id: int, include_comments: bool = False):
return {
"user_id": user_id,
"post_id": post_id,
"include_comments": include_comments
}
Integration with PyWeber Application¶
Adding Routes to Application¶
from pyweber import Pyweber
app = Pyweber()
# Method 1: Direct route creation
route = Route(
route="/users/{user_id}",
template=get_user_template,
methods=["GET"]
)
app.add_route_object(route)
# Method 2: Using app.add_route (creates Route internally)
app.add_route(
route="/posts",
template=get_posts,
methods=["GET", "POST"],
content_type=ContentTypes.json
)
# Method 3: Using decorator (creates Route internally)
@app.route("/products/{product_id}", methods=["GET"])
def get_product(product_id: int):
return f"<h1>Product {product_id}</h1>"
Route Groups in Application¶
app = Pyweber()
# Create API routes group
api_routes = [
Route(route="/users", template=get_users, group="api"),
Route(route="/posts", template=get_posts, group="api"),
Route(route="/comments", template=get_comments, group="api")
]
app.add_group_routes(api_routes)
# Routes will be available at:
# /api/users
# /api/posts
# /api/comments
OpenAPI Integration¶
Automatic Documentation Generation¶
def documented_handler(
user_id: int,
name: str,
email: str,
age: int = 18,
active: bool = True
):
"""
Get or update user information.
This endpoint handles user data retrieval and updates.
"""
return {
"user_id": user_id,
"name": name,
"email": email,
"age": age,
"active": active
}
# Route with full OpenAPI documentation
documented_route = Route(
route="/api/users/{user_id}",
template=documented_handler,
callback=documented_handler,
methods=["GET", "POST"],
content_type=ContentTypes.json,
title="User Management"
)
# OpenAPI spec will include:
# - Path parameters (user_id)
# - Request body schema (name, email, age, active)
# - Response schema
# - Parameter types and defaults
Best Practices¶
Route Organization¶
# Group related routes
user_routes = [
Route(route="/", template=list_users, group="users"),
Route(route="/{user_id}", template=get_user, group="users"),
Route(route="/{user_id}/edit", template=edit_user, group="users")
]
# Use descriptive names
Route(
route="/api/users",
template=get_users_api,
name="users_api",
methods=["GET"]
)
Error Handling¶
def robust_handler(**kwargs):
try:
return process_request(**kwargs)
except ValidationError as e:
return {"error": str(e)}, 400
except NotFoundError:
return {"error": "Resource not found"}, 404
except Exception as e:
return {"error": "Internal server error"}, 500
Route(
route="/api/robust",
template=robust_handler,
callback=robust_handler,
content_type=ContentTypes.json
)
Security¶
# Authentication middleware
def require_auth(request):
token = request.headers.get("Authorization")
if not token or not validate_token(token):
return Response(
content={"error": "Unauthorized"},
status_code=401,
content_type=ContentTypes.json
)
return None
# Protected routes
protected_routes = [
Route(
route="/admin/users",
template=admin_users,
middlewares=[require_auth]
),
Route(
route="/api/private",
template=private_api,
middlewares=[require_auth],
content_type=ContentTypes.json
)
]
Performance¶
# Cache expensive operations
from functools import lru_cache
@lru_cache(maxsize=100)
def expensive_template(category: str):
# Expensive operation
return generate_complex_template(category)
cached_route = Route(
route="/expensive/{category}",
template=expensive_template
)
# Use appropriate content types
Route(
route="/api/data",
template=get_json_data,
content_type=ContentTypes.json # Avoid HTML processing
)
Common Patterns¶
RESTful API Routes¶
# RESTful user resource
user_routes = [
Route(route="/users", template=list_users, methods=["GET"]),
Route(route="/users", template=create_user, methods=["POST"]),
Route(route="/users/{user_id}", template=get_user, methods=["GET"]),
Route(route="/users/{user_id}", template=update_user, methods=["PUT"]),
Route(route="/users/{user_id}", template=delete_user, methods=["DELETE"])
]
Form Handling Pattern¶
# Display form
form_route = Route(
route="/contact",
template=contact_form_template,
methods=["GET"]
)
# Process form
form_handler = Route(
route="/contact",
template=process_contact_form,
methods=["POST"],
callback=process_contact_form
)
API Versioning¶
# Version 1 API
v1_routes = [
Route(route="/users", template=v1_users, group="api/v1"),
Route(route="/posts", template=v1_posts, group="api/v1")
]
# Version 2 API
v2_routes = [
Route(route="/users", template=v2_users, group="api/v2"),
Route(route="/posts", template=v2_posts, group="api/v2")
]
Troubleshooting¶
Common Issues¶
- Route not matching: Ensure route starts with '/'
- Method not allowed: Check methods list includes the HTTP method
- Middleware errors: Verify all middleware functions are callable
- Parameter extraction: Ensure callback parameters match URL parameters
- Content type issues: Set appropriate ContentTypes for response
Debugging Routes¶
# Debug route information
route = Route(route="/debug/{param}", template=debug_handler)
print(f"Full route: {route.full_route}")
print(f"Methods: {route.methods}")
print(f"Parameters: {Route.get_query_parameters(route.route, route.callback)}")
print(f"Callback: {route.callback}")
The Route class is the foundation of PyWeber's routing system, providing flexible and powerful URL handling with support for parameters, middleware, multiple content types, and automatic OpenAPI documentation generation.