API Reference

Complete documentation for Expressify's API. Easily build web applications with our intuitive and powerful interface.

This documentation covers all the methods, properties, and features available in Expressify.

Application Methods

expressify()

Creates an Expressify application.

Example:
from expressify import expressify

app = expressify()

app.listen(port, hostname, callback=None)

Starts a server and listens for connections on the specified host and port.

Parameters:
  • port

    Required port number

  • hostname

    Required hostname (e.g., '127.0.0.1')

  • callback

    Optional function called when server starts

Example:
app.listen(port=5000, hostname='0.0.0.0', callback=lambda: print('Server running on port 5000'))

app.use(path_or_middleware, middleware=None)

Mounts middleware at the specified path or globally.

Parameters:
  • path_or_middleware

    Path string or middleware function

  • middleware

    Middleware function if path is provided

Example:
# Global middleware
app.use(logger_middleware)

# Path-specific middleware
app.use('/admin', auth_middleware)

app.set(name, value)

Assigns a setting to the application.

Parameters:
  • name

    Setting name

  • value

    Setting value

Example:
app.set('view engine', 'jinja2')
app.set('views', './views')

Application Properties

app.locals

Object for app-level data that persists throughout the lifetime of the application.

Example:
app.locals.title = 'My Application'
app.locals.version = '1.0.0'

Application Settings

Common Settings

Setting Type Description
view engine String The template engine to use ('jinja2')
views String Directory path for template files
trust proxy Boolean When true, trust the X-Forwarded-* headers
json spaces Number Spaces for JSON responses indentation

Routing

HTTP Methods

Expressify provides methods for handling different types of HTTP requests. Each method represents a standard HTTP verb and allows you to define how your application responds to client requests.

GET

app.get()

Handles GET requests to retrieve data from the server. Used when clients want to read or fetch resources.

POST

app.post()

Handles POST requests to create new resources on the server. Used when clients want to submit data.

PUT

app.put()

Handles PUT requests to completely replace existing resources. Used for updating entire resources.

DELETE

app.delete()

Handles DELETE requests to remove resources from the server. Used when clients want to delete data.

PATCH

app.patch()

Handles PATCH requests for partial updates to resources. Used when clients want to modify only specific parts of data.

ALL

app.all()

Handles all HTTP methods at a specific path. Useful for setting up middleware that should run for all request types.

Method Parameters:

  • path (string, required)

    The URL pattern that the route should match. Can include route parameters like :id to capture values from the URL.

  • handler (function, required)

    The function that processes the request. Must accept req and res parameters.

  • middleware (list, optional)

    List of middleware functions to run before the handler. Each middleware must accept req, res, and next parameters.

Decorator Syntax
Express-like Syntax

Decorator syntax is more Pythonic and similar to other Python web frameworks like Flask.

from expressify import expressify

app = expressify()

# Basic GET route
@app.get('/users')
def get_users(req, res):
    res.json([{'name': 'John'}, {'name': 'Jane'}])

# POST route with JSON response
@app.post('/users')
def create_user(req, res):
    user_data = req.body
    # Process user data...
    res.status(201).json({'message': 'User created', 'user': user_data})

# Route with path parameter
@app.get('/users/:id')
def get_user(req, res):
    user_id = req.params.get('id')
    # Fetch user from database...
    res.json({'id': user_id, 'name': 'Example User'})

# Route with middleware
@app.get('/admin/dashboard', middleware=[auth_middleware])
def admin_dashboard(req, res):
    res.send('Admin Dashboard')

Route Parameters

Route parameters let you capture values from specific parts of the URL path. They act as placeholders in your route definitions, making your routes more flexible and powerful.

How Parameters Work:

  • Parameters are defined with a colon : prefix in the route path
  • The parameter name becomes the key you use to access the value in your code
  • Access parameters through req.params.get('parameter_name')
  • Parameter values are always strings, so convert them if needed

Examples:

Single Parameter (Decorator Style)
@app.get('/users/:id')
def get_user(req, res):
    user_id = req.params.get('id')
    res.send(f'User ID: {user_id}')

Visiting /users/42 would display "User ID: 42".

