173 lines
6.0 KiB
HTML
173 lines
6.0 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Routing - 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">Guides</a> / Routing
|
|
</div>
|
|
|
|
<div id="content">
|
|
<h2>Routing</h2>
|
|
|
|
<p>pyserve supports nginx-style routing patterns including exact matches,
|
|
regex locations, and SPA fallback.</p>
|
|
|
|
<h3>Location Types</h3>
|
|
|
|
<table class="dirindex">
|
|
<tr>
|
|
<td><code>=</code></td>
|
|
<td>Exact match</td>
|
|
<td class="desc"><code>=/health</code> matches only <code>/health</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>~</code></td>
|
|
<td>Case-sensitive regex</td>
|
|
<td class="desc"><code>~^/api/v\d+/</code> matches <code>/api/v1/</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>~*</code></td>
|
|
<td>Case-insensitive regex</td>
|
|
<td class="desc"><code>~*\.(js|css)$</code> matches <code>.JS</code> and <code>.css</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>__default__</code></td>
|
|
<td>Default fallback</td>
|
|
<td class="desc">Matches when no other route matches</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Match Priority</h3>
|
|
<p>Routes are processed in the following order:</p>
|
|
<ol class="indent">
|
|
<li><strong>Exact matches</strong> (<code>=</code>) — checked first</li>
|
|
<li><strong>Regex patterns</strong> (<code>~</code> and <code>~*</code>) — in definition order</li>
|
|
<li><strong>Default fallback</strong> (<code>__default__</code>) — last resort</li>
|
|
</ol>
|
|
|
|
<h3>Routing Configuration</h3>
|
|
<p>Routing is configured via the <code>routing</code> extension:</p>
|
|
|
|
<pre><code class="language-yaml">extensions:
|
|
- type: routing
|
|
config:
|
|
regex_locations:
|
|
# Exact match for health check
|
|
"=/health":
|
|
return: "200 OK"
|
|
content_type: "text/plain"
|
|
|
|
# Static files with caching
|
|
"~*\\.(js|css|png|jpg|gif|ico)$":
|
|
root: "./static"
|
|
cache_control: "public, max-age=31536000"
|
|
|
|
# HTML files without caching
|
|
"~*\\.html$":
|
|
root: "./static"
|
|
cache_control: "no-cache"
|
|
|
|
# Default fallback
|
|
"__default__":
|
|
root: "./static"
|
|
index_file: "index.html"</code></pre>
|
|
|
|
<h3>Location Directives</h3>
|
|
|
|
<dl>
|
|
<dt>root</dt>
|
|
<dd>Base directory for serving files.</dd>
|
|
|
|
<dt>index_file</dt>
|
|
<dd>Index file name for directory requests. Default: <code>index.html</code></dd>
|
|
|
|
<dt>proxy_pass</dt>
|
|
<dd>Upstream server URL for reverse proxy. See <a href="reverse-proxy.html">Reverse Proxy</a>.</dd>
|
|
|
|
<dt>return</dt>
|
|
<dd>Return a fixed response. Format: <code>"status message"</code> or <code>"status"</code></dd>
|
|
|
|
<dt>content_type</dt>
|
|
<dd>Response content type for <code>return</code> directive.</dd>
|
|
|
|
<dt>cache_control</dt>
|
|
<dd>Cache-Control header value.</dd>
|
|
|
|
<dt>headers</dt>
|
|
<dd>List of additional headers to add. Format: <code>"Header-Name: value"</code></dd>
|
|
|
|
<dt>spa_fallback</dt>
|
|
<dd>Enable SPA mode — serve index file for all routes.</dd>
|
|
|
|
<dt>exclude_patterns</dt>
|
|
<dd>URL patterns to exclude from SPA fallback.</dd>
|
|
</dl>
|
|
|
|
<h3>Named Capture Groups</h3>
|
|
<p>Regex locations support named capture groups that can be used in headers and proxy URLs:</p>
|
|
|
|
<pre><code class="language-bash">"~^/api/v(?P<version>\\d+)/(?P<resource>\\w+)":
|
|
proxy_pass: "http://backend:9001"
|
|
headers:
|
|
- "X-API-Version: {version}"
|
|
- "X-Resource: {resource}"</code></pre>
|
|
|
|
<p>Request to <code>/api/v2/users</code> will have headers:</p>
|
|
<ul class="indent">
|
|
<li><code>X-API-Version: 2</code></li>
|
|
<li><code>X-Resource: users</code></li>
|
|
</ul>
|
|
|
|
<h3>SPA Configuration</h3>
|
|
<p>For Single Page Applications, use <code>spa_fallback</code> with <code>exclude_patterns</code>:</p>
|
|
|
|
<pre><code class="language-python">"__default__":
|
|
spa_fallback: true
|
|
root: "./dist"
|
|
index_file: "index.html"
|
|
exclude_patterns:
|
|
- "/api/"
|
|
- "/assets/"
|
|
- "/static/"</code></pre>
|
|
|
|
<p>This will:</p>
|
|
<ul class="indent">
|
|
<li>Serve <code>index.html</code> for routes like <code>/about</code>, <code>/users/123</code></li>
|
|
<li>Return 404 for <code>/api/*</code>, <code>/assets/*</code>, <code>/static/*</code> if file not found</li>
|
|
</ul>
|
|
|
|
<h3>Static File Serving</h3>
|
|
<p>Basic static file configuration:</p>
|
|
|
|
<pre><code class="language-bash">"~*\\.(css|js|png|jpg|gif|svg|woff2?)$":
|
|
root: "./static"
|
|
cache_control: "public, max-age=86400"
|
|
headers:
|
|
- "X-Content-Type-Options: nosniff"</code></pre>
|
|
|
|
<div class="note">
|
|
<strong>Note:</strong> pyserve automatically detects MIME types based on file extensions.
|
|
</div>
|
|
</div>
|
|
|
|
<div id="footer">
|
|
<p>pyserve © 2024-2025 | MIT License</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|