Why QueryWeave
The same query is read in many places
Section titled “The same query is read in many places”A server renders the first response from it. The client reads it again after hydration. The user shares it as a link. A test asserts the result. A helper tied to one framework’s component lifecycle can only cover one of those reads.
QueryWeave defines the query as a model and syncs it through environment-specific adapters. The model stays the same everywhere; only the adapter changes with the environment.
Decoding and encoding stay together
Section titled “Decoding and encoding stay together”When a parser and a serializer are configured separately, they drift: the parser accepts values the serializer cannot produce, and a value no longer survives the trip from state to URL and back.
In QueryWeave, each parameter has one codec that handles both directions. There is no createParser
or separate serializer to keep in step with it.
Defaults belong to the parameter
Section titled “Defaults belong to the parameter”If a default lives in the component that reads the query, every other reader has to repeat it. The
URL also stops being canonical: ?page=1 and an absent page mean the same thing but are different
strings.
Declaring the default on the parameter fixes both. Every reader gets the same default when decoding,
and encoding leaves page out when it equals 1, so both spellings collapse into one URL.
Invalid input is normal
Section titled “Invalid input is normal”Query strings arrive from links, bookmarks, crawlers, and typos. Treating bad input as an exception
forces every call site into a try/catch that usually swallows the cause.
QueryWeave returns a result. A failed decode still carries partial values and a list of issues
with stable codes, so an application can render something useful and report what went wrong.
Model first
Section titled “Model first”@queryweave/core has no framework dependency, and a repository check keeps it that way. Vue and
Nuxt support are integrations built on the same runtime a plain TypeScript application uses.
Parsing the string is the smallest part of the library. Most of it is the model around the string: issues with stable codes, the canonical form, and the rules for when and how a transition writes the URL.
You declare a model, then change it through named operations such as update and reset.
Hook-shaped APIs, per-key hooks, tuple setters, and parseAs*-style constructors are ruled out in
ADR 0001.
What that costs
Section titled “What that costs”- More to write up front. A model must be declared before anything can read a single value.
For an application with one
?tab=parameter, that is more ceremony than it is worth. - No per-key ergonomics. There is no
useTab(). You readbinding.values.taband call an explicit operation to change it. - No debounce. A runtime can throttle its writes so a search field does not write on every keystroke, but a quiet-period delay, where nothing is written until typing pauses, stays yours to write.
URL state as a domain walks through the concepts in order.