Single Parameter (Express Style)
def get_user(req, res):
    user_id = req.params.get('id')
    res.send(f'User ID: {user_id}')
    
app.get('/users/:id', get_user)

Express-style approach for the same route.

Multiple Parameters (Decorator Style)
@app.get('/users/:user_id/posts/:post_id')
def get_user_post(req, res):
    user_id = req.params.get('user_id')
    post_id = req.params.get('post_id')
    res.send(f'User {user_id}, Post {post_id}')

Visiting /users/42/posts/123 would display "User 42, Post 123".

Multiple Parameters (Express Style)
def get_user_post(req, res):
    user_id = req.params.get('user_id')
    post_id = req.params.get('post_id')
    res.send(f'User {user_id}, Post {post_id}')
    
app.get('/users/:user_id/posts/:post_id', get_user_post)

Express-style approach for multiple parameters.

Route Handlers

Route handlers are functions that run when a matching request is received. They define what happens when someone visits a specific URL in your application.

Handler Structure:

Every route handler must accept two parameters:

  • req (Request object)

    Contains information about the HTTP request, including query parameters, route parameters, headers, and body.

  • res (Response object)

    Provides methods to send a response to the client, such as send(), json(), and status().

Common Response Types:

Sending HTML or Text (Decorator Style)
@app.get('/hello')
def hello(req, res):
    res.send('

Hello, World!

')
Sending HTML or Text (Express Style)
def hello(req, res):
    res.send('

Hello, World!

') app.get('/hello', hello)
Sending JSON Data (Decorator Style)
@app.get('/api/data')
def get_data(req, res):
    res.json({
        'name': 'Example',
        'items': [1, 2, 3]
    })
Sending JSON Data (Express Style)
def get_data(req, res):
    res.json({
        'name': 'Example',
        'items': [1, 2, 3]
    })
    
app.get('/api/data', get_data)
Status Codes (Decorator Style)
@app.post('/api/items')
def create_item(req, res):
    # Create item logic...
    res.status(201).json({'message': 'Created'})
Status Codes (Express Style)
def create_item(req, res):
    # Create item logic...
    res.status(201).json({'message': 'Created'})
    
app.post('/api/items', create_item)
Error Responses (Decorator Style)
@app.get('/api/protected')
def protected(req, res):
    if not is_authenticated(req):
        return res.status(401).json({
            'error': 'Unauthorized'
        })
Error Responses (Express Style)
def protected(req, res):
    if not is_authenticated(req):
        return res.status(401).json({
            'error': 'Unauthorized'
        })
        
app.get('/api/protected', protected)

Response Methods

Sending Responses

Response methods allow you to send different types of data back to the client. Each method terminates the request-response cycle unless otherwise specified.

res.send(data)

Sends a response with the provided data. The data type determines the Content-Type header.

@app.get('/hello')
def hello(req, res):
    res.send('Hello, World!')

res.json(obj)

Sends a JSON response. Automatically sets the Content-Type header to application/json.

@app.get('/api/data')
def get_data(req, res):
    res.json({
        'name': 'Example',
        'items': [1, 2, 3],
        'active': True
    })

res.status(code)

Sets the HTTP status code for the response. This method is chainable.

@app.post('/api/items')
def create_item(req, res):
    # Create item logic...
    res.status(201).json({
        'message': 'Item created',
        'id': 'new-item-id'
    })

res.redirect(path)

Redirects the request to the specified path with status code 302 by default.

@app.get('/old-page')
def old_page(req, res):
    # Temporary redirect (302)
    res.redirect('/new-page')

Method Chaining

Many response methods return the response object, allowing you to chain multiple methods together for more concise code.

@app.get('/api/chainable')
def chainable(req, res):
    res.status(200)
       .set_header('X-Custom-Header', 'value')
       .set_header('Content-Type', 'application/json')
       .send('{"message": "Success"}')

Pro Tip

Only methods that don't end the request-response cycle (like status() and set_header()) can be chained.

Using Middleware

Middleware Basics

Middleware functions are functions that have access to the request object, response object, and the next middleware function in the application's request-response cycle. Middleware can:

  • Process incoming requests before they reach route handlers
  • Modify the request and response objects
  • End the request-response cycle early
  • Call the next middleware function in the stack

Middleware Structure:

Every middleware function follows the same pattern and must accept three parameters:

  • req (Request object)

    Contains information about the HTTP request.

  • res (Response object)

    Provides methods to send responses.

  • next (Function)

    A function that passes control to the next middleware. You must call next() unless you want to end the request cycle.

Registering Middleware

Expressify provides two different ways to register middleware in your application. You can use either the decorator syntax (Python-idiomatic) or the Express-like function call syntax. Both approaches achieve the same result.

Decorator Syntax
Express-like Syntax

The decorator syntax is more Pythonic and allows you to apply middleware with the @app.use decorator or directly in route definitions.

from expressify import expressify

app = expressify()

# Global middleware using decorator
@app.use
def logger_middleware(req, res, next):
    print(f"{req.method} {req.path}")
    next()

# Define authentication middleware
def auth_middleware(req, res, next):
    if not req.headers.get('Authorization'):
        return res.status(401).send('Unauthorized')
    next()

# Regular route - no middleware
@app.get('/')
def home(req, res):
    res.send('Home page')

# Route with middleware parameter
@app.get('/admin', [auth_middleware])
def admin(req, res):
    res.send('Admin dashboard')

# Multiple middleware functions
@app.get('/profile', [auth_middleware, logger_middleware])
def profile(req, res):
    res.send('User profile')

if __name__ == '__main__':
    app.listen(port=3000, hostname='127.0.0.1')

Middleware Examples

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. Please provide X-API-Key header.'
            })
        
        if api_key != 'abc123':
            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'}
    
    # Call the next middleware/route handler
    return next()

