docs.pyserve.org/guides/routing.html
Илья Глазунов 1f25033d2d initial commit
2025-12-05 12:57:41 +03:00

170 lines
7.1 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">
</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">pyserve</a> » <a href="/guides/">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><span class="directive">extensions:</span>
- <span class="directive">type:</span> <span class="value">routing</span>
<span class="directive">config:</span>
<span class="directive">regex_locations:</span>
<span class="comment"># Exact match for health check</span>
<span class="value">"=/health"</span>:
<span class="directive">return:</span> <span class="value">"200 OK"</span>
<span class="directive">content_type:</span> <span class="value">"text/plain"</span>
<span class="comment"># Static files with caching</span>
<span class="value">"~*\\.(js|css|png|jpg|gif|ico)$"</span>:
<span class="directive">root:</span> <span class="value">"./static"</span>
<span class="directive">cache_control:</span> <span class="value">"public, max-age=31536000"</span>
<span class="comment"># HTML files without caching</span>
<span class="value">"~*\\.html$"</span>:
<span class="directive">root:</span> <span class="value">"./static"</span>
<span class="directive">cache_control:</span> <span class="value">"no-cache"</span>
<span class="comment"># Default fallback</span>
<span class="value">"__default__"</span>:
<span class="directive">root:</span> <span class="value">"./static"</span>
<span class="directive">index_file:</span> <span class="value">"index.html"</span></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><span class="value">"~^/api/v(?P&lt;version&gt;\\d+)/(?P&lt;resource&gt;\\w+)"</span>:
<span class="directive">proxy_pass:</span> <span class="value">"http://backend:9001"</span>
<span class="directive">headers:</span>
- <span class="value">"X-API-Version: {version}"</span>
- <span class="value">"X-Resource: {resource}"</span></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><span class="value">"__default__"</span>:
<span class="directive">spa_fallback:</span> <span class="value">true</span>
<span class="directive">root:</span> <span class="value">"./dist"</span>
<span class="directive">index_file:</span> <span class="value">"index.html"</span>
<span class="directive">exclude_patterns:</span>
- <span class="value">"/api/"</span>
- <span class="value">"/assets/"</span>
- <span class="value">"/static/"</span></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><span class="value">"~*\\.(css|js|png|jpg|gif|svg|woff2?)$"</span>:
<span class="directive">root:</span> <span class="value">"./static"</span>
<span class="directive">cache_control:</span> <span class="value">"public, max-age=86400"</span>
<span class="directive">headers:</span>
- <span class="value">"X-Content-Type-Options: nosniff"</span></pre>
<div class="note">
<strong>Note:</strong> pyserve automatically detects MIME types based on file extensions.
</div>
</div>
<div id="footer">
<p>pyserve &copy; 2024-2025 | MIT License</p>
</div>
</div>
</body>
</html>