AniUI Academy

Parse bracket-notation query parameters

hardDOM & Utilities+350 XPPractice

Once filters get nested, flat key-value parsing is not enough: APIs and form libraries encode structure into the key itself with bracket notation. Rebuilding the object from that is a neat exercise in walking a path and creating containers as you go.

Implement parseNestedQuery(search) returning a nested plain object. Strip one leading ?, split on &, and skip empty segments. Split each segment on its first =; a segment with no = has the value "".

Read the bracket structure from the **raw** key before decoding: the text before the first [ is the base key, and each following [...] is one more path segment. Then decode each segment and the value individually by replacing + with a space and calling decodeURIComponent, falling back to the raw text if that throws — so a percent-encoded bracket never changes the structure.

An empty segment [] means append to an array, so tags[]=a&tags[]=b gives { tags: ["a", "b"] }. Every other segment, **including a numeric one**, is an ordinary object key, so a[0]=x gives { a: { "0": "x" } }. Containers are created as you walk: a segment is an array when the next segment is [] and a plain object otherwise, and if a [] is followed by further segments a new object is appended for each pair. A repeated non-array key is overwritten, so the last value wins. An empty input returns {}.

Arguments

searchstring
A query string, with or without a leading ?. Empty segments are tolerated and an empty input returns {}.

Returns

object — A nested plain object reflecting the bracket structure in the keys. [] segments produce arrays; every other segment is an object key, even when numeric.

Examples

parseNestedQuery("user[name]=Ada&user[address][city]=London");
// => { user: { name: "Ada", address: { city: "London" } } }

Each [segment] adds one level of nesting.

parseNestedQuery("tags[]=a&tags[]=b");
// => { tags: ["a", "b"] }

The empty [] marker appends to an array.

parseNestedQuery("?filter[tags][]=x&filter[tags][]=y&filter[q]=hello+world");
// => { filter: { tags: ["x", "y"], q: "hello world" } }

Nested arrays and + decoded as space, all in one go.

parseNestedQuery("a[0]=x");
// => { a: { "0": "x" } }

Numeric segments are object keys, not array indices — they stay strings.

What it has to do

  • Strip an optional leading ?, split on &, and skip empty segments.
  • Read the bracket path from the raw key, then decode each key segment and the value separately, handling + as a space.
  • Append to an array for the empty [] segment.
  • Treat every other segment, including numeric ones, as an ordinary object key.
  • Create arrays and objects on demand while walking the path, and return {} for empty input.

Notes

  • Reading the bracket path from the _raw_ key is critical: once you decode first, a percent-encoded bracket like %5B becomes [ and you can no longer tell structure from content.
  • This matches the behaviour of PHP, Rails and the qs library — the format Rails forms serialise into and that most REST APIs built on those stacks expect.

Stuck? The javascript course covers everything this challenge needs.

Try it yourself
Loading playground...
5 tests · +350 XP

Discussion

Sign in to post
Sign in to join the conversation.Sign in

No comments yet. Be the first to say something.