# Apply middleware to all routes
app.use(auth_middleware)

# This route requires API key
@app.get('/protected/data')
def protected_data(req, res):
    # The auth middleware will have already verified the API key
    return res.json({
        'message': 'You have accessed protected data',
        'user': req.user,
        'timestamp': time.time()
    })

Rate Limiter Middleware

# Rate Limiter Middleware
def rate_limiter(max_requests=100, window_seconds=60):
    """
    Creates a rate limiting middleware function
    
    Args:
        max_requests (int): Maximum number of requests allowed
        window_seconds (int): Time window in seconds
    """
    # Store request timestamps for each client
    clients = {}
    
    def middleware(req, res, next):
        client_ip = req.get_header("x-forwarded-for") or req.remote_addr
        
        # Initialize client record if doesn't exist
        if client_ip not in clients:
            clients[client_ip] = []
        
        # Get current time
        now = time.time()
        
        # Remove requests outside the window
        clients[client_ip] = [t for t in clients[client_ip] if now - t < window_seconds]
        
        # Check if client has exceeded rate limit
        if len(clients[client_ip]) >= max_requests:
            return res.status(429).json({
                "error": "Too Many Requests",
                "message": f"Rate limit of {max_requests} requests per {window_seconds} seconds exceeded"
            })
        
        # Add current request timestamp
        clients[client_ip].append(now)
        
        # Add rate limit headers
        remaining = max_requests - len(clients[client_ip])
        res.set_header("X-RateLimit-Limit", str(max_requests))
        res.set_header("X-RateLimit-Remaining", str(remaining))
        res.set_header("X-RateLimit-Reset", str(int(now + window_seconds)))
        
        return next()
    
    return middleware

# Create API rate limiter with custom limits
api_rate_limiter = rate_limiter(max_requests=5, window_seconds=10)

# Apply to specific routes
@app.get('/api/status', [api_rate_limiter])
def api_status(req, res):
    return res.json({
        "status": "online",
        "timestamp": time.time()
    })

Best Practice

For error handling middleware, it's recommended to define it as the first middleware in your application. This ensures that any errors thrown in subsequent middleware or route handlers will be caught and handled properly.

Middleware Order

Middleware functions are executed in the order they are defined. This means that the order in which you register middleware is important.

from expressify import expressify

app = expressify()

# Register middleware in specific order
@app.use
def middleware1(req, res, next):
    print("Middleware 1 - Before")
    next()
    print("Middleware 1 - After")

@app.use
def middleware2(req, res, next):
    print("Middleware 2 - Before")
    next()
    print("Middleware 2 - After")

