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

252 lines
9.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ASGI Mount API - 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="/reference/">Reference</a> » ASGI Mount API
</div>
<div id="content">
<h2>ASGI Mount API Reference</h2>
<p>The <code>pyserve.asgi_mount</code> module provides a Python API for mounting
ASGI and WSGI applications programmatically.</p>
<h3>Classes</h3>
<h4>ASGIAppLoader</h4>
<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
loader = ASGIAppLoader()
<span class="comment"># Load an ASGI app</span>
app = loader.load_app(
app_path=<span class="value">"mymodule:app"</span>,
app_type=<span class="value">"asgi"</span>,
module_path=<span class="value">"/path/to/project"</span>,
factory=<span class="value">False</span>,
factory_args=<span class="value">None</span>
)</pre>
<h5>Methods</h5>
<dl>
<dt>load_app(app_path, app_type="asgi", module_path=None, factory=False, factory_args=None)</dt>
<dd>
Load an application from an import path.
<ul class="indent">
<li><code>app_path</code>: Import path in format <code>module:attribute</code></li>
<li><code>app_type</code>: <code>"asgi"</code> or <code>"wsgi"</code></li>
<li><code>module_path</code>: Optional path to add to <code>sys.path</code></li>
<li><code>factory</code>: If True, call the attribute as a factory function</li>
<li><code>factory_args</code>: Dict of arguments for factory function</li>
</ul>
Returns the loaded ASGI application or <code>None</code> on error.
</dd>
<dt>get_app(app_path)</dt>
<dd>Get a previously loaded application by its path.</dd>
<dt>reload_app(app_path, **kwargs)</dt>
<dd>Reload an application, useful for development hot-reloading.</dd>
</dl>
<h4>MountedApp</h4>
<p>Represents an application mounted at a specific path.</p>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> MountedApp
mount = MountedApp(
path=<span class="value">"/api"</span>,
app=my_asgi_app,
name=<span class="value">"my-api"</span>,
strip_path=<span class="value">True</span>
)</pre>
<h5>Attributes</h5>
<dl>
<dt>path: str</dt>
<dd>The mount path (without trailing slash).</dd>
<dt>app: ASGIApp</dt>
<dd>The ASGI application.</dd>
<dt>name: str</dt>
<dd>Friendly name for logging.</dd>
<dt>strip_path: bool</dt>
<dd>Whether to strip the mount path from requests.</dd>
</dl>
<h5>Methods</h5>
<dl>
<dt>matches(request_path) → bool</dt>
<dd>Check if a request path matches this mount.</dd>
<dt>get_modified_path(original_path) → str</dt>
<dd>Get the modified path after stripping mount prefix.</dd>
</dl>
<h4>ASGIMountManager</h4>
<p>Manages multiple mounted applications and routes requests.</p>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> ASGIMountManager
manager = ASGIMountManager()
<span class="comment"># Mount using app instance</span>
manager.mount(path=<span class="value">"/api"</span>, app=my_app)
<span class="comment"># Mount using import path</span>
manager.mount(
path=<span class="value">"/flask"</span>,
app_path=<span class="value">"myapp:flask_app"</span>,
app_type=<span class="value">"wsgi"</span>
)</pre>
<h5>Methods</h5>
<dl>
<dt>mount(path, app=None, app_path=None, app_type="asgi", module_path=None, factory=False, factory_args=None, name="", strip_path=True) → bool</dt>
<dd>
Mount an application at a path. Either <code>app</code> or <code>app_path</code> must be provided.
Returns <code>True</code> on success.
</dd>
<dt>unmount(path) → bool</dt>
<dd>Remove a mounted application. Returns <code>True</code> if found and removed.</dd>
<dt>get_mount(request_path) → Optional[MountedApp]</dt>
<dd>Get the mount that matches a request path.</dd>
<dt>handle_request(scope, receive, send) → bool</dt>
<dd>Handle an ASGI request. Returns <code>True</code> if handled by a mounted app.</dd>
<dt>list_mounts() → List[Dict]</dt>
<dd>Get a list of all mounts with their configuration.</dd>
</dl>
<h5>Properties</h5>
<dl>
<dt>mounts: List[MountedApp]</dt>
<dd>Copy of the current mounts list (sorted by path length, longest first).</dd>
</dl>
<h3>Helper Functions</h3>
<p>Convenience functions for loading specific framework applications:</p>
<h4>create_fastapi_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_fastapi_app
app = create_fastapi_app(
app_path=<span class="value">"myapp.api:app"</span>,
module_path=<span class="value">None</span>,
factory=<span class="value">False</span>,
factory_args=<span class="value">None</span>
)</pre>
<h4>create_flask_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_flask_app
app = create_flask_app(
app_path=<span class="value">"myapp.web:app"</span>,
module_path=<span class="value">None</span>,
factory=<span class="value">False</span>,
factory_args=<span class="value">None</span>
)</pre>
<p>Automatically wraps the WSGI app for ASGI compatibility.</p>
<h4>create_django_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_django_app
app = create_django_app(
settings_module=<span class="value">"myproject.settings"</span>,
module_path=<span class="value">"/path/to/project"</span>
)</pre>
<p>Sets <code>DJANGO_SETTINGS_MODULE</code> and returns Django's ASGI application.</p>
<h4>create_starlette_app()</h4>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> create_starlette_app
app = create_starlette_app(
app_path=<span class="value">"myapp:starlette_app"</span>,
module_path=<span class="value">None</span>,
factory=<span class="value">False</span>,
factory_args=<span class="value">None</span>
)</pre>
<h3>Usage Example</h3>
<p>Complete example mounting multiple applications:</p>
<pre><span class="keyword">from</span> pyserve <span class="keyword">import</span> (
PyServeServer,
ASGIMountManager,
create_fastapi_app,
create_flask_app
)
<span class="comment"># Create mount manager</span>
mounts = ASGIMountManager()
<span class="comment"># Mount FastAPI</span>
api_app = create_fastapi_app(<span class="value">"myapp.api:app"</span>)
<span class="keyword">if</span> api_app:
mounts.mount(<span class="value">"/api"</span>, app=api_app, name=<span class="value">"api"</span>)
<span class="comment"># Mount Flask</span>
admin_app = create_flask_app(<span class="value">"myapp.admin:app"</span>)
<span class="keyword">if</span> admin_app:
mounts.mount(<span class="value">"/admin"</span>, app=admin_app, name=<span class="value">"admin"</span>)
<span class="comment"># List mounts</span>
<span class="keyword">for</span> mount <span class="keyword">in</span> mounts.list_mounts():
print(f<span class="value">"Mounted {mount['name']} at {mount['path']}"</span>)</pre>
<h3>Error Handling</h3>
<p>All loader functions return <code>None</code> on failure and log errors.
Check the return value before using:</p>
<pre>app = create_fastapi_app(<span class="value">"nonexistent:app"</span>)
<span class="keyword">if</span> app <span class="keyword">is None</span>:
<span class="comment"># Handle error - check logs for details</span>
print(<span class="value">"Failed to load application"</span>)</pre>
<h3>WSGI Compatibility</h3>
<p>For WSGI applications, pyserve uses adapters in this priority:</p>
<ol class="indent">
<li><code>a2wsgi.WSGIMiddleware</code> (recommended)</li>
<li><code>asgiref.wsgi.WsgiToAsgi</code> (fallback)</li>
</ol>
<p>Install an adapter:</p>
<pre>pip install a2wsgi <span class="comment"># recommended</span>
<span class="comment"># or</span>
pip install asgiref</pre>
<div class="note">
<strong>See Also:</strong>
<ul class="indent">
<li><a href="../guides/asgi-mount.html">ASGI Mounting Guide</a> — Configuration-based mounting</li>
<li><a href="extensions.html">Extensions</a> — ASGI extension configuration</li>
</ul>
</div>
</div>
<div id="footer">
<p>pyserve &copy; 2024-2025 | MIT License</p>
</div>
</div>
</body>
</html>