329 lines
11 KiB
HTML
329 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Extensions - pyserve</title>
|
|
<link rel="stylesheet" href="../style.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
|
<script>hljs.highlightAll();</script>
|
|
</head>
|
|
<body>
|
|
<div id="container">
|
|
<div id="header">
|
|
<h1>pyserve</h1>
|
|
<div class="tagline">python application orchestrator</div>
|
|
</div>
|
|
|
|
<div class="breadcrumb">
|
|
<a href="../index.html">Home</a> / <a href="index.html">Reference</a> / Extensions
|
|
</div>
|
|
|
|
<div id="content">
|
|
<h2>Extensions</h2>
|
|
|
|
<p>pyserve uses a modular extension system for adding functionality. Extensions
|
|
are loaded in order and can process requests and modify responses.</p>
|
|
|
|
<h3>Built-in Extensions</h3>
|
|
|
|
<table class="dirindex">
|
|
<tr>
|
|
<td><code>process_orchestration</code></td>
|
|
<td>Run ASGI/WSGI apps in isolated processes with health monitoring</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>routing</code></td>
|
|
<td>nginx-style URL routing with regex patterns</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>asgi</code></td>
|
|
<td>Mount ASGI/WSGI applications in-process</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>security</code></td>
|
|
<td>Security headers and IP filtering</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>caching</code></td>
|
|
<td>Response caching (in development)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>monitoring</code></td>
|
|
<td>Request metrics and statistics</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Extension Configuration</h3>
|
|
<p>Extensions are configured in the <code>extensions</code> section:</p>
|
|
|
|
<pre><code class="language-yaml">extensions:
|
|
- type: routing
|
|
config:
|
|
# extension-specific configuration
|
|
|
|
- type: security
|
|
config:
|
|
# ...</code></pre>
|
|
|
|
<h3>Routing Extension</h3>
|
|
<p>The primary extension for URL routing. See <a href="../guides/routing.html">Routing Guide</a> for full documentation.</p>
|
|
|
|
<pre><code class="language-python">- type: routing
|
|
config:
|
|
regex_locations:
|
|
"=/health":
|
|
return: "200 OK"
|
|
"~^/api/":
|
|
proxy_pass: "http://backend:9001"
|
|
"__default__":
|
|
root: "./static"</code></pre>
|
|
|
|
<h3>Security Extension</h3>
|
|
<p>Adds security headers and IP-based access control.</p>
|
|
|
|
<h4>Configuration Options</h4>
|
|
<dl>
|
|
<dt>security_headers</dt>
|
|
<dd>Dictionary of security headers to add to all responses</dd>
|
|
|
|
<dt>allowed_ips</dt>
|
|
<dd>List of allowed IP addresses (whitelist mode)</dd>
|
|
|
|
<dt>blocked_ips</dt>
|
|
<dd>List of blocked IP addresses (blacklist mode)</dd>
|
|
</dl>
|
|
|
|
<pre><code class="language-bash">- type: security
|
|
config:
|
|
security_headers:
|
|
X-Frame-Options: DENY
|
|
X-Content-Type-Options: nosniff
|
|
X-XSS-Protection: "1; mode=block"
|
|
Strict-Transport-Security: "max-age=31536000"
|
|
blocked_ips:
|
|
- "192.168.1.100"
|
|
- "10.0.0.50"</code></pre>
|
|
|
|
<p>Default security headers if not specified:</p>
|
|
<ul class="indent">
|
|
<li><code>X-Content-Type-Options: nosniff</code></li>
|
|
<li><code>X-Frame-Options: DENY</code></li>
|
|
<li><code>X-XSS-Protection: 1; mode=block</code></li>
|
|
</ul>
|
|
|
|
<h3>Caching Extension</h3>
|
|
<p>Response caching for improved performance. <em>(Currently in development)</em></p>
|
|
|
|
<h4>Configuration Options</h4>
|
|
<dl>
|
|
<dt>cache_patterns</dt>
|
|
<dd>URL patterns to cache</dd>
|
|
|
|
<dt>cache_ttl</dt>
|
|
<dd>Default cache TTL in seconds. Default: <code>3600</code></dd>
|
|
</dl>
|
|
|
|
<pre><code class="language-bash">- type: caching
|
|
config:
|
|
cache_ttl: 3600
|
|
cache_patterns:
|
|
- "/api/public/*"</code></pre>
|
|
|
|
<h3>Monitoring Extension</h3>
|
|
<p>Collects request metrics and provides statistics.</p>
|
|
|
|
<h4>Configuration Options</h4>
|
|
<dl>
|
|
<dt>enable_metrics</dt>
|
|
<dd>Enable metrics collection. Default: <code>true</code></dd>
|
|
</dl>
|
|
|
|
<pre><code class="language-bash">- type: monitoring
|
|
config:
|
|
enable_metrics: true</code></pre>
|
|
|
|
<p>Collected metrics (available at <code>/metrics</code>):</p>
|
|
<ul class="indent">
|
|
<li><code>request_count</code> — Total number of requests</li>
|
|
<li><code>error_count</code> — Number of requests with 4xx/5xx status</li>
|
|
<li><code>error_rate</code> — Error rate (errors / total)</li>
|
|
<li><code>avg_response_time</code> — Average response time in seconds</li>
|
|
</ul>
|
|
|
|
<h3>Built-in Endpoints</h3>
|
|
<p>pyserve provides built-in endpoints regardless of extensions:</p>
|
|
|
|
<table class="dirindex">
|
|
<tr>
|
|
<td><code>/health</code></td>
|
|
<td>Health check endpoint, returns <code>200 OK</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/metrics</code></td>
|
|
<td>JSON metrics from all extensions</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Extension Processing Order</h3>
|
|
<p>Extensions process requests in the order they are defined:</p>
|
|
<ol class="indent">
|
|
<li>Request comes in</li>
|
|
<li>Each extension's <code>process_request</code> is called in order</li>
|
|
<li>First extension to return a response wins</li>
|
|
<li>Response passes through each extension's <code>process_response</code></li>
|
|
<li>Response is sent to client</li>
|
|
</ol>
|
|
|
|
<div class="note">
|
|
<strong>Note:</strong> Place the <code>routing</code> extension last if you want
|
|
other extensions (like security) to process requests first.
|
|
</div>
|
|
|
|
<h3>ASGI Extension</h3>
|
|
<p>Mount external ASGI/WSGI applications (FastAPI, Flask, Django, etc.) at specified paths.</p>
|
|
|
|
<h4>Configuration Options</h4>
|
|
<dl>
|
|
<dt>mounts</dt>
|
|
<dd>List of mount configurations (see below)</dd>
|
|
</dl>
|
|
|
|
<h4>Mount Configuration</h4>
|
|
<dl>
|
|
<dt>path</dt>
|
|
<dd>URL path where the app will be mounted. Example: <code>/api</code></dd>
|
|
|
|
<dt>app_path</dt>
|
|
<dd>Python import path. Format: <code>module:attribute</code></dd>
|
|
|
|
<dt>app_type</dt>
|
|
<dd>Application type: <code>asgi</code> or <code>wsgi</code>. Default: <code>asgi</code></dd>
|
|
|
|
<dt>module_path</dt>
|
|
<dd>Optional path to add to <code>sys.path</code></dd>
|
|
|
|
<dt>factory</dt>
|
|
<dd>If <code>true</code>, call as factory function. Default: <code>false</code></dd>
|
|
|
|
<dt>factory_args</dt>
|
|
<dd>Arguments to pass to factory function</dd>
|
|
|
|
<dt>name</dt>
|
|
<dd>Friendly name for logging</dd>
|
|
|
|
<dt>strip_path</dt>
|
|
<dd>Remove mount path from request URL. Default: <code>true</code></dd>
|
|
|
|
<dt>django_settings</dt>
|
|
<dd>Django settings module (for Django apps only)</dd>
|
|
</dl>
|
|
|
|
<pre><code class="language-bash">- type: asgi
|
|
config:
|
|
mounts:
|
|
# FastAPI application
|
|
- path: "/api"
|
|
app_path: "myapp.api:app"
|
|
app_type: asgi
|
|
name: "api"
|
|
|
|
# Flask application (WSGI)
|
|
- path: "/admin"
|
|
app_path: "myapp.admin:app"
|
|
app_type: wsgi
|
|
name: "admin"
|
|
|
|
# Factory pattern with arguments
|
|
- path: "/api/v2"
|
|
app_path: "myapp.api:create_app"
|
|
factory: true
|
|
factory_args:
|
|
debug: true
|
|
version: "2.0"</code></pre>
|
|
|
|
<p>Supported frameworks:</p>
|
|
<ul class="indent">
|
|
<li><strong>FastAPI</strong> — Native ASGI (<code>app_type: asgi</code>)</li>
|
|
<li><strong>Starlette</strong> — Native ASGI (<code>app_type: asgi</code>)</li>
|
|
<li><strong>Flask</strong> — WSGI, auto-wrapped (<code>app_type: wsgi</code>)</li>
|
|
<li><strong>Django</strong> — Use <code>django_settings</code> parameter</li>
|
|
<li><strong>Custom ASGI</strong> — Any ASGI-compatible application</li>
|
|
</ul>
|
|
|
|
<div class="note">
|
|
<strong>Note:</strong> For WSGI applications, install <code>a2wsgi</code> or <code>asgiref</code>:
|
|
<code>pip install a2wsgi</code>
|
|
</div>
|
|
|
|
<p>See <a href="../guides/asgi-mount.html">ASGI Mounting Guide</a> for detailed documentation.</p>
|
|
|
|
<h3>Process Orchestration Extension</h3>
|
|
<p>The flagship extension for running apps in isolated subprocesses. <strong>Recommended for production.</strong></p>
|
|
|
|
<h4>Key Features</h4>
|
|
<ul class="indent">
|
|
<li>Process isolation — each app runs in its own subprocess</li>
|
|
<li>Health monitoring with automatic restart</li>
|
|
<li>Multi-worker support per application</li>
|
|
<li>Dynamic port allocation (9000-9999)</li>
|
|
<li>Request tracing with X-Request-ID</li>
|
|
</ul>
|
|
|
|
<pre><code class="language-yaml">- type: process_orchestration
|
|
config:
|
|
port_range: [9000, 9999]
|
|
health_check_enabled: true
|
|
proxy_timeout: 60.0
|
|
logging:
|
|
httpx_level: warning
|
|
proxy_logs: true
|
|
health_check_logs: false
|
|
apps:
|
|
- name: api
|
|
path: /api
|
|
app_path: myapp.api:app
|
|
workers: 4
|
|
health_check_path: /health
|
|
|
|
- name: admin
|
|
path: /admin
|
|
app_path: myapp.admin:app
|
|
app_type: wsgi
|
|
workers: 2</code></pre>
|
|
|
|
<h4>App Configuration</h4>
|
|
<dl>
|
|
<dt>name</dt>
|
|
<dd>Unique identifier (required)</dd>
|
|
|
|
<dt>path</dt>
|
|
<dd>URL path prefix (required)</dd>
|
|
|
|
<dt>app_path</dt>
|
|
<dd>Python import path (required)</dd>
|
|
|
|
<dt>app_type</dt>
|
|
<dd><code>asgi</code> or <code>wsgi</code>. Default: <code>asgi</code></dd>
|
|
|
|
<dt>workers</dt>
|
|
<dd>Number of uvicorn workers. Default: <code>1</code></dd>
|
|
|
|
<dt>health_check_path</dt>
|
|
<dd>Health endpoint. Default: <code>/health</code></dd>
|
|
|
|
<dt>max_restart_count</dt>
|
|
<dd>Max restart attempts. Default: <code>5</code></dd>
|
|
</dl>
|
|
|
|
<p>See <a href="../guides/process-orchestration.html">Process Orchestration Guide</a> for full documentation.</p>
|
|
</div>
|
|
|
|
<div id="footer">
|
|
<p>pyserve © 2024-2025 | MIT License</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|