@app.get('/')
def home(req, res):
    print("Route Handler")
    res.send('Home')

# Output for a request to '/' would be:
# Middleware 1 - Before
# Middleware 2 - Before
# Route Handler
# Middleware 2 - After
# Middleware 1 - After

Middleware Execution Flow

Request
Global Middleware
Path-specific Middleware
Route-specific Middleware
Route Handler
Response

Request Object

Request Basics

The request object contains information about the incoming request, such as the HTTP method, URL, headers, and body.

Request Methods:

  • GET: Retrieves data from the server
  • POST: Submits data to be processed
  • PUT: Updates existing data on the server
  • DELETE: Deletes data from the server
  • PATCH: Partially updates data on the server
  • OPTIONS: Describes HTTP methods supported by the server

Request Headers:

Headers are key-value pairs that provide additional information about the request.

  • Authorization: Authentication token
  • Content-Type: Type of data being sent
  • Accept: Accepted response content types
  • User-Agent: Information about the client software
  • X-Forwarded-For: IP address of the client

Query Parameters:

Query parameters are appended to the URL and are used to send data to the server.

@app.get('/search')
def search(req, res):
    query = req.query.get('q')
    res.send(f'Searching for: {query}')

Route Parameters:

Route parameters are part of the URL path and are used to capture values from the URL.

@app.get('/users/:id')
def get_user(req, res):
    user_id = req.params.get('id')
    res.send(f'User ID: {user_id}')

Request Body:

The request body contains data sent by the client to the server.

@app.post('/users')
def create_user(req, res):
    user_data = req.body
    # Process user data...
    res.status(201).json({'message': 'User created', 'user': user_data})

Request Object Methods

The request object provides several methods to access information about the request.

req.method:

Returns the HTTP method of the request.

@app.get('/')
def home(req, res):
    res.send(f"Method: {req.method}")

req.url:

Returns the full URL of the request.

@app.get('/')
def home(req, res):
    res.send(f"URL: {req.url}")

req.headers:

Returns a dictionary of request headers.

@app.get('/')
def home(req, res):
    res.send(f"Headers: {req.headers}")

req.query:

Returns a dictionary of query parameters.

@app.get('/search')
def search(req, res):
    query = req.query.get('q')
    res.send(f'Searching for: {query}')

req.params:

Returns a dictionary of route parameters.

@app.get('/users/:id')
def get_user(req, res):
    user_id = req.params.get('id')
    res.send(f'User ID: {user_id}')

req.body:

Contains the parsed request body.

@app.post('/users')
def create_user(req, res):
    user_data = req.body
    # Process user data...
    res.status(201).json({'message': 'User created', 'user': user_data})

Response Object

Response Basics

The response object is used to send data back to the client. It provides methods to set the status code, headers, and body.

Setting Status Code:

Use res.status(code) to set the HTTP status code.

@app.get('/')
def home(req, res):
    res.status(200).send('OK')

Setting Headers:

Use res.set_header('Header-Name', 'Value') to set custom headers.

@app.get('/')
def home(req, res):
    res.set_header('X-Custom-Header', 'Value')
    res.send('OK')

Sending Data:

Use res.send(data) to send various types of data back to the client.

@app.get('/')
def home(req, res):
    res.send('Hello, World!')

Sending JSON:

Use res.json(obj) to send JSON data back to the client.

@app.get('/api/data')
def get_data(req, res):
    res.json({
        'name': 'Example',
        'items': [1, 2, 3]
    })

Redirecting:

Use res.redirect(path) to redirect the request to a different path.

@app.get('/old-page')
def old_page(req, res):
    # Temporary redirect (302)
    res.redirect('/new-page')

Response Object Methods

The response object provides several methods to send data back to the client.

res.status(code):

Sets the HTTP status code for the response.

@app.get('/')
def home(req, res):
    res.status(200).send('OK')

res.set_header('Header-Name', 'Value'):

Sets a custom header for the response.

@app.get('/')
def home(req, res):
    res.set_header('X-Custom-Header', 'Value')
    res.send('OK')

res.type(content_type):

Sets the Content-Type HTTP header for the response.

# Setting different content types
@app.get('/text')
def text(req, res):
    res.type('text/plain').send('Plain text content')

@app.get('/html')
def html(req, res):
    res.type('text/html').send('

HTML Content

') @app.get('/xml') def xml(req, res): res.type('application/xml').send('XML Content') @app.get('/css') def css(req, res): res.type('text/css').send('body { color: blue; }')

res.send(data):

Sends various types of data back to the client.

@app.get('/')
def home(req, res):
    res.send('Hello, World!')

res.json(obj):

Sends JSON data back to the client.

@app.get('/api/data')
def get_data(req, res):
    res.json({
        'name': 'Example',
        'items': [1, 2, 3]
    })

res.redirect(path):

Redirects the request to a different path.

@app.get('/old-page')
def old_page(req, res):
    # Temporary redirect (302)
    res.redirect('/new-page')

Middleware

Middleware Basics

Middleware functions are functions that have access to the request object, response object, and the next middleware function in the application's request-response cycle. Middleware can:

  • Process incoming requests before they reach route handlers
  • Modify the request and response objects
  • End the request-response cycle early
  • Call the next middleware function in the stack

Middleware Structure:

Every middleware function follows the same pattern and must accept three parameters:

  • req (Request object)

    Contains information about the HTTP request.

  • res (Response object)

    Provides methods to send responses.

  • next (Function)

    A function that passes control to the next middleware. You must call next() unless you want to end the request cycle.

Registering Middleware

There are several ways to register middleware in your application. You can apply middleware globally to all routes, to specific routes, or to routes under a specific path prefix.

Decorator Syntax
Express-like Syntax

Decorator syntax provides a cleaner way to apply middleware with the @app.use decorator or through route parameters.

from expressify import expressify

app = expressify()

# Global middleware using decorator
@app.use
def logger_middleware(req, res, next):
    print(f"{req.method} {req.path}")
    next()

# Authentication middleware for protected routes
def auth_middleware(req, res, next):
    if not req.headers.get('Authorization'):
        return res.status(401).send('Unauthorized')
    next()

# Regular route - no middleware
@app.get('/')
def home(req, res):
    res.send('Home page')

# Route with middleware param
@app.get('/admin', middleware=[auth_middleware])
def admin(req, res):
    res.send('Admin dashboard')

# Multiple middleware functions
@app.get('/profile', middleware=[auth_middleware, logger_middleware])
def profile(req, res):
    res.send('User profile')

if __name__ == '__main__':
    app.listen(port=3000, hostname="127.0.0.1")

Middleware Examples

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. Please provide X-API-Key header.'
            })
        
        if api_key != 'abc123':
            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'}
    
    # Call the next middleware/route handler
    return next()

# Apply middleware to all routes
app.use(auth_middleware)

# This route requires API key
@app.get('/protected/data')
def protected_data(req, res):
    # The auth middleware will have already verified the API key
    return res.json({
        'message': 'You have accessed protected data',
        'user': req.user,
        'timestamp': time.time()
    })

Request Logging

import time

def logger_middleware(req, res, next):
    # Start time
    start_time = time.time()
    
    # Log request
    print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {req.method} {req.path}")
    
    # Store start time on request object
    req.start_time = start_time
    
    # Call next middleware
    next()
    
    # Calculate duration after response
    duration = time.time() - start_time
    
    # Log response
    print(f"Response: {res.status_code} in {duration:.2f}s")

CORS Middleware

def cors_middleware(req, res, next):
    # Allow requests from any origin
    res.set_header('Access-Control-Allow-Origin', '*')
    
    # Allow specific HTTP methods
    res.set_header('Access-Control-Allow-Methods', 
                  'GET, POST, PUT, DELETE, OPTIONS')
    
    # Allow specific headers
    res.set_header('Access-Control-Allow-Headers', 
                  'Content-Type, Authorization')
    
    # Handle preflight requests
    if req.method == 'OPTIONS':
        return res.status(204).send()
    
    next()

Error Handling

def error_handler(req, res, next):
    try:
        next()
    except Exception as e:
        print(f"Error: {str(e)}")
        
        # Send appropriate response based on error
        status_code = getattr(e, 'status_code', 500)
        message = getattr(e, 'message', str(e))
        
        res.status(status_code).json({
            'error': True,
            'message': message
        })

