Skip to content

Add support for wildcard route handling - #8588

Merged
philippjfr merged 15 commits into
mainfrom
wildcard_routes
May 15, 2026
Merged

philippjfr merged 15 commits into
mainfrom
wildcard_routes

Conversation

@philippjfr

@philippjfr philippjfr commented May 14, 2026

Copy link
Copy Markdown
Member

Description

This PR adds first-class dynamic route support across both server implementations and makes route context available inside apps in a backend-consistent way.

Users can now serve apps on dynamic routes and reliably read:

  • pn.state.route_params for captured path variables
  • pn.state.app_url as the concrete matched app path for the current session (not new)

It also improves route matching behavior for wildcard routes, ensures websocket/session flows preserve route context, and updates docs to present path-template syntax as the primary recommended style.

Supported route syntax

  • Path-template syntax (recommended, cross-backend):

    • /user/{name}
    • /files/{filepath:path}
  • Regex syntax (Tornado):

    • /user/([^/]+)
    • /org/(?P<org>[^/]+)/user/(?P<user>[^/]+)

For Tornado, path templates are normalized to Tornado-compatible patterns.
For FastAPI, path templates are passed through naturally and now preserve route metadata in session state.

Behavior improvements included

  • Wildcard/dynamic routes no longer interfere with core app endpoints (/ws, /metadata, /autoload.js).
  • Root index no longer auto-redirects to an invalid wildcard-only route.
  • Session creation and websocket-first flows both carry route metadata so app state is consistent regardless of connection path.
  • Server docs now include a dedicated wildcard routes how-to and backend compatibility guidance.

Examples

Tornado

import panel as pn
pn.extension()

def app():
    return {
        "route_params": pn.state.route_params,
        "app_url": pn.state.app_url,
    }

pn.serve({"/user/{name}": app}, show=False)
# /user/alice -> {"route_params": {"name": "alice"}, "app_url": "/user/alice"}

FastAPI

import panel as pn
from panel.io.fastapi import serve
pn.extension()

def app():
    return {
        "route_params": pn.state.route_params,
        "app_url": pn.state.app_url,
    }

serve({"/files/{filepath:path}": app}, show=False)
# /files/a/b/c.txt -> {"route_params": {"filepath": "a/b/c.txt"}, "app_url": "/files/a/b/c.txt"}

AI Disclosure

  • Tool & Model: Cursor + Codex 5.3 / GPT 5.5

  • Usage: Used to investigate routing internals, implement dynamic route support across Tornado/FastAPI, add tests, and update documentation.

  • I have tested all AI-generated content in my PR.

  • I take responsibility for all AI-generated content in my PR.

Checklist

  • Tests added and are passing
  • Added documentation

@codecov

codecov Bot commented May 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.71484% with 43 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.76%. Comparing base (15a5f18) to head (594ea2a).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
panel/io/server.py 90.84% 14 Missing ⚠️
panel/io/fastapi.py 88.17% 11 Missing ⚠️
panel/io/state.py 61.90% 8 Missing ⚠️
panel/io/application.py 84.61% 4 Missing ⚠️
panel/tests/test_server.py 98.15% 4 Missing ⚠️
panel/io/threads.py 77.77% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #8588       +/-   ##
===========================================
+ Coverage   69.59%   85.76%   +16.17%     
===========================================
  Files         349      350        +1     
  Lines       56327    56820      +493     
===========================================
+ Hits        39201    48732     +9531     
+ Misses      17126     8088     -9038     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds backend-consistent dynamic/wildcard route support across the Tornado (Bokeh server) and FastAPI server implementations, making matched route context available inside apps via session state.

Changes:

  • Introduces pn.state.route_params and updates pn.state.app_url to reflect the concrete matched app path (including dynamic segments).
  • Normalizes FastAPI-style path templates to Tornado regex routes and propagates route context through HTTP, autoload, and websocket/session flows.
  • Adds server tests for route context and updates server documentation index to include a wildcard routes guide.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
panel/tests/test_server.py Adds regression + behavior tests for wildcard root handling and route_params / app_url across backends.
panel/io/state.py Exposes route_params on state and makes app_url prefer concrete app_path from the session token payload.
panel/io/server.py Adds path-template → Tornado regex normalization and injects route context into request handling and websocket token refresh.
panel/io/fastapi.py Hooks FastAPI session/websocket flows to preserve route context in the token payload used by Panel/Bokeh.
panel/io/application.py Ensures base_url/rel_path derive from the concrete app_path and passes route context through process_request.
doc/how_to/server/index.md Adds navigation entry for wildcard routes documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread panel/io/server.py

@hoxbro hoxbro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only reviewed the code, not tested the functionality.

Comment thread panel/io/fastapi.py Outdated
Comment thread panel/io/server.py
Comment thread panel/io/server.py Outdated
Comment thread panel/io/server.py Outdated
Comment thread panel/io/server.py
Comment thread doc/how_to/server/wildcard_routes.md Outdated
Comment thread panel/io/application.py Outdated
Comment thread panel/io/fastapi.py
Comment thread panel/io/fastapi.py Outdated
@philippjfr
philippjfr enabled auto-merge (squash) May 15, 2026 13:30
@philippjfr
philippjfr disabled auto-merge May 15, 2026 13:35
@philippjfr
philippjfr merged commit 8489abc into main May 15, 2026
18 of 19 checks passed
@philippjfr
philippjfr deleted the wildcard_routes branch May 15, 2026 13:35
@github-actions

Copy link
Copy Markdown

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Aug 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants