Refactor documentation for reverse proxy and routing guides
All checks were successful
Deploy to Production / deploy (push) Successful in 5s

This commit is contained in:
Илья Глазунов 2025-12-08 01:05:52 +03:00
parent 58660ec8d4
commit 00119ce463
12 changed files with 521 additions and 517 deletions

View File

@ -77,11 +77,30 @@ All documentation pages follow this structure:
## Code Highlighting ## Code Highlighting
All pages include highlight.js for automatic syntax highlighting: All pages use highlight.js for automatic syntax highlighting:
- CSS theme: `github-dark.min.css` (matches dark theme) - **Theme**: `github-dark.min.css` (matches dark theme)
- Auto-initialization: `hljs.highlightAll()` - **Auto-initialization**: `hljs.highlightAll()` runs on page load
- Custom styles in `style.css` integrate with highlight.js - **Custom styles**: Enhanced color palette in `style.css`
- **Languages detected**: YAML, Bash, Python, Plaintext
### Code Block Format
All code blocks use semantic language classes:
```html
<pre><code class="language-yaml">
server:
host: 0.0.0.0
port: 8080
</code></pre>
```
Supported languages:
- `language-yaml` — YAML configuration files
- `language-bash` — Shell commands and scripts
- `language-python` — Python code examples
- `language-plaintext` — Plain text output
## Deployment ## Deployment

View File

@ -32,32 +32,32 @@
<h3>Install from Release (Recommended)</h3> <h3>Install from Release (Recommended)</h3>
<p>Download the latest wheel file from <a href="https://git.pyserve.org/Shifty/pyserveX/releases">Git Releases</a> and install it:</p> <p>Download the latest wheel file from <a href="https://git.pyserve.org/Shifty/pyserveX/releases">Git Releases</a> and install it:</p>
<pre><span class="comment"># Download the wheel file from releases</span> <pre><code class="language-bash"># Download the wheel file from releases
<span class="comment"># Example: pyserve-0.7.0-py3-none-any.whl</span> # Example: pyserve-0.7.0-py3-none-any.whl
pip install pyserve-0.7.0-py3-none-any.whl</pre> pip install pyserve-0.7.0-py3-none-any.whl</code></pre>
<p>After installation, the <code>pyserve</code> command will be available in your terminal:</p> <p>After installation, the <code>pyserve</code> command will be available in your terminal:</p>
<pre>pyserve --version</pre> <pre><code class="language-bash">pyserve --version</code></pre>
<h3>Install from Source</h3> <h3>Install from Source</h3>
<p>For development or if you want the latest changes:</p> <p>For development or if you want the latest changes:</p>
<pre><span class="comment"># Clone the repository</span> <pre><code class="language-bash"># Clone the repository
git clone https://github.com/ShiftyX1/PyServe.git git clone https://github.com/ShiftyX1/PyServe.git
cd PyServe cd PyServe
<span class="comment"># Install with Poetry (recommended for development)</span> # Install with Poetry (recommended for development)
make init make init
<span class="comment"># Or build and install the package</span> # Or build and install the package
make build make build
pip install dist/pyserve-*.whl</pre> pip install dist/pyserve-*.whl</code></pre>
<h3>Verify Installation</h3> <h3>Verify Installation</h3>
<p>Check that pyserve is installed correctly:</p> <p>Check that pyserve is installed correctly:</p>
<pre>pyserve --version <pre><code class="language-bash">pyserve --version
<span class="comment"># Output: pyserve 0.7.0</span></pre> # Output: pyserve 0.7.0</code></pre>
<h3>Dependencies</h3> <h3>Dependencies</h3>
<p>pyserve automatically installs the following dependencies:</p> <p>pyserve automatically installs the following dependencies:</p>

View File

@ -28,37 +28,37 @@
<h3>1. Create Configuration File</h3> <h3>1. Create Configuration File</h3>
<p>Create a file named <code>config.yaml</code> in your project directory:</p> <p>Create a file named <code>config.yaml</code> in your project directory:</p>
<pre><span class="directive">http:</span> <pre><code class="language-yaml">http:
<span class="directive">static_dir:</span> <span class="value">./static</span> static_dir: ./static
<span class="directive">templates_dir:</span> <span class="value">./templates</span> templates_dir: ./templates
<span class="directive">server:</span> server:
<span class="directive">host:</span> <span class="value">0.0.0.0</span> host: 0.0.0.0
<span class="directive">port:</span> <span class="value">8080</span> port: 8080
<span class="directive">logging:</span> logging:
<span class="directive">level:</span> <span class="value">INFO</span> level: INFO
<span class="directive">console_output:</span> <span class="value">true</span> console_output: true
<span class="directive">extensions:</span> extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"__default__"</span>: "__default__":
<span class="directive">root:</span> <span class="value">"./static"</span> root: "./static"
<span class="directive">index_file:</span> <span class="value">"index.html"</span></pre> index_file: "index.html"</code></pre>
<h3>2. Create Static Directory</h3> <h3>2. Create Static Directory</h3>
<p>Create a <code>static</code> folder and add an <code>index.html</code>:</p> <p>Create a <code>static</code> folder and add an <code>index.html</code>:</p>
<pre>mkdir -p static <pre><code class="language-bash">mkdir -p static
echo '&lt;h1&gt;Hello from pyserve!&lt;/h1&gt;' &gt; static/index.html</pre> echo '&lt;h1&gt;Hello from pyserve!&lt;/h1&gt;' &gt; static/index.html</code></pre>
<h3>3. Start the Server</h3> <h3>3. Start the Server</h3>
<pre>pyserve</pre> <pre><code class="language-bash">pyserve</code></pre>
<p>You should see output like:</p> <p>You should see output like:</p>
<pre>Starting PyServe server on 0.0.0.0:8080</pre> <pre><code class="language-plaintext">Starting PyServe server on 0.0.0.0:8080</code></pre>
<h3>4. Open in Browser</h3> <h3>4. Open in Browser</h3>
<p>Navigate to <a href="http://localhost:8080">http://localhost:8080</a> — you should see your page!</p> <p>Navigate to <a href="http://localhost:8080">http://localhost:8080</a> — you should see your page!</p>
@ -66,44 +66,44 @@ echo '&lt;h1&gt;Hello from pyserve!&lt;/h1&gt;' &gt; static/index.html</pre>
<h3>Using CLI Options</h3> <h3>Using CLI Options</h3>
<p>Override configuration via command line:</p> <p>Override configuration via command line:</p>
<pre><span class="comment"># Use a different config file</span> <pre><code class="language-bash"># Use a different config file
pyserve -c /path/to/config.yaml pyserve -c /path/to/config.yaml
<span class="comment"># Override host and port</span> # Override host and port
pyserve --host 127.0.0.1 --port 9000 pyserve --host 127.0.0.1 --port 9000
<span class="comment"># Enable debug mode (verbose logging)</span> # Enable debug mode (verbose logging)
pyserve --debug</pre> pyserve --debug</code></pre>
<h3>Example: Serve Documentation</h3> <h3>Example: Serve Documentation</h3>
<p>Serve a documentation directory with proper caching:</p> <p>Serve a documentation directory with proper caching:</p>
<pre><span class="directive">http:</span> <pre><code class="language-yaml">http:
<span class="directive">static_dir:</span> <span class="value">./docs</span> static_dir: ./docs
<span class="directive">server:</span> server:
<span class="directive">host:</span> <span class="value">0.0.0.0</span> host: 0.0.0.0
<span class="directive">port:</span> <span class="value">8000</span> port: 8000
<span class="directive">extensions:</span> extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"=/"</span>: "=/":
<span class="directive">root:</span> <span class="value">"./docs"</span> root: "./docs"
<span class="directive">index_file:</span> <span class="value">"index.html"</span> index_file: "index.html"
<span class="value">"~*\\.(css|js)$"</span>: "~*\\.(css|js)$":
<span class="directive">root:</span> <span class="value">"./docs"</span> root: "./docs"
<span class="directive">cache_control:</span> <span class="value">"public, max-age=3600"</span> cache_control: "public, max-age=3600"
<span class="value">"~*\\.html$"</span>: "~*\\.html$":
<span class="directive">root:</span> <span class="value">"./docs"</span> root: "./docs"
<span class="directive">cache_control:</span> <span class="value">"no-cache"</span> cache_control: "no-cache"
<span class="value">"__default__"</span>: "__default__":
<span class="directive">root:</span> <span class="value">"./docs"</span> root: "./docs"
<span class="directive">index_file:</span> <span class="value">"index.html"</span></pre> index_file: "index.html"</code></pre>
<div class="note"> <div class="note">
<strong>Next Steps:</strong> <strong>Next Steps:</strong>

View File

@ -45,15 +45,15 @@
<h3>Configuration</h3> <h3>Configuration</h3>
<p>ASGI applications are mounted via the <code>asgi</code> extension:</p> <p>ASGI applications are mounted via the <code>asgi</code> extension:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">asgi</span> - type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
- <span class="directive">path:</span> <span class="value">"/api"</span> - path: "/api"
<span class="directive">app_path:</span> <span class="value">"myapp.api:app"</span> app_path: "myapp.api:app"
<span class="directive">app_type:</span> <span class="value">asgi</span> app_type: asgi
<span class="directive">name:</span> <span class="value">"api-app"</span> name: "api-app"
<span class="directive">strip_path:</span> <span class="value">true</span></pre> strip_path: true</code></pre>
<h3>Mount Configuration Options</h3> <h3>Mount Configuration Options</h3>
<dl> <dl>
@ -85,23 +85,23 @@
<h3>Mounting FastAPI</h3> <h3>Mounting FastAPI</h3>
<p>FastAPI applications are native ASGI:</p> <p>FastAPI applications are native ASGI:</p>
<pre><span class="comment"># myapp/api.py</span> <pre><code class="language-python"># myapp/api.py
from fastapi import FastAPI from fastapi import FastAPI
app = FastAPI() app = FastAPI()
@app.get("/users") @app.get("/users")
async def get_users(): async def get_users():
return [{"id": 1, "name": "Alice"}]</pre> return [{"id": 1, "name": "Alice"}]</code></pre>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">asgi</span> - type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
- <span class="directive">path:</span> <span class="value">"/api"</span> - path: "/api"
<span class="directive">app_path:</span> <span class="value">"myapp.api:app"</span> app_path: "myapp.api:app"
<span class="directive">app_type:</span> <span class="value">asgi</span> app_type: asgi
<span class="directive">name:</span> <span class="value">"fastapi-app"</span></pre> name: "fastapi-app"</code></pre>
<p>With this configuration:</p> <p>With this configuration:</p>
<ul class="indent"> <ul class="indent">
@ -112,23 +112,23 @@ async def get_users():
<h3>Mounting Flask</h3> <h3>Mounting Flask</h3>
<p>Flask applications are WSGI and will be automatically wrapped:</p> <p>Flask applications are WSGI and will be automatically wrapped:</p>
<pre><span class="comment"># myapp/flask_api.py</span> <pre><code class="language-python"># myapp/flask_api.py
from flask import Flask from flask import Flask
app = Flask(__name__) app = Flask(__name__)
@app.route("/hello") @app.route("/hello")
def hello(): def hello():
return {"message": "Hello from Flask!"}</pre> return {"message": "Hello from Flask!"}</code></pre>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">asgi</span> - type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
- <span class="directive">path:</span> <span class="value">"/flask"</span> - path: "/flask"
<span class="directive">app_path:</span> <span class="value">"myapp.flask_api:app"</span> app_path: "myapp.flask_api:app"
<span class="directive">app_type:</span> <span class="value">wsgi</span> app_type: wsgi
<span class="directive">name:</span> <span class="value">"flask-app"</span></pre> name: "flask-app"</code></pre>
<div class="note"> <div class="note">
<strong>Note:</strong> WSGI wrapping requires either <code>a2wsgi</code> or <code>asgiref</code> <strong>Note:</strong> WSGI wrapping requires either <code>a2wsgi</code> or <code>asgiref</code>
@ -138,19 +138,19 @@ def hello():
<h3>Mounting Django</h3> <h3>Mounting Django</h3>
<p>Django can be mounted using its ASGI application:</p> <p>Django can be mounted using its ASGI application:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">asgi</span> - type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
- <span class="directive">path:</span> <span class="value">"/django"</span> - path: "/django"
<span class="directive">django_settings:</span> <span class="value">"myproject.settings"</span> django_settings: "myproject.settings"
<span class="directive">module_path:</span> <span class="value">"/path/to/django/project"</span> module_path: "/path/to/django/project"
<span class="directive">name:</span> <span class="value">"django-app"</span></pre> name: "django-app"</code></pre>
<h3>Factory Pattern</h3> <h3>Factory Pattern</h3>
<p>Use factory functions to create apps with custom configuration:</p> <p>Use factory functions to create apps with custom configuration:</p>
<pre><span class="comment"># myapp/api.py</span> <pre><code class="language-python"># myapp/api.py
from fastapi import FastAPI from fastapi import FastAPI
def create_app(debug: bool = False, prefix: str = "/v1") -> FastAPI: def create_app(debug: bool = False, prefix: str = "/v1") -> FastAPI:
@ -160,19 +160,19 @@ def create_app(debug: bool = False, prefix: str = "/v1") -> FastAPI:
async def status(): async def status():
return {"debug": debug} return {"debug": debug}
return app</pre> return app</code></pre>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">asgi</span> - type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
- <span class="directive">path:</span> <span class="value">"/api"</span> - path: "/api"
<span class="directive">app_path:</span> <span class="value">"myapp.api:create_app"</span> app_path: "myapp.api:create_app"
<span class="directive">app_type:</span> <span class="value">asgi</span> app_type: asgi
<span class="directive">factory:</span> <span class="value">true</span> factory: true
<span class="directive">factory_args:</span> factory_args:
<span class="directive">debug:</span> <span class="value">true</span> debug: true
<span class="directive">prefix:</span> <span class="value">"/v2"</span></pre> prefix: "/v2"</code></pre>
<h3>Path Stripping</h3> <h3>Path Stripping</h3>
<p>By default, <code>strip_path: true</code> removes the mount prefix from requests:</p> <p>By default, <code>strip_path: true</code> removes the mount prefix from requests:</p>
@ -198,31 +198,31 @@ def create_app(debug: bool = False, prefix: str = "/v1") -> FastAPI:
<h3>Multiple Mounts</h3> <h3>Multiple Mounts</h3>
<p>Mount multiple applications at different paths:</p> <p>Mount multiple applications at different paths:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">asgi</span> - type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
<span class="comment"># FastAPI for REST API</span> # FastAPI for REST API
- <span class="directive">path:</span> <span class="value">"/api"</span> - path: "/api"
<span class="directive">app_path:</span> <span class="value">"apps.api:app"</span> app_path: "apps.api:app"
<span class="directive">app_type:</span> <span class="value">asgi</span> app_type: asgi
<span class="comment"># Flask admin panel</span> # Flask admin panel
- <span class="directive">path:</span> <span class="value">"/admin"</span> - path: "/admin"
<span class="directive">app_path:</span> <span class="value">"apps.admin:app"</span> app_path: "apps.admin:app"
<span class="directive">app_type:</span> <span class="value">wsgi</span> app_type: wsgi
<span class="comment"># Starlette websocket handler</span> # Starlette websocket handler
- <span class="directive">path:</span> <span class="value">"/ws"</span> - path: "/ws"
<span class="directive">app_path:</span> <span class="value">"apps.websocket:app"</span> app_path: "apps.websocket:app"
<span class="directive">app_type:</span> <span class="value">asgi</span> app_type: asgi
<span class="comment"># Standard routing for static files</span> # Standard routing for static files
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"__default__"</span>: "__default__":
<span class="directive">root:</span> <span class="value">"./static"</span></pre> root: "./static"</code></pre>
<h3>Mount Priority</h3> <h3>Mount Priority</h3>
<p>Mounts are matched by path length (longest first). Given mounts at <p>Mounts are matched by path length (longest first). Given mounts at
@ -236,24 +236,24 @@ def create_app(debug: bool = False, prefix: str = "/v1") -> FastAPI:
<p>ASGI mounts work alongside the routing extension. The <code>asgi</code> extension <p>ASGI mounts work alongside the routing extension. The <code>asgi</code> extension
should be listed before <code>routing</code> to handle mounted paths first:</p> should be listed before <code>routing</code> to handle mounted paths first:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
<span class="comment"># ASGI apps handle /api/* and /admin/*</span> # ASGI apps handle /api/* and /admin/*
- <span class="directive">type:</span> <span class="value">asgi</span> - type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
- <span class="directive">path:</span> <span class="value">"/api"</span> - path: "/api"
<span class="directive">app_path:</span> <span class="value">"myapp:api"</span> app_path: "myapp:api"
<span class="directive">app_type:</span> <span class="value">asgi</span> app_type: asgi
<span class="comment"># Routing handles everything else</span> # Routing handles everything else
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"=/health"</span>: "=/health":
<span class="directive">return:</span> <span class="value">"200 OK"</span> return: "200 OK"
<span class="value">"__default__"</span>: "__default__":
<span class="directive">spa_fallback:</span> <span class="value">true</span> spa_fallback: true
<span class="directive">root:</span> <span class="value">"./dist"</span></pre> root: "./dist"</code></pre>
<h3>Python API</h3> <h3>Python API</h3>
<p>For programmatic mounting, see <a href="../reference/asgi-mount.html">ASGI Mount API Reference</a>.</p> <p>For programmatic mounting, see <a href="../reference/asgi-mount.html">ASGI Mount API Reference</a>.</p>

View File

@ -131,42 +131,42 @@
<p>List of extension modules to load. See <a href="../reference/extensions.html">Extensions Reference</a>.</p> <p>List of extension modules to load. See <a href="../reference/extensions.html">Extensions Reference</a>.</p>
<h3>Complete Example</h3> <h3>Complete Example</h3>
<pre><span class="directive">http:</span> <pre><code class="language-yaml">http:
<span class="directive">static_dir:</span> <span class="value">./static</span> static_dir: ./static
<span class="directive">templates_dir:</span> <span class="value">./templates</span> templates_dir: ./templates
<span class="directive">server:</span> server:
<span class="directive">host:</span> <span class="value">0.0.0.0</span> host: 0.0.0.0
<span class="directive">port:</span> <span class="value">8080</span> port: 8080
<span class="directive">backlog:</span> <span class="value">5</span> backlog: 5
<span class="directive">default_root:</span> <span class="value">false</span> default_root: false
<span class="directive">proxy_timeout:</span> <span class="value">30.0</span> proxy_timeout: 30.0
<span class="directive">ssl:</span> ssl:
<span class="directive">enabled:</span> <span class="value">false</span> enabled: false
<span class="directive">cert_file:</span> <span class="value">./ssl/cert.pem</span> cert_file: ./ssl/cert.pem
<span class="directive">key_file:</span> <span class="value">./ssl/key.pem</span> key_file: ./ssl/key.pem
<span class="directive">logging:</span> logging:
<span class="directive">level:</span> <span class="value">INFO</span> level: INFO
<span class="directive">console_output:</span> <span class="value">true</span> console_output: true
<span class="directive">format:</span> format:
<span class="directive">type:</span> <span class="value">standard</span> type: standard
<span class="directive">use_colors:</span> <span class="value">true</span> use_colors: true
<span class="directive">timestamp_format:</span> <span class="value">"%Y-%m-%d %H:%M:%S"</span> timestamp_format: "%Y-%m-%d %H:%M:%S"
<span class="directive">files:</span> files:
- <span class="directive">path:</span> <span class="value">./logs/pyserve.log</span> - path: ./logs/pyserve.log
<span class="directive">level:</span> <span class="value">DEBUG</span> level: DEBUG
<span class="directive">max_bytes:</span> <span class="value">10485760</span> max_bytes: 10485760
<span class="directive">backup_count:</span> <span class="value">5</span> backup_count: 5
<span class="directive">extensions:</span> extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"__default__"</span>: "__default__":
<span class="directive">root:</span> <span class="value">"./static"</span> root: "./static"
<span class="directive">index_file:</span> <span class="value">"index.html"</span></pre> index_file: "index.html"</code></pre>
<div class="warning"> <div class="warning">
<strong>Warning:</strong> When running in production, always use SSL <strong>Warning:</strong> When running in production, always use SSL

View File