Best Practice

For error handling middleware, it's recommended to define it as the first middleware in your application. This ensures that any errors thrown in subsequent middleware or route handlers will be caught and handled properly.

Middleware Order

Middleware functions are executed in the order they are defined. This means that the order in which you register middleware is important.

from expressify import expressify

app = expressify()

# Register middleware in specific order
@app.use
def middleware1(req, res, next):
    print("Middleware 1 - Before")
    next()
    print("Middleware 1 - After")

@app.use
def middleware2(req, res, next):
    print("Middleware 2 - Before")
    next()
    print("Middleware 2 - After")

@app.get('/')
def home(req, res):
    print("Route Handler")
    res.send('Home')

# Output for a request to '/' would be:
# Middleware 1 - Before
# Middleware 2 - Before
# Route Handler
# Middleware 2 - After
# Middleware 1 - After

Middleware Execution Flow

Request
Global Middleware
Path-specific Middleware
Route-specific Middleware
Route Handler
Response

Template Rendering

Template Basics

Expressify uses Jinja2 as its template engine. Jinja2 is a powerful templating engine for Python.

Setting Up Templates:

Templates are stored in a directory called views. You can set this directory using the views setting in your application.

from expressify import expressify
import os

app = expressify()

# Set the template engine to Jinja2
app.set('view engine', 'jinja2')

# Set the templates directory
app.set('views', os.path.join(os.path.dirname(__file__), 'views'))

Rendering Templates:

Use the res.render() method to render templates.

@app.get('/')
def home(req, res):
    res.render('index.html')

Template Variables:

You can pass variables to templates using the res.render() method.

# Method 1: Pass data as a dictionary
@app.get('/example1')
def example1(req, res):
    res.render('index.html', {
        'title': 'Home',
        'message': 'Welcome to Expressify',
        'items': ['Item 1', 'Item 2', 'Item 3']
    })

# Method 2: Express.js style - store data in a variable first
@app.get('/example2')
def example2(req, res):
    # Data to pass to the view
    data = {
        'title': 'Hello, World!',
        'message': 'Welcome to my Expressify app!',
        'user': {
            'name': 'John Doe',
            'age': 30
        }
    }
    
    # Render the view and pass the data
    res.render('index.html', data)

Template Inheritance:

Jinja2 supports template inheritance, allowing you to create a base template that other templates can extend.

{% extends "base.html" %}

{% block content %}

Welcome to Expressify

{% endblock %}

Template Filters:

Jinja2 provides several built-in filters that you can use in your templates.

Built-in Filters:

  • safe: Marks the value as safe for HTML output
  • capitalize: Capitalizes the first letter of the value
  • lower: Converts the value to lowercase
  • upper: Converts the value to uppercase
  • title: Capitalizes the first letter of each word
  • striptags: Strips HTML tags from the value
  • escape: Escapes HTML characters in the value

Custom Filters:

You can also define your own filters in Python.

from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('templates'))

def format_date(date):
    return date.strftime('%Y-%m-%d')

env.filters['format_date'] = format_date

Static Files

Setting Up Static Files:

Expressify provides a built-in middleware for serving static files such as CSS, JavaScript, and images.

Serving Static Files:

There are two main approaches to serving static files:

from expressify import expressify
from expressify.lib.middleware import Middleware
import os

app = expressify()

# Method 1: Serve files from the 'public' directory at the root URL path
public_dir = os.path.join(os.path.dirname(__file__), 'public')
app.use(Middleware.static(public_dir))

# Method 2: Serve files from a directory at a specific URL path
# This mounts the 'public/assets' directory at the '/assets' URL path
assets_dir = os.path.join(os.path.dirname(__file__), 'public', 'assets')
app.use('/assets', Middleware.static(assets_dir))

Serving Specific Files:

You can also serve specific files directly.

from expressify.lib.middleware import Middleware
import os

favicon_path = os.path.join(os.path.dirname(__file__), 'public', 'favicon.ico')
app.get('/favicon.ico', lambda req, res: res.sendFile(favicon_path))

Using Static Files in Templates:

You can use static files in your templates by directly referencing their paths:

Example:







Logo


Icon


Error Handling

Error Handling Basics

Expressify provides a simple way to handle errors using middleware.

Error Handling Middleware:

You can define error handling middleware to catch exceptions and send a custom response.

def error_handler(req, res, next):
    try:
        next()
    except Exception as e:
        print(f"Error: {str(e)}")
        
        # Send appropriate response based on error
        status_code = getattr(e, 'status_code', 500)
        message = getattr(e, 'message', str(e))
        
        res.status(status_code).json({
            'error': True,
            'message': message
        })

Error Pages:

You can also define custom error pages for specific status codes.

from expressify import expressify

app = expressify()

# Custom 404 handler
@app.error(404)
def not_found(req, res):
    res.render('404.html')

# Custom 500 handler
@app.error(500)
def internal_error(req, res):
    res.render('500.html')

Error Handling in Route Handlers:

You can use try-except blocks to handle errors in route handlers.

Example:

@app.get('/')
def home(req, res):
    try:
        # Route handler logic
        res.render('index.html')
    except Exception as e:
        print(f"Error: {str(e)}")
        
        # Send appropriate response based on error
        status_code = getattr(e, 'status_code', 500)
        message = getattr(e, 'message', str(e))
        
        res.status(status_code).json({
            'error': True,
            'message': message
        })

Utilities

Common Utilities

Expressify provides several utilities to help with common tasks.

app.locals:

app.locals is an object that persists throughout the lifetime of the application. You can use it to store app-level data.

app.locals.title = 'My Application'
app.locals.version = '1.0.0'

app.set(name, value):

app.set is used to set application-level settings like the template engine or the static files directory.

app.set('view engine', 'jinja2')
app.set('views', './views')
app.set('static_folder', 'static')

Request Object Methods:

The request object provides several methods to access information about the request.

req.method:

Returns the HTTP method of the request.

@app.get('/')
def home(req, res):
    res.send(f"Method: {req.method}")

req.url:

Returns the full URL of the request.

@app.get('/')
def home(req, res):
    res.send(f"URL: {req.url}")

req.headers:

Returns a dictionary of request headers.

@app.get('/')
def home(req, res):
    res.send(f"Headers: {req.headers}")

req.query:

Returns a dictionary of query parameters.

@app.get('/search')
def search(req, res):
    query = req.query.get('q')
    res.send(f'Searching for: {query}')

req.params:

Returns a dictionary of route parameters.

@app.get('/users/:id')
def get_user(req, res):
    user_id = req.params.get('id')
    res.send(f'User ID: {user_id}')

req.body:

Contains the parsed request body.

@app.post('/users')
def create_user(req, res):
    user_data = req.body
    # Process user data...
    res.status(201).json({'message': 'User created', 'user': user_data})

Response Object Methods:

The response object provides several methods to send data back to the client.

res.status(code):

Sets the HTTP status code for the response.

@app.get('/')
def home(req, res):
    res.status(200).send('OK')

res.set_header('Header-Name', 'Value'):

Sets a custom header for the response.

@app.get('/')
def home(req, res):
    res.set_header('X-Custom-Header', 'Value')
    res.send('OK')

res.type(content_type):

Sets the Content-Type HTTP header for the response.

# Setting different content types
@app.get('/text')
def text(req, res):
    res.type('text/plain').send('Plain text content')

@app.get('/html')
def html(req, res):
    res.type('text/html').send('

HTML Content

') @app.get('/xml') def xml(req, res): res.type('application/xml').send('XML Content') @app.get('/css') def css(req, res): res.type('text/css').send('body { color: blue; }')

res.send(data):

Sends various types of data back to the client.

@app.get('/')
def home(req, res):
    res.send('Hello, World!')

res.json(obj):

Sends JSON data back to the client.

@app.get('/api/data')
def get_data(req, res):
    res.json({
        'name': 'Example',
        'items': [1, 2, 3]
    })

res.redirect(path):

Redirects the request to a different path.

@app.get('/old-page')
def old_page(req, res):
    # Temporary redirect (302)
    res.redirect('/new-page')