Learn how to use Expressify with practical, real-world examples that demonstrate the power and flexibility of the framework.
Expressify offers flexibility in how you define your routes and applications. Choose the style that best fits your project and preferences.
Decorator syntax offers a clean, concise way to define routes directly above handler functions.
from expressify import expressify
app = expressify()
@app.get('/')
def home(req, res):
res.send('Hello World!')
@app.get('/users/:id')
def get_user(req, res):
user_id = req.params.get('id')
res.send(f'User: {user_id}')
@app.post('/users')
def create_user(req, res):
data = req.body
res.status(201).json({'message': 'User created', 'data': data})
if __name__ == '__main__':
app.listen(port=3000, hostname='127.0.0.1', callback=lambda: print('Server running on port 3000'))
The non-decorator syntax is particularly useful for dynamic route registration, such as loading routes from a configuration file:
{
"routes": [
{
"path": "/api/products",
"method": "get",
"handler": "get_products"
},
{
"path": "/api/products/:id",
"method": "get",
"handler": "get_product_by_id"
},
{
"path": "/api/products",
"method": "post",
"handler": "create_product"
}
]
}
import json
from expressify import expressify
app = expressify()
# Handler functions
def get_products(req, res):
res.json([{"id": 1, "name": "Product 1"}, {"id": 2, "name": "Product 2"}])
def get_product_by_id(req, res):
product_id = req.params.get('id')
res.json({"id": product_id, "name": f"Product {product_id}"})
def create_product(req, res):
res.status(201).json({"message": "Product created"})
# Load routes from config file
with open('routes_config.json', 'r') as f:
config = json.load(f)
# Register routes dynamically
for route in config['routes']:
handler = globals()[route['handler']]
method = route['method'].lower()
# Use getattr to dynamically call the appropriate method
getattr(app, method)(route['path'], handler)
if __name__ == '__main__':
app.listen(port=3000, hostname='127.0.0.1', callback=lambda: print('Server running on port 3000'))
Middleware functions have access to the request and response objects and can perform actions before the final route handler.
Global middleware is applied to all routes in the application.
from expressify import Expressify
import time
import json
app = Expressify()
# Logger middleware
def logger_middleware(req, res, next):
"""Log request information and timing data"""
start_time = time.time()
print(f"Request: {req.method} {req.path}")
# Call the next middleware/route handler
result = next()
# Calculate and log timing
duration = (time.time() - start_time) * 1000 # Convert to ms
print(f"Response: {res.status_code} - {duration:.2f}ms")
return result
# JSON Parser middleware
def json_parser_middleware(req, res, next):
"""Parse JSON request bodies"""
if 'application/json' in req.get_header('content-type', ''):
try:
if req.body:
req.json = json.loads(req.body)
except json.JSONDecodeError:
return res.status(400).json({
'error': 'Invalid JSON',
'message': 'Failed to parse request body as JSON'
})
# Call the next middleware/route handler
return next()
# Error Handler middleware
def error_handler_middleware(req, res, next):
"""Handle errors in the middleware chain"""
try:
# Call the next middleware/route handler
return next()
except Exception as e:
print(f"Error: {str(e)}")
return res.status(500).json({
'error': 'Internal Server Error',
'message': str(e)
})
# Apply middleware to all routes
app.use(logger_middleware)
app.use(json_parser_middleware)
app.use(error_handler_middleware)
@app.get('/')
def home(req, res):
res.send('Hello World!')
@app.post('/api/data')
def create_data(req, res):
# The JSON parser middleware will have already parsed the JSON body
if hasattr(req, 'json'):
return res.status(201).json({
'message': 'Data received successfully',
'data': req.json
})
else:
return res.status(400).json({
'error': 'No data provided',
'message': 'Request body should contain JSON data'
})
if __name__ == '__main__':
app.listen(port=3000)
Verify user identity before allowing access to protected routes
Record request details and response times for monitoring
Catch and process errors to return appropriate responses
Add Cross-Origin Resource Sharing headers to enable cross-origin requests
Restrict request frequency to prevent abuse or API overload
Validate request data before it reaches the route handlers
Compress response data to reduce bandwidth and improve performance
Parse request bodies (JSON, form data) and make data available to handlers
Add security-related HTTP headers to strengthen application security
Learn how to define routes with path parameters and handle different HTTP methods.
from expressify import Expressify
app = Expressify()
# Simple route
@app.get('/')
def home(req, res):
return res.send('Welcome to Expressify!')
# Route with parameters
@app.get('/users/:id')
def get_user(req, res):
user_id = req.params['id']
return res.json({
'id': user_id,
'name': 'John Doe'
})
# REST API routes
@app.get('/api/products')
def get_products(req, res):
return res.json([
{'id': 1, 'name': 'Laptop'},
{'id': 2, 'name': 'Phone'}
])
@app.post('/api/products')
def create_product(req, res):
new_product = req.body
return res.status(201).json({
'id': 3,
'name': new_product['name']
})
app.listen(port=3000)
Implement authentication, logging, and request processing with middleware.
from expressify import Expressify
app = Expressify()
# Error handling middleware
def error_middleware(req, res, next):
try:
return next()
except Exception as e:
if isinstance(e, ValueError):
return res.status(400).json({
'error': 'Bad Request',
'message': str(e)
})
else:
# Log the error
print(f"Error: {str(e)}")
return res.status(500).json({
'error': 'Internal Server Error',
'message': 'Something went wrong'
})
# Apply globally
app.use(error_middleware)
@app.get('/api/users/:id')
def get_user(req, res):
user_id = req.params['id']
# Simulate database lookup
if user_id == '999':
raise ValueError('User not found')
if not user_id.isdigit():
raise ValueError('Invalid user ID')
return res.json({'id': user_id, 'name': 'John Doe'})
Serve static files and render dynamic HTML content with ease.
from expressify import Expressify
import os
app = Expressify()
# Serve static files from the 'public' directory
app.serve_static('public')
# Dynamic route that renders HTML
@app.get('/dashboard')
def dashboard(req, res):
username = req.query.get('user', 'Guest')
return res.html(f"""
Dashboard
Welcome, {username}!
This is your dashboard
""")
# Ensure the public directory exists
if not os.path.exists('public'):
os.makedirs('public')
app.listen(port=3000)
Learn how to use Jinja2 templates with Expressify.
Process form submissions and validate input data.
Connect to databases and perform CRUD operations.
Implement user authentication and session management.
Handle file uploads and process uploaded files.
Real-time communication with WebSockets.
Explore examples created by the Expressify community or share your own projects built with Expressify.
Secure your API routes with a simple authentication middleware that protects sensitive endpoints.
from expressify import Expressify
app = Expressify()
# API Key authentication middleware
def auth_middleware(req, res, next):
"""Check for API key on protected routes"""
if req.path.startswith('/protected'):
api_key = req.get_header('x-api-key')
if not api_key:
return res.status(401).json({
'error': 'Authentication required',
'message': 'Missing API key'
})
if api_key != 'valid_key':
return res.status(403).json({
'error': 'Access denied',
'message': 'Invalid API key'
})
# If authentication passes, add user info to request
req.user = {'id': 123, 'role': 'user'}
# Continue to next middleware or route handler
return next()
# Apply the middleware globally
app.use(auth_middleware)
# Protected route requiring authentication
@app.get('/protected/data')
def protected_data(req, res):
# req.user is available because of auth_middleware
return res.json({
'message': 'You have access to protected data',
'user_id': req.user['id'],
'role': req.user['role']
})
# Public route (no authentication required)
@app.get('/public/data')
def public_data(req, res):
return res.json({
'message': 'This is public data',
'timestamp': '2023-06-15T12:00:00Z'
})
if __name__ == '__main__':
app.listen(port=3000)
print("Server running on port 3000")
To test protected routes, include the API key in your request headers:
curl -H "X-API-Key: valid_key" http://localhost:3000/protected/data