Skip to content

Update router documentation for new URL API#6371

Open
masenf wants to merge 9 commits intomainfrom
claude/document-router-url-87UPj
Open

Update router documentation for new URL API#6371
masenf wants to merge 9 commits intomainfrom
claude/document-router-url-87UPj

Conversation

@masenf
Copy link
Copy Markdown
Collaborator

@masenf masenf commented Apr 23, 2026

Type of change

  • This change requires a documentation update

Description

This PR updates the documentation to reflect changes in the router API. The changes document the transition from the deprecated router.page namespace to the new router.url API and router.route_id attribute.

Key documentation updates:

  1. Updated router attributes examples in docs/utility_methods/router_attributes.md:

    • Replaced deprecated router.page.* attributes with new router.url.* components
    • Added examples for router.url.scheme, router.url.netloc, router.url.origin, router.url.query, router.url.query_parameters, and router.url.fragment
    • Added router.route_id example
  2. Added comprehensive URL Attributes section documenting:

    • The structure and purpose of router.url as a parsed URL object
    • All available URL component attributes with descriptions
    • A detailed example table showing URL parsing for a concrete request
    • Best practices for reading query parameters using query_parameters
    • Reference to dynamic route handling
  3. Added migration guide from deprecated router.page to new API:

    • Mapping table showing old attributes and their replacements
    • Notes explaining behavioral differences (e.g., query_parameters is now a frozen mapping)
  4. Updated overview documentation in docs/pages/overview.md:

    • Changed code examples to use router.route_id instead of router.page.path
    • Changed code examples to use router.url.path instead of router.page.raw_path
    • Updated explanations to reference the new API
    • Simplified full URL access to use router.url directly

Fixes #5664

Test Plan

N/A - Documentation only changes

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh

Document the router.url attribute (a parsed URL object exposing scheme,
netloc, origin, path, query, query_parameters, and fragment) and
router.route_id. Add a migration table mapping each deprecated
router.page.* attribute to its router.url replacement. Update the
"Getting the Current Page" example in pages/overview.md to use the new
API.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 23, 2026

Greptile Summary

This PR migrates the router documentation from the deprecated router.page.* API to the new router.url (a str-subclass parsed URL object) and router.route_id, and backs the change with a new Var implementation (ReflexURLCastedVar) that serializes ReflexURL as a component dict so the frontend can access individual URL fields. The code changes are well-tested and the eager serializer bypass for the str-subclass is correctly handled and documented.

Confidence Score: 5/5

Safe to merge; only finding is a minor documentation gap in the migration guide.

All remaining findings are P2 documentation suggestions. The implementation is solid, the serializer bypass is correctly handled, VarData propagation is explicitly tested, and both test fixture files are consistently updated.

docs/utility_methods/router_attributes.md — migration note for raw_path omits fragment.

Important Files Changed

Filename Overview
reflex/istate/data.py Adds ReflexURLVar/ReflexURLCastedVar Var wrappers and an eager _serialize_reflex_url serializer; the bypass of the generic serializer for the str-subclass ReflexURL is correctly handled and well-commented.
tests/units/istate/test_data.py New test file covering URL parsing, serialization round-trip through json_dumps, Var type registration, VarData propagation, JS expression rendering, and query_parameters ObjectVar typing — comprehensive coverage.
docs/utility_methods/router_attributes.md Replaces deprecated router.page.* examples with router.url.* and adds URL Attributes + migration guide sections; migration note for raw_path omits the fragment component.
docs/pages/overview.md Updates code examples to use router.route_id and router.url.path/router.url in place of deprecated router.page.* attributes — accurate and well-worded.
tests/units/test_state.py Updates formatted_router fixture to reflect url now serializing as a component dict instead of a plain string.
tests/units/utils/test_format.py Same formatted_router fixture update as test_state.py — consistent and correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Frontend URL in browser\nhttps://example.com:3000/posts/123?tab=comments#top"] -->|"WebSocket router payload"| B["RouterData.from_router_data()"]
    B --> C["ReflexURL (str subclass)\nstores full URL + parsed attrs"]
    C -->|"_serialize_reflex_url() called eagerly\n(bypasses json.dumps str-subclass shortcut)"| D["Serialized dict\n{href, scheme, netloc, origin,\npath, query, query_parameters, fragment}"]
    D -->|"State sync to frontend"| E["JS state object\nreflex_state.router.url"]
    E -->|"ReflexURLCastedVar._cached_var_name"| F["router.url → url?.['href']\n(full URL string)"]
    E -->|"_component('scheme').to(str)"| G["router.url.scheme → url?.['scheme']"]
    E -->|"_component('query_parameters')\n.to(ObjectVar, Mapping[str,str])"| H["router.url.query_parameters\n→ url?.['query_parameters']"]
Loading

Reviews (2): Last reviewed commit: "fix(state): explicitly serialize ReflexU..." | Re-trigger Greptile

Comment thread docs/utility_methods/router_attributes.md Outdated
The previous wording claimed the fragment is "usually empty" because
browsers do not send it over HTTP. That is wrong for Reflex: the client
template builds asPath as pathname + search + hash and ships it over
the WebSocket, so router.url.fragment does reflect the current URL bar.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 23, 2026

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing claude/document-router-url-87UPj (18b5578) with main (76ff38c)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Accessing rx.State.router.url.scheme (and the other parsed URL
components) previously raised VarAttributeError because ReflexURL is a
str subclass, so guess_type mapped it to StringVar, which rejects
arbitrary attribute lookup.

Introduce ReflexURLVar, a StringVar subclass that exposes each URL
component (scheme/netloc/origin/path/query/query_parameters/fragment/
href) as a typed child Var via __getattr__. The companion
ReflexURLCastedVar overrides the rendered JS expression so the Var
itself resolves to the href property at compile time, meaning
rx.text(self.router.url) renders the full URL string while
self.router.url.scheme, .path, etc. resolve to the corresponding keys
on the serialized object.

Add a dict serializer for ReflexURL so the frontend receives
{scheme, netloc, origin, path, query, query_parameters, fragment, href}
under router.url. Drop the now-unnecessary .to_string() call in the
docs sample table since the Var already renders as a URL string.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
Comment thread tests/units/istate/test_data.py Outdated
Comment thread tests/units/istate/test_data.py
Comment thread reflex/istate/data.py Outdated
Comment thread reflex/istate/data.py Outdated
Address review: replace the __getattr__ dispatch + component-type dict
with one @Property per URL component on ReflexURLCastedVar, each
annotated with the correct Var return type. This gives static typing
for self.router.url.scheme / .path / .query_parameters / etc. and
removes the dead __getattr__ on ReflexURLVar (all instances flow
through ReflexURLCastedVar).

Also tighten the regression tests: drop the unnecessary local _State
class in favor of rx.State directly, and assert on both the emitted
JS expression and the returned Var's _var_type so future regressions
on the component typing are caught.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
@masenf masenf requested review from a team and Alek99 as code owners April 23, 2026 23:31
Comment thread reflex/istate/data.py Outdated
Address review: move .guess_type() out of _component and have each
property narrow the raw ObjectItemOperation with .to(str) or
.to(ObjectVar, Mapping[str, str]) instead. The .to() overloads carry
accurate static return types, so StringVar / ObjectVar annotations
type-check without any pyright: ignore[reportReturnType] suppressions.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
Comment thread reflex/istate/data.py Outdated
Address review: ReflexURL has no .href attribute in Python, so exposing
one as a Var property creates a Var-only API that doesn't exist at
runtime. Drop the property. The serialized payload still carries an
href key because _cached_var_name needs it to render the top-level Var
as the URL string in JS, but that's an internal implementation detail
and is not exposed on the Python API.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
Comment thread tests/units/istate/test_data.py
claude added 2 commits April 24, 2026 00:22
Address review: add coverage for the VarData propagation path. The
casted Var and every child component Var must carry the state-context
imports and hook from the underlying router state-var access,
otherwise using self.router.url.scheme in a component would silently
drop the state subscription at compile time.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
ReflexURL is a str subclass, so json.dumps handles it natively and
never invokes the default=serialize hook registered by the framework.
This meant the enclosing RouterData serializer handed the raw
ReflexURL to json.dumps, which short-circuited it to a plain URL
string instead of the {scheme, netloc, ..., href} component dict the
frontend expects for router.url.<component> access.

Serialize the url field eagerly inside serialize_router_data so the
component dict makes it through to the frontend. Add a regression
test that goes through the real json_dumps path (not just serialize)
to catch this short-circuit in the future, and update the fixture
formatted_router in test_state.py and test_format.py to match the
new payload shape.

https://claude.ai/code/session_01GTk6Ni7kyfd8VQKtq7JAXh
@masenf
Copy link
Copy Markdown
Collaborator Author

masenf commented Apr 24, 2026

@greptile-apps re-review

@adhami3310 adhami3310 added the documentation Improvements or additions to documentation label Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ReflexURL.path cannot be accessed as Var

3 participants