@ -41,7 +41,7 @@
</ul> </ul>
<h3>Architecture</h3> <h3>Architecture</h3>
<pre> <pre><code class="language-bash">
PyServe Gateway (:8000) PyServe Gateway (:8000)
┌────────────────┼────────────────┐ ┌────────────────┼────────────────┐
@ -49,25 +49,25 @@
FastAPI Flask Starlette FastAPI Flask Starlette
:9001 :9002 :9003 :9001 :9002 :9003
/api/* /admin/* /ws/* /api/* /admin/* /ws/*
</pre> </code></pre>
<p>PyServe acts as a gateway, routing requests to the appropriate subprocess based on URL path.</p> <p>PyServe acts as a gateway, routing requests to the appropriate subprocess based on URL path.</p>
<h3>Basic Configuration</h3> <h3>Basic Configuration</h3>
<pre><span class="directive">server:</span> <pre><code class="language-yaml">server:
<span class="directive">host:</span> <span class="value">0.0.0.0</span> host: 0.0.0.0
<span class="directive">port:</span> <span class="value">8000</span> port: 8000
<span class="directive">extensions:</span> extensions:
- <span class="directive">type:</span> <span class="value">process_orchestration</span> - type: process_orchestration
<span class="directive">config:</span> config:
<span class="directive">apps:</span> apps:
- <span class="directive">name:</span> <span class="value">api</span> - name: api
<span class="directive">path:</span> <span class="value">/api</span> path: /api
<span class="directive">app_path:</span> <span class="value">myapp.api:app</span> app_path: myapp.api:app
- <span class="directive">name:</span> <span class="value">admin</span> - name: admin
<span class="directive">path:</span> <span class="value">/admin</span> path: /admin
<span class="directive">app_path:</span> <span class="value">myapp.admin:app</span></pre> app_path: myapp.admin:app</code></pre>
<h3>App Configuration Options</h3> <h3>App Configuration Options</h3>
<dl> <dl>
@ -130,18 +130,18 @@
</dl> </dl>
<h3>Global Configuration</h3> <h3>Global Configuration</h3>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">process_orchestration</span> - type: process_orchestration
<span class="directive">config:</span> config:
<span class="directive">port_range:</span> <span class="value">[9000, 9999]</span> port_range: [9000, 9999]
<span class="directive">health_check_enabled:</span> <span class="value">true</span> health_check_enabled: true
<span class="directive">proxy_timeout:</span> <span class="value">60.0</span> proxy_timeout: 60.0
<span class="directive">logging:</span> logging:
<span class="directive">httpx_level:</span> <span class="value">warning</span> httpx_level: warning
<span class="directive">proxy_logs:</span> <span class="value">true</span> proxy_logs: true
<span class="directive">health_check_logs:</span> <span class="value">false</span> health_check_logs: false
<span class="directive">apps:</span> apps:
<span class="comment"># ...</span></pre> # ...</code></pre>
<dl> <dl>
<dt>port_range</dt> <dt>port_range</dt>
@ -161,7 +161,7 @@
</dl> </dl>
<h3>FastAPI Example</h3> <h3>FastAPI Example</h3>
<pre><span class="comment"># myapp/api.py</span> <pre><code class="language-python"># myapp/api.py
from fastapi import FastAPI from fastapi import FastAPI
app = FastAPI() app = FastAPI()
@ -172,22 +172,22 @@ async def health():
@app.get("/users") @app.get("/users")
async def get_users(): async def get_users():
return [{"id": 1, "name": "Alice"}]</pre> return [{"id": 1, "name": "Alice"}]</code></pre>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">process_orchestration</span> - type: process_orchestration
<span class="directive">config:</span> config:
<span class="directive">apps:</span> apps:
- <span class="directive">name:</span> <span class="value">api</span> - name: api
<span class="directive">path:</span> <span class="value">/api</span> path: /api
<span class="directive">app_path:</span> <span class="value">myapp.api:app</span> app_path: myapp.api:app
<span class="directive">workers:</span> <span class="value">4</span> workers: 4
<span class="directive">health_check_path:</span> <span class="value">/health</span></pre> health_check_path: /health</code></pre>
<p>Requests to <code>/api/users</code> are proxied to the FastAPI process as <code>/users</code>.</p> <p>Requests to <code>/api/users</code> are proxied to the FastAPI process as <code>/users</code>.</p>
<h3>Flask Example (WSGI)</h3> <h3>Flask Example (WSGI)</h3>
<pre><span class="comment"># myapp/admin.py</span> <pre><code class="language-python"># myapp/admin.py
from flask import Flask from flask import Flask
app = Flask(__name__) app = Flask(__name__)
@ -198,17 +198,17 @@ def health():
@app.route("/dashboard") @app.route("/dashboard")
def dashboard(): def dashboard():
return {"page": "dashboard"}</pre> return {"page": "dashboard"}</code></pre>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">process_orchestration</span> - type: process_orchestration
<span class="directive">config:</span> config:
<span class="directive">apps:</span> apps:
- <span class="directive">name:</span> <span class="value">admin</span> - name: admin
<span class="directive">path:</span> <span class="value">/admin</span> path: /admin
<span class="directive">app_path:</span> <span class="value">myapp.admin:app</span> app_path: myapp.admin:app
<span class="directive">app_type:</span> <span class="value">wsgi</span> app_type: wsgi
<span class="directive">workers:</span> <span class="value">2</span></pre> workers: 2</code></pre>
<div class="note"> <div class="note">
<strong>Note:</strong> WSGI support requires <code>a2wsgi</code> package: <strong>Note:</strong> WSGI support requires <code>a2wsgi</code> package:
@ -216,7 +216,7 @@ def dashboard():
</div> </div>
<h3>Factory Pattern</h3> <h3>Factory Pattern</h3>
<pre><span class="comment"># myapp/api.py</span> <pre><code class="language-python"># myapp/api.py
from fastapi import FastAPI from fastapi import FastAPI
def create_app(debug: bool = False) -> FastAPI: def create_app(debug: bool = False) -> FastAPI:
@ -226,49 +226,49 @@ def create_app(debug: bool = False) -> FastAPI:
async def health(): async def health():
return {"status": "ok", "debug": debug} return {"status": "ok", "debug": debug}
return app</pre> return app</code></pre>
<pre><span class="directive">apps:</span> <pre><code class="language-bash">apps:
- <span class="directive">name:</span> <span class="value">api</span> - name: api
<span class="directive">path:</span> <span class="value">/api</span> path: /api
<span class="directive">app_path:</span> <span class="value">myapp.api:create_app</span> app_path: myapp.api:create_app
<span class="directive">factory:</span> <span class="value">true</span></pre> factory: true</code></pre>
<h3>Environment Variables</h3> <h3>Environment Variables</h3>
<p>Pass environment variables to subprocesses:</p> <p>Pass environment variables to subprocesses:</p>
<pre><span class="directive">apps:</span> <pre><code class="language-bash">apps:
- <span class="directive">name:</span> <span class="value">api</span> - name: api
<span class="directive">path:</span> <span class="value">/api</span> path: /api
<span class="directive">app_path:</span> <span class="value">myapp.api:app</span> app_path: myapp.api:app
<span class="directive">env:</span> env:
<span class="directive">DATABASE_URL:</span> <span class="value">"postgresql://localhost/mydb"</span> DATABASE_URL: "postgresql://localhost/mydb"
<span class="directive">REDIS_URL:</span> <span class="value">"redis://localhost:6379"</span> REDIS_URL: "redis://localhost:6379"
<span class="directive">DEBUG:</span> <span class="value">"false"</span></pre> DEBUG: "false"</code></pre>
<h3>Multiple Applications</h3> <h3>Multiple Applications</h3>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">process_orchestration</span> - type: process_orchestration
<span class="directive">config:</span> config:
<span class="directive">port_range:</span> <span class="value">[9000, 9999]</span> port_range: [9000, 9999]
<span class="directive">apps:</span> apps:
<span class="comment"># FastAPI REST API</span> # FastAPI REST API
- <span class="directive">name:</span> <span class="value">api</span> - name: api
<span class="directive">path:</span> <span class="value">/api</span> path: /api
<span class="directive">app_path:</span> <span class="value">apps.api:app</span> app_path: apps.api:app
<span class="directive">workers:</span> <span class="value">4</span> workers: 4
<span class="comment"># Flask Admin Panel</span> # Flask Admin Panel
- <span class="directive">name:</span> <span class="value">admin</span> - name: admin
<span class="directive">path:</span> <span class="value">/admin</span> path: /admin
<span class="directive">app_path:</span> <span class="value">apps.admin:app</span> app_path: apps.admin:app
<span class="directive">app_type:</span> <span class="value">wsgi</span> app_type: wsgi
<span class="directive">workers:</span> <span class="value">2</span> workers: 2
<span class="comment"># Starlette WebSocket Handler</span> # Starlette WebSocket Handler
- <span class="directive">name:</span> <span class="value">websocket</span> - name: websocket
<span class="directive">path:</span> <span class="value">/ws</span> path: /ws
<span class="directive">app_path:</span> <span class="value">apps.websocket:app</span> app_path: apps.websocket:app
<span class="directive">workers:</span> <span class="value">1</span></pre> workers: 1</code></pre>
<h3>Request Tracing</h3> <h3>Request Tracing</h3>
<p>PyServe automatically generates and propagates <code>X-Request-ID</code> headers:</p> <p>PyServe automatically generates and propagates <code>X-Request-ID</code> headers:</p>

View File

@ -28,12 +28,12 @@
<h3>Basic Proxy Configuration</h3> <h3>Basic Proxy Configuration</h3>
<p>Use the <code>proxy_pass</code> directive in routing:</p> <p>Use the <code>proxy_pass</code> directive in routing:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"~^/api/"</span>: "~^/api/":
<span class="directive">proxy_pass:</span> <span class="value">"http://localhost:9001"</span></pre> proxy_pass: "http://localhost:9001"</code></pre>
<p>All requests to <code>/api/*</code> will be forwarded to <code>http://localhost:9001/api/*</code>.</p> <p>All requests to <code>/api/*</code> will be forwarded to <code>http://localhost:9001/api/*</code>.</p>
@ -62,21 +62,21 @@
<h3>Custom Headers</h3> <h3>Custom Headers</h3>
<p>Add custom headers to proxied requests:</p> <p>Add custom headers to proxied requests:</p>
<pre><span class="value">"~^/api/"</span>: <pre><code class="language-bash">"~^/api/":
<span class="directive">proxy_pass:</span> <span class="value">"http://localhost:9001"</span> proxy_pass: "http://localhost:9001"
<span class="directive">headers:</span> headers:
- <span class="value">"X-Custom-Header: my-value"</span> - "X-Custom-Header: my-value"
- <span class="value">"Authorization: Bearer token123"</span></pre> - "Authorization: Bearer token123"</code></pre>
<h3>Dynamic Headers with Captures</h3> <h3>Dynamic Headers with Captures</h3>
<p>Use regex capture groups to build dynamic headers:</p> <p>Use regex capture groups to build dynamic headers:</p>
<pre><span class="value">"~^/api/v(?P&lt;version&gt;\\d+)/(?P&lt;service&gt;\\w+)"</span>: <pre><code class="language-bash">"~^/api/v(?P&lt;version&gt;\\d+)/(?P&lt;service&gt;\\w+)":
<span class="directive">proxy_pass:</span> <span class="value">"http://localhost:9001"</span> proxy_pass: "http://localhost:9001"
<span class="directive">headers:</span> headers:
- <span class="value">"X-API-Version: {version}"</span> - "X-API-Version: {version}"
- <span class="value">"X-Service: {service}"</span> - "X-Service: {service}"
- <span class="value">"X-Client-IP: $remote_addr"</span></pre> - "X-Client-IP: $remote_addr"</code></pre>
<p>Special variables:</p> <p>Special variables:</p>
<ul class="indent"> <ul class="indent">
@ -87,49 +87,49 @@
<h3>Proxy Timeout</h3> <h3>Proxy Timeout</h3>
<p>Configure timeout for proxy requests:</p> <p>Configure timeout for proxy requests:</p>
<pre><span class="comment"># Global default timeout</span> <pre><code class="language-yaml"># Global default timeout
<span class="directive">server:</span> server:
<span class="directive">proxy_timeout:</span> <span class="value">30.0</span> proxy_timeout: 30.0
<span class="comment"># Per-route timeout</span> # Per-route timeout
<span class="directive">extensions:</span> extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"~^/api/slow"</span>: "~^/api/slow":
<span class="directive">proxy_pass:</span> <span class="value">"http://localhost:9001"</span> proxy_pass: "http://localhost:9001"
<span class="directive">timeout:</span> <span class="value">120</span> <span class="comment"># 2 minutes for slow endpoints</span></pre> timeout: 120 # 2 minutes for slow endpoints</code></pre>
<h3>URL Rewriting</h3> <h3>URL Rewriting</h3>
<p>The proxy preserves the original request path by default:</p> <p>The proxy preserves the original request path by default:</p>
<pre><span class="comment"># Request: GET /api/users/123</span> <pre><code class="language-bash"># Request: GET /api/users/123
<span class="comment"># Proxied: GET http://backend:9001/api/users/123</span> # Proxied: GET http://backend:9001/api/users/123
<span class="value">"~^/api/"</span>: "~^/api/":
<span class="directive">proxy_pass:</span> <span class="value">"http://backend:9001"</span></pre> proxy_pass: "http://backend:9001"</code></pre>
<p>To proxy to a specific path:</p> <p>To proxy to a specific path:</p>
<pre><span class="comment"># Request: GET /api/users/123</span> <pre><code class="language-bash"># Request: GET /api/users/123
<span class="comment"># Proxied: GET http://backend:9001/v2/users/123 (path preserved)</span> # Proxied: GET http://backend:9001/v2/users/123 (path preserved)
<span class="value">"~^/api/"</span>: "~^/api/":
<span class="directive">proxy_pass:</span> <span class="value">"http://backend:9001/v2"</span></pre> proxy_pass: "http://backend:9001/v2"</code></pre>
<h3>Load Balancing Example</h3> <h3>Load Balancing Example</h3>
<p>Route different services to different backends:</p> <p>Route different services to different backends:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"~^/api/users"</span>: "~^/api/users":
<span class="directive">proxy_pass:</span> <span class="value">"http://user-service:8001"</span> proxy_pass: "http://user-service:8001"
<span class="value">"~^/api/orders"</span>: "~^/api/orders":
<span class="directive">proxy_pass:</span> <span class="value">"http://order-service:8002"</span> proxy_pass: "http://order-service:8002"
<span class="value">"~^/api/products"</span>: "~^/api/products":
<span class="directive">proxy_pass:</span> <span class="value">"http://product-service:8003"</span></pre> proxy_pass: "http://product-service:8003"</code></pre>
<h3>Error Handling</h3> <h3>Error Handling</h3>
<p>pyserve returns appropriate error codes for proxy failures:</p> <p>pyserve returns appropriate error codes for proxy failures:</p>

View File

@ -62,29 +62,29 @@
<h3>Routing Configuration</h3> <h3>Routing Configuration</h3>
<p>Routing is configured via the <code>routing</code> extension:</p> <p>Routing is configured via the <code>routing</code> extension:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="comment"># Exact match for health check</span> # Exact match for health check
<span class="value">"=/health"</span>: "=/health":
<span class="directive">return:</span> <span class="value">"200 OK"</span> return: "200 OK"
<span class="directive">content_type:</span> <span class="value">"text/plain"</span> content_type: "text/plain"
<span class="comment"># Static files with caching</span> # Static files with caching
<span class="value">"~*\\.(js|css|png|jpg|gif|ico)$"</span>: "~*\\.(js|css|png|jpg|gif|ico)$":
<span class="directive">root:</span> <span class="value">"./static"</span> root: "./static"
<span class="directive">cache_control:</span> <span class="value">"public, max-age=31536000"</span> cache_control: "public, max-age=31536000"
<span class="comment"># HTML files without caching</span> # HTML files without caching
<span class="value">"~*\\.html$"</span>: "~*\\.html$":
<span class="directive">root:</span> <span class="value">"./static"</span> root: "./static"
<span class="directive">cache_control:</span> <span class="value">"no-cache"</span> cache_control: "no-cache"
<span class="comment"># Default fallback</span> # Default fallback
<span class="value">"__default__"</span>: "__default__":
<span class="directive">root:</span> <span class="value">"./static"</span> root: "./static"
<span class="directive">index_file:</span> <span class="value">"index.html"</span></pre> index_file: "index.html"</code></pre>
<h3>Location Directives</h3> <h3>Location Directives</h3>
@ -120,11 +120,11 @@
<h3>Named Capture Groups</h3> <h3>Named Capture Groups</h3>
<p>Regex locations support named capture groups that can be used in headers and proxy URLs:</p> <p>Regex locations support named capture groups that can be used in headers and proxy URLs:</p>
<pre><span class="value">"~^/api/v(?P&lt;version&gt;\\d+)/(?P&lt;resource&gt;\\w+)"</span>: <pre><code class="language-bash">"~^/api/v(?P&lt;version&gt;\\d+)/(?P&lt;resource&gt;\\w+)":
<span class="directive">proxy_pass:</span> <span class="value">"http://backend:9001"</span> proxy_pass: "http://backend:9001"
<span class="directive">headers:</span> headers:
- <span class="value">"X-API-Version: {version}"</span> - "X-API-Version: {version}"
- <span class="value">"X-Resource: {resource}"</span></pre> - "X-Resource: {resource}"</code></pre>
<p>Request to <code>/api/v2/users</code> will have headers:</p> <p>Request to <code>/api/v2/users</code> will have headers:</p>
<ul class="indent"> <ul class="indent">
@ -135,14 +135,14 @@
<h3>SPA Configuration</h3> <h3>SPA Configuration</h3>
<p>For Single Page Applications, use <code>spa_fallback</code> with <code>exclude_patterns</code>:</p> <p>For Single Page Applications, use <code>spa_fallback</code> with <code>exclude_patterns</code>:</p>
<pre><span class="value">"__default__"</span>: <pre><code class="language-python">"__default__":
<span class="directive">spa_fallback:</span> <span class="value">true</span> spa_fallback: true
<span class="directive">root:</span> <span class="value">"./dist"</span> root: "./dist"
<span class="directive">index_file:</span> <span class="value">"index.html"</span> index_file: "index.html"
<span class="directive">exclude_patterns:</span> exclude_patterns:
- <span class="value">"/api/"</span> - "/api/"
- <span class="value">"/assets/"</span> - "/assets/"
- <span class="value">"/static/"</span></pre> - "/static/"</code></pre>
<p>This will:</p> <p>This will:</p>
<ul class="indent"> <ul class="indent">
@ -153,11 +153,11 @@
<h3>Static File Serving</h3> <h3>Static File Serving</h3>
<p>Basic static file configuration:</p> <p>Basic static file configuration:</p>
<pre><span class="value">"~*\\.(css|js|png|jpg|gif|svg|woff2?)$"</span>: <pre><code class="language-bash">"~*\\.(css|js|png|jpg|gif|svg|woff2?)$":
<span class="directive">root:</span> <span class="value">"./static"</span> root: "./static"
<span class="directive">cache_control:</span> <span class="value">"public, max-age=86400"</span> cache_control: "public, max-age=86400"
<span class="directive">headers:</span> headers:
- <span class="value">"X-Content-Type-Options: nosniff"</span></pre> - "X-Content-Type-Options: nosniff"</code></pre>
<div class="note"> <div class="note">
<strong>Note:</strong> pyserve automatically detects MIME types based on file extensions. <strong>Note:</strong> pyserve automatically detects MIME types based on file extensions.

View File

@ -31,18 +31,18 @@
<h4>ASGIAppLoader</h4> <h4>ASGIAppLoader</h4>
<p>Loads and manages ASGI/WSGI applications from Python import paths.</p> <p>Loads and manages ASGI/WSGI applications from Python import paths.</p>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> ASGIAppLoader <pre><code class="language-python">from pyserve import ASGIAppLoader
loader = ASGIAppLoader() loader = ASGIAppLoader()
<span class="comment"># Load an ASGI app</span> # Load an ASGI app
app = loader.load_app( app = loader.load_app(
app_path=<span class="value">"mymodule:app"</span>, app_path="mymodule:app",
app_type=<span class="value">"asgi"</span>, app_type="asgi",
module_path=<span class="value">"/path/to/project"</span>, module_path="/path/to/project",
factory=<span class="value">False</span>, factory=False,
factory_args=<span class="value">None</span> factory_args=None
)</pre> )</code></pre>
<h5>Methods</h5> <h5>Methods</h5>
<dl> <dl>
@ -69,14 +69,14 @@ app = loader.load_app(
<h4>MountedApp</h4> <h4>MountedApp</h4>
<p>Represents an application mounted at a specific path.</p> <p>Represents an application mounted at a specific path.</p>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> MountedApp <pre><code class="language-python">from pyserve import MountedApp
mount = MountedApp( mount = MountedApp(
path=<span class="value">"/api"</span>, path="/api",
app=my_asgi_app, app=my_asgi_app,
name=<span class="value">"my-api"</span>, name="my-api",
strip_path=<span class="value">True</span> strip_path=True
)</pre> )</code></pre>
<h5>Attributes</h5> <h5>Attributes</h5>
<dl> <dl>
@ -105,19 +105,19 @@ mount = MountedApp(
<h4>ASGIMountManager</h4> <h4>ASGIMountManager</h4>
<p>Manages multiple mounted applications and routes requests.</p> <p>Manages multiple mounted applications and routes requests.</p>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> ASGIMountManager <pre><code class="language-python">from pyserve import ASGIMountManager
manager = ASGIMountManager() manager = ASGIMountManager()
<span class="comment"># Mount using app instance</span> # Mount using app instance
manager.mount(path=<span class="value">"/api"</span>, app=my_app) manager.mount(path="/api", app=my_app)
<span class="comment"># Mount using import path</span> # Mount using import path
manager.mount( manager.mount(
path=<span class="value">"/flask"</span>, path="/flask",
app_path=<span class="value">"myapp:flask_app"</span>, app_path="myapp:flask_app",
app_type=<span class="value">"wsgi"</span> app_type="wsgi"
)</pre> )</code></pre>
<h5>Methods</h5> <h5>Methods</h5>
<dl> <dl>
@ -150,80 +150,80 @@ manager.mount(
<p>Convenience functions for loading specific framework applications:</p> <p>Convenience functions for loading specific framework applications:</p>
<h4>create_fastapi_app()</h4> <h4>create_fastapi_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_fastapi_app <pre><code class="language-python">from pyserve import create_fastapi_app
app = create_fastapi_app( app = create_fastapi_app(
app_path=<span class="value">"myapp.api:app"</span>, app_path="myapp.api:app",
module_path=<span class="value">None</span>, module_path=None,
factory=<span class="value">False</span>, factory=False,
factory_args=<span class="value">None</span> factory_args=None
)</pre> )</code></pre>
<h4>create_flask_app()</h4> <h4>create_flask_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_flask_app <pre><code class="language-python">from pyserve import create_flask_app
app = create_flask_app( app = create_flask_app(
app_path=<span class="value">"myapp.web:app"</span>, app_path="myapp.web:app",
module_path=<span class="value">None</span>, module_path=None,
factory=<span class="value">False</span>, factory=False,
factory_args=<span class="value">None</span> factory_args=None
)</pre> )</code></pre>
<p>Automatically wraps the WSGI app for ASGI compatibility.</p> <p>Automatically wraps the WSGI app for ASGI compatibility.</p>
<h4>create_django_app()</h4> <h4>create_django_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_django_app <pre><code class="language-python">from pyserve import create_django_app
app = create_django_app( app = create_django_app(
settings_module=<span class="value">"myproject.settings"</span>, settings_module="myproject.settings",
module_path=<span class="value">"/path/to/project"</span> module_path="/path/to/project"
)</pre> )</code></pre>
<p>Sets <code>DJANGO_SETTINGS_MODULE</code> and returns Django's ASGI application.</p> <p>Sets <code>DJANGO_SETTINGS_MODULE</code> and returns Django's ASGI application.</p>
<h4>create_starlette_app()</h4> <h4>create_starlette_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_starlette_app <pre><code class="language-python">from pyserve import create_starlette_app
app = create_starlette_app( app = create_starlette_app(
app_path=<span class="value">"myapp:starlette_app"</span>, app_path="myapp:starlette_app",
module_path=<span class="value">None</span>, module_path=None,
factory=<span class="value">False</span>, factory=False,
factory_args=<span class="value">None</span> factory_args=None
)</pre> )</code></pre>
<h3>Usage Example</h3> <h3>Usage Example</h3>
<p>Complete example mounting multiple applications:</p> <p>Complete example mounting multiple applications:</p>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> ( <pre><code class="language-python">from pyserve import (
PyServeServer, PyServeServer,
ASGIMountManager, ASGIMountManager,
create_fastapi_app, create_fastapi_app,
create_flask_app create_flask_app
) )
<span class="comment"># Create mount manager</span> # Create mount manager
mounts = ASGIMountManager() mounts = ASGIMountManager()
<span class="comment"># Mount FastAPI</span> # Mount FastAPI
api_app = create_fastapi_app(<span class="value">"myapp.api:app"</span>) api_app = create_fastapi_app("myapp.api:app")
<span class="keyword">if</span> api_app: if api_app:
mounts.mount(<span class="value">"/api"</span>, app=api_app, name=<span class="value">"api"</span>) mounts.mount("/api", app=api_app, name="api")
<span class="comment"># Mount Flask</span> # Mount Flask
admin_app = create_flask_app(<span class="value">"myapp.admin:app"</span>) admin_app = create_flask_app("myapp.admin:app")
<span class="keyword">if</span> admin_app: if admin_app:
mounts.mount(<span class="value">"/admin"</span>, app=admin_app, name=<span class="value">"admin"</span>) mounts.mount("/admin", app=admin_app, name="admin")
<span class="comment"># List mounts</span> # List mounts
<span class="keyword">for</span> mount <span class="keyword">in</span> mounts.list_mounts(): for mount in mounts.list_mounts():
print(f<span class="value">"Mounted {mount['name']} at {mount['path']}"</span>)</pre> print(f"Mounted {mount['name']} at {mount['path']}")</code></pre>
<h3>Error Handling</h3> <h3>Error Handling</h3>
<p>All loader functions return <code>None</code> on failure and log errors. <p>All loader functions return <code>None</code> on failure and log errors.
Check the return value before using:</p> Check the return value before using:</p>
<pre>app = create_fastapi_app(<span class="value">"nonexistent:app"</span>) <pre><code class="language-bash">app = create_fastapi_app("nonexistent:app")
<span class="keyword">if</span> app <span class="keyword">is None</span>: if app is None:
<span class="comment"># Handle error - check logs for details</span> # Handle error - check logs for details
print(<span class="value">"Failed to load application"</span>)</pre> print("Failed to load application")</code></pre>
<h3>WSGI Compatibility</h3> <h3>WSGI Compatibility</h3>
<p>For WSGI applications, pyserve uses adapters in this priority:</p> <p>For WSGI applications, pyserve uses adapters in this priority:</p>
@ -233,9 +233,9 @@ admin_app = create_flask_app(<span class="value">"myapp.admin:app"</span>)
</ol> </ol>
<p>Install an adapter:</p> <p>Install an adapter:</p>
<pre>pip install a2wsgi <span class="comment"># recommended</span> <pre><code class="language-bash">pip install a2wsgi # recommended
<span class="comment"># or</span> # or
pip install asgiref</pre> pip install asgiref</code></pre>
<div class="note"> <div class="note">
<strong>See Also:</strong> <strong>See Also:</strong>

View File

@ -26,7 +26,7 @@
<p>pyserve provides a command-line interface for server management.</p> <p>pyserve provides a command-line interface for server management.</p>
<h3>Synopsis</h3> <h3>Synopsis</h3>
<pre>pyserve [OPTIONS]</pre> <pre><code class="language-bash">pyserve [OPTIONS]</code></pre>
<h3>Options</h3> <h3>Options</h3>
@ -66,20 +66,20 @@
<h3>Examples</h3> <h3>Examples</h3>
<p><strong>Start with default configuration:</strong></p> <p><strong>Start with default configuration:</strong></p>
<pre>pyserve</pre> <pre><code class="language-bash">pyserve</code></pre>
<p><strong>Start with custom config file:</strong></p> <p><strong>Start with custom config file:</strong></p>
<pre>pyserve -c /path/to/config.yaml</pre> <pre><code class="language-bash">pyserve -c /path/to/config.yaml</code></pre>
<p><strong>Override host and port:</strong></p> <p><strong>Override host and port:</strong></p>
<pre>pyserve --host 127.0.0.1 --port 9000</pre> <pre><code class="language-bash">pyserve --host 127.0.0.1 --port 9000</code></pre>
<p><strong>Enable debug mode:</strong></p> <p><strong>Enable debug mode:</strong></p>
<pre>pyserve --debug</pre> <pre><code class="language-bash">pyserve --debug</code></pre>
<p><strong>Show version:</strong></p> <p><strong>Show version:</strong></p>
<pre>pyserve --version <pre><code class="language-bash">pyserve --version
<span class="comment"># Output: pyserve 0.7.0</span></pre> # Output: pyserve 0.7.0</code></pre>
<h3>Configuration Priority</h3> <h3>Configuration Priority</h3>
<p>Settings are applied in the following order (later overrides earlier):</p> <p>Settings are applied in the following order (later overrides earlier):</p>
@ -125,15 +125,15 @@
<h3>Development Commands (Makefile)</h3> <h3>Development Commands (Makefile)</h3>
<p>When working with the source repository, use make commands:</p> <p>When working with the source repository, use make commands:</p>
<pre>make run <span class="comment"># Start in development mode</span> <pre><code class="language-bash">make run # Start in development mode
make run-prod <span class="comment"># Start in production mode</span> make run-prod # Start in production mode
make test <span class="comment"># Run tests</span> make test # Run tests
make test-cov <span class="comment"># Tests with coverage</span> make test-cov # Tests with coverage
make lint <span class="comment"># Check code with linters</span> make lint # Check code with linters
make format <span class="comment"># Format code</span> make format # Format code
make build <span class="comment"># Build wheel package</span> make build # Build wheel package
make clean <span class="comment"># Clean temporary files</span> make clean # Clean temporary files
make help <span class="comment"># Show all commands</span></pre> make help # Show all commands</code></pre>
</div> </div>
<div id="footer"> <div id="footer">

View File

@ -58,27 +58,27 @@
<h3>Extension Configuration</h3> <h3>Extension Configuration</h3>
<p>Extensions are configured in the <code>extensions</code> section:</p> <p>Extensions are configured in the <code>extensions</code> section:</p>
<pre><span class="directive">extensions:</span> <pre><code class="language-yaml">extensions:
- <span class="directive">type:</span> <span class="value">routing</span> - type: routing
<span class="directive">config:</span> config:
<span class="comment"># extension-specific configuration</span> # extension-specific configuration
- <span class="directive">type:</span> <span class="value">security</span> - type: security
<span class="directive">config:</span> config:
<span class="comment"># ...</span></pre> # ...</code></pre>
<h3>Routing Extension</h3> <h3>Routing Extension</h3>
<p>The primary extension for URL routing. See <a href="../guides/routing.html">Routing Guide</a> for full documentation.</p> <p>The primary extension for URL routing. See <a href="../guides/routing.html">Routing Guide</a> for full documentation.</p>
<pre><span class="directive">- type:</span> <span class="value">routing</span> <pre><code class="language-python">- type: routing
<span class="directive">config:</span> config:
<span class="directive">regex_locations:</span> regex_locations:
<span class="value">"=/health"</span>: "=/health":
<span class="directive">return:</span> <span class="value">"200 OK"</span> return: "200 OK"
<span class="value">"~^/api/"</span>: "~^/api/":
<span class="directive">proxy_pass:</span> <span class="value">"http://backend:9001"</span> proxy_pass: "http://backend:9001"
<span class="value">"__default__"</span>: "__default__":
<span class="directive">root:</span> <span class="value">"./static"</span></pre> root: "./static"</code></pre>
<h3>Security Extension</h3> <h3>Security Extension</h3>
<p>Adds security headers and IP-based access control.</p> <p>Adds security headers and IP-based access control.</p>
@ -95,16 +95,16 @@
<dd>List of blocked IP addresses (blacklist mode)</dd> <dd>List of blocked IP addresses (blacklist mode)</dd>
</dl> </dl>
<pre><span class="directive">- type:</span> <span class="value">security</span> <pre><code class="language-bash">- type: security
<span class="directive">config:</span> config:
<span class="directive">security_headers:</span> security_headers:
<span class="directive">X-Frame-Options:</span> <span class="value">DENY</span> X-Frame-Options: DENY
<span class="directive">X-Content-Type-Options:</span> <span class="value">nosniff</span> X-Content-Type-Options: nosniff
<span class="directive">X-XSS-Protection:</span> <span class="value">"1; mode=block"</span> X-XSS-Protection: "1; mode=block"
<span class="directive">Strict-Transport-Security:</span> <span class="value">"max-age=31536000"</span> Strict-Transport-Security: "max-age=31536000"
<span class="directive">blocked_ips:</span> blocked_ips:
- <span class="value">"192.168.1.100"</span> - "192.168.1.100"
- <span class="value">"10.0.0.50"</span></pre> - "10.0.0.50"</code></pre>
<p>Default security headers if not specified:</p> <p>Default security headers if not specified:</p>
<ul class="indent"> <ul class="indent">
@ -125,11 +125,11 @@
<dd>Default cache TTL in seconds. Default: <code>3600</code></dd> <dd>Default cache TTL in seconds. Default: <code>3600</code></dd>
</dl> </dl>
<pre><span class="directive">- type:</span> <span class="value">caching</span> <pre><code class="language-bash">- type: caching
<span class="directive">config:</span> config:
<span class="directive">cache_ttl:</span> <span class="value">3600</span> cache_ttl: 3600
<span class="directive">cache_patterns:</span> cache_patterns:
- <span class="value">"/api/public/*"</span></pre> - "/api/public/*"</code></pre>
<h3>Monitoring Extension</h3> <h3>Monitoring Extension</h3>
<p>Collects request metrics and provides statistics.</p> <p>Collects request metrics and provides statistics.</p>
@ -140,9 +140,9 @@
<dd>Enable metrics collection. Default: <code>true</code></dd> <dd>Enable metrics collection. Default: <code>true</code></dd>
</dl> </dl>
<pre><span class="directive">- type:</span> <span class="value">monitoring</span> <pre><code class="language-bash">- type: monitoring
<span class="directive">config:</span> config:
<span class="directive">enable_metrics:</span> <span class="value">true</span></pre> enable_metrics: true</code></pre>
<p>Collected metrics (available at <code>/metrics</code>):</p> <p>Collected metrics (available at <code>/metrics</code>):</p>
<ul class="indent"> <ul class="indent">
@ -220,28 +220,28 @@
<dd>Django settings module (for Django apps only)</dd> <dd>Django settings module (for Django apps only)</dd>
</dl> </dl>
<pre><span class="directive">- type:</span> <span class="value">asgi</span> <pre><code class="language-bash">- type: asgi
<span class="directive">config:</span> config:
<span class="directive">mounts:</span> mounts:
<span class="comment"># FastAPI application</span> # FastAPI application
- <span class="directive">path:</span> <span class="value">"/api"</span> - path: "/api"
<span class="directive">app_path:</span> <span class="value">"myapp.api:app"</span> app_path: "myapp.api:app"
<span class="directive">app_type:</span> <span class="value">asgi</span> app_type: asgi
<span class="directive">name:</span> <span class="value">"api"</span> name: "api"
<span class="comment"># Flask application (WSGI)</span> # Flask application (WSGI)
- <span class="directive">path:</span> <span class="value">"/admin"</span> - path: "/admin"
<span class="directive">app_path:</span> <span class="value">"myapp.admin:app"</span> app_path: "myapp.admin:app"
<span class="directive">app_type:</span> <span class="value">wsgi</span> app_type: wsgi
<span class="directive">name:</span> <span class="value">"admin"</span> name: "admin"
<span class="comment"># Factory pattern with arguments</span> # Factory pattern with arguments
- <span class="directive">path:</span> <span class="value">"/api/v2"</span> - path: "/api/v2"
<span class="directive">app_path:</span> <span class="value">"myapp.api:create_app"</span> app_path: "myapp.api:create_app"
<span class="directive">factory:</span> <span class="value">true</span> factory: true
<span class="directive">factory_args:</span> factory_args:
<span class="directive">debug:</span> <span class="value">true</span> debug: true
<span class="directive">version:</span> <span class="value">"2.0"</span></pre> version: "2.0"</code></pre>
<p>Supported frameworks:</p> <p>Supported frameworks:</p>
<ul class="indent"> <ul class="indent">
@ -271,27 +271,27 @@
<li>Request tracing with X-Request-ID</li> <li>Request tracing with X-Request-ID</li>
</ul> </ul>
<pre><span class="directive">- type:</span> <span class="value">process_orchestration</span> <pre><code class="language-yaml">- type: process_orchestration
<span class="directive">config:</span> config:
<span class="directive">port_range:</span> <span class="value">[9000, 9999]</span> port_range: [9000, 9999]
<span class="directive">health_check_enabled:</span> <span class="value">true</span> health_check_enabled: true
<span class="directive">proxy_timeout:</span> <span class="value">60.0</span> proxy_timeout: 60.0
<span class="directive">logging:</span> logging:
<span class="directive">httpx_level:</span> <span class="value">warning</span> httpx_level: warning
<span class="directive">proxy_logs:</span> <span class="value">true</span> proxy_logs: true
<span class="directive">health_check_logs:</span> <span class="value">false</span> health_check_logs: false
<span class="directive">apps:</span> apps:
- <span class="directive">name:</span> <span class="value">api</span> - name: api
<span class="directive">path:</span> <span class="value">/api</span> path: /api
<span class="directive">app_path:</span> <span class="value">myapp.api:app</span> app_path: myapp.api:app
<span class="directive">workers:</span> <span class="value">4</span> workers: 4
<span class="directive">health_check_path:</span> <span class="value">/health</span> health_check_path: /health
- <span class="directive">name:</span> <span class="value">admin</span> - name: admin
<span class="directive">path:</span> <span class="value">/admin</span> path: /admin
<span class="directive">app_path:</span> <span class="value">myapp.admin:app</span> app_path: myapp.admin:app
<span class="directive">app_type:</span> <span class="value">wsgi</span> app_type: wsgi
<span class="directive">workers:</span> <span class="value">2</span></pre> workers: 2</code></pre>
<h4>App Configuration</h4> <h4>App Configuration</h4>
<dl> <dl>

View File

@ -221,21 +221,6 @@ dd {
text-align: center; text-align: center;
} }
/* Syntax highlighting for config examples */
.directive {
color: #5fba7d;
font-weight: bold;
}
.value {
color: #87ceeb;
}
.comment {
color: #666;
font-style: italic;
}
/* Main wrapper for two-column layout */ /* Main wrapper for two-column layout */
#main-wrapper { #main-wrapper {
display: flex; display: flex;