Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Support Base URL / Starlette Prefix #530

Open
2 tasks done
vanpelt opened this issue Oct 17, 2024 · 1 comment
Open
2 tasks done

[FEATURE] Support Base URL / Starlette Prefix #530

vanpelt opened this issue Oct 17, 2024 · 1 comment
Labels
enhancement New feature or request

Comments

@vanpelt
Copy link

vanpelt commented Oct 17, 2024

Is your feature request related to a problem? Please describe.

I want to run FastHTML application's within my existing web app under a dynamic url prefix. For example: https://apps.aihype.com/username/appname.

Describe the solution you'd like

Streamlit let's you configure --server.baseUrlPath=/username/appname when starting an app. It will be trickier with FastHTML as both the backend and the frontend need to know about this, but I think it can be done with a settings / environment variable.

Example code

I was able to get this mostly working by manually wrapping the app in a custom entrypoint and adding some headers to the generated HTML:

Wrapper

os.environ["BASE_PREFIX"] = prefix
if prefix:
    print("Prefix detected, wrapping app...")
    orig_entrypoint = os.path.basename(entrypoint)
    with open("prefixed_app.py", "w") as f:
        f.write(f"""from starlette.applications import Starlette
from starlette.routing import Mount
from {orig_entrypoint.replace('.py', '')} import app as orig_app, serve

routes = [Mount("{prefix}", orig_app)]
app = Starlette(routes=routes)

serve(reload=False)""")

App

headers = (...)
if os.getenv("BASE_PREFIX"):
    prefix = os.getenv("BASE_PREFIX")
    headers = (
        Base(
            href=prefix
        ),
        Script(
            f"""document.addEventListener('DOMContentLoaded', () => {{
    document.body.addEventListener('htmx:configRequest', (event) => {{
        event.detail.path = `{prefix}${{event.detail.path}}`
    }})
}});
""")
    ) + headers
... = fast_app("rad.db", hdrs=headers, ...)

Similar implementations

  1. Streamlit - See baseUrlPath in the Server section

Problem solved

This would allow users to host multiple apps on a single domain behind an authenticated proxy. It also enables 3rd parties to support hosting fasthtml apps within their existing platforms.

Additional context

I imagine my initial approach doesn't catch all cases. For instance I noticed when live=True the websocket is not getting re-routed when I mounted the existing Starlette app. The <base href tag should take care of any vanilla links that are relative. HTMX doesn't respect that tag so I added the configRequest hook. If users incorporate their own weird routing or custom JS it might be nice to expose something on the window object so they could use it... It's a bit of a rabbit hole but making the simple case work still seems worth it.

Confirmation

Please confirm the following:

  • I have checked the existing issues and pull requests to ensure this feature hasn't been requested before.
  • I have read the project's documentation to ensure this feature doesn't already exist.
@vanpelt vanpelt added the enhancement New feature or request label Oct 17, 2024
@vanpelt
Copy link
Author

vanpelt commented Oct 17, 2024

Just thought of another detail. This setting should also alter the session cookie path by default. 🐰 🕳️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant