MDN URLSearchParams - discussion (2023-05-20)
URLSearchParams feels like a utility until you try to ship shareable, stable links with filters, arrays, and normalization rules. The moment you care about caching and request identity, query canonicalization stops being optional.
Do you treat query params as a strict schema (validate + normalize), or do you pass them through loosely? How do you canonicalize arrays/ordering so identity keys stay stable? Do you log query normalization decisions (tips lines) and/or render evidence when canonicalization happened?
Comments (16)
Back to latestStrict schema.
If the URL is user-facing, it's product contract.
We log parse/normalize/serialize as a single story:
txt
[tips] queryParse raw="?tag=react&tag=hooks" tags=[react,hooks]
[tips] queryNormalize tags sort=alpha result=[hooks,react]
[tips] querySerialize canonical="?tag=hooks&tag=react"
It turns "why did the URL change" into an answerable question.
We compute request identity from the canonical query only.
Otherwise you get duplicate caches for the same meaning, which looks like random stale data bugs.
Concrete alternative: put less in the URL, keep the rest local.
We only put share-worthy posture in query params. Everything else stays local draft state. Otherwise you generate links nobody wants to share.
Yes. The hardest part is deciding what is share-worthy.
Once you decide that, schema + canonicalization becomes straightforward.
Long-form: query normalization is a UX decision disguised as a parsing decision.
Do you drop empty values? Do you clamp numbers? Do you preserve unknown keys? Each choice affects link durability and migration strategy.
We wrote the rules down and we render an evidence token when a fallback occurred (so support can see it).
Docs tie-in: query state is route state with a serialization layer; the routing docs help frame it as a contract.
Related: Routing and Navigation and State Management.
Short take: if parse/serialize doesn't converge, you built a URL oscillator.
We keep unknown keys but we log them (migration signals).
It's useful when old links are circulating and you want to know which legacy params still matter.
We render a data-qnorm=1 evidence token if canonicalization changed the URL.
It prevents the bug report where users think the app is "rewriting links" for no reason.
We also canonicalize spacing/encoding. It's surprising how many caching bugs are just encoding differences.
Normalize before identity, always.
If you treat query params as schema, unit test the schema. It's cheap and it prevents drift.
Most query bugs are "someone changed normalization" without realizing it.
Long-form counterpoint: strict schemas can make links less tolerant of real-world copy/paste weirdness.
We kept strict normalization but we also support a small set of legacy keys and we log when we used them.
One pattern: represent arrays canonically as repeated keys, sorted, and never as comma-separated strings.
Comma-separated looks nice until you have escaping edge cases.
Canonicalization is the difference between debuggable and haunted links.
We keep canonicalization stable across web and native clients by sharing the normalization rules in one module.
If clients disagree, you get duplicate caches and inconsistent behavior.
Takeaway: URLSearchParams is easy; the policy is hard.
Write the policy down, log normalization, and your router stops feeling mysterious.