Summary
Any markdown page whose URL starts with /api/ (e.g. docs/api/usage.md → /api/usage) returns 404 when loaded directly or refreshed in the browser.
Reproduction
- Create
docs/api/usage.md in an rw serve project.
- Navigate to the page via the sidebar — it loads (SPA client-side routing, no server hit).
- Refresh the browser, or paste
http://localhost:7979/api/usage into a new tab.
- Server returns 404 Not Found.
Root cause
crates/rw-server/src/static_files.rs:37 excludes any path starting with api/ from the SPA fallback:
let is_spa_route = !path.starts_with("api/") && !path.contains('.');
The intent was to avoid serving index.html for unmatched API calls, but the check is too broad — it also blocks legitimate doc pages under /api/*.
Request flow for /api/usage:
- Router does not match
/api/config, /api/navigation, /api/pages/..., or /api/comments.
- Falls through to
static_files::serve_asset.
path.starts_with("api/") is true → is_spa_route = false → 404.
Suggested fixes
Two options:
- Tighten the fallback check — only skip SPA fallback for the actual API prefixes (
api/config, api/navigation, api/pages/, api/comments). Smallest change; keeps the /api/* URL contract.
- Move API under a reserved prefix — e.g.
/_api/* or /__rw/api/*. Eliminates the collision entirely but changes the public API surface (frontend client, tests, any external callers of /api/comments).
Option 1 is lower-risk; option 2 is cleaner long-term.
Related code
crates/rw-server/src/app.rs:22-35 — route registrations
crates/rw-server/src/static_files.rs:37 — fallback check
Summary
Any markdown page whose URL starts with
/api/(e.g.docs/api/usage.md→/api/usage) returns 404 when loaded directly or refreshed in the browser.Reproduction
docs/api/usage.mdin anrw serveproject.http://localhost:7979/api/usageinto a new tab.Root cause
crates/rw-server/src/static_files.rs:37excludes any path starting withapi/from the SPA fallback:The intent was to avoid serving
index.htmlfor unmatched API calls, but the check is too broad — it also blocks legitimate doc pages under/api/*.Request flow for
/api/usage:/api/config,/api/navigation,/api/pages/..., or/api/comments.static_files::serve_asset.path.starts_with("api/")is true →is_spa_route = false→ 404.Suggested fixes
Two options:
api/config,api/navigation,api/pages/,api/comments). Smallest change; keeps the/api/*URL contract./_api/*or/__rw/api/*. Eliminates the collision entirely but changes the public API surface (frontend client, tests, any external callers of/api/comments).Option 1 is lower-risk; option 2 is cleaner long-term.
Related code
crates/rw-server/src/app.rs:22-35— route registrationscrates/rw-server/src/static_files.rs:37— fallback check