Query-string parser lab · Updated November 9, 2026

Query Parameters Explained: Repeated Empty and Array Values

A query string is the key-value sequence after the ? in a URL, with parameters separated by &. Repeated keys, empty values, valueless keys, and array conventions can make the same data parse into different results, so inspect the raw sequence before choosing a parser.

Query string URL anatomy

In /search?tag=red&tag=blue#results, the query string is tag=red&tag=blue. The ? starts it, & separates parameters, and #results is a fragment for the client; the fragment is not sent in the HTTP request.

Repeated, empty, and valueless parameters

Raw inputStateJavaScriptPython
tag=red&tag=blueRepeated keyget() → first; getAll() → bothparse_qs → list
empty=Empty valuekey exists, value ""parse_qs(...,keep_blank_values=True)
flagValueless keykey exists with empty valueNode returns an empty string; Python default drops it, and keep_blank_values=True retains [""]; see the measured table below

Do not convert repeated entries to a plain object before deciding what they mean: a single object property cannot retain every value.

Arrays and objects: three serialization conventions

The same logical list can be written three common ways. They are not interchangeable on the wire.

ConventionRaw queryTypical parser result
Bracketa[]=1&a[]=2Array under the key a in bracket-aware frameworks
Repeated keya=1&a=2List when the parser preserves duplicates; first value in single-value APIs
Comma valuea=1,2One string unless the application explicitly splits commas

Language-level measurements

Run date: November 9, 2026. Node.js v24.19.0, Python 3.13.15. PHP 8.5.12 CLI was used for the PHP row.

Runtimea[]=1&a[]=2&flagflag
Node URLSearchParamskeys remain literal a[]; entries: [["a[]","1"],["a[]","2"]]get("flag") → ""
Python 3.13 parse_qs default{"a[]":["1","2"]}; bracket is not specialomitted by default
Python 3.13 parse_qs(..., keep_blank_values=True){"a[]":["1","2"]}{"flag":[""]}
Node qs 6.13.1{a:["1","2"]}flag:""
PHP parse_stra array ["1","2"]; flag empty stringflag → ""

The important mismatch is concrete: Python keeps the literal key a[], while bracket-aware conventions turn it into a. A parser choice is therefore part of the API contract.

Measured raw request and parsed output

GET /items?a[]=1&a[]=2 HTTP/1.1
raw query: a[]=1&a[]=2
bracket-aware output: {"a":["1","2"]}

GET /items?a=1&a=2 HTTP/1.1
raw query: a=1&a=2
get(): "1"   getAll(): ["1","2"]

GET /items?a=1,2 HTTP/1.1
raw query: a=1,2
plain output: {"a":"1,2"}

These outputs describe parser behavior, not a universal server requirement. The server or framework decides which convention it accepts.

Decode URL parameters

Percent-encoded parameter names and values must be decoded with the correct plus policy. Use URL Decode Online for one-layer decoding and to compare + with %20.

Encoding-side pitfalls

For form bodies, see application/x-www-form-urlencoded. For repeated-key serialization and mutation behavior, see repeated query parameters.

Run the parser

FAQ

Are repeated keys valid?

They are syntactically possible, but the application must define whether to keep all values or only one.

Is an empty value the same as a missing value?

No. empty= carries a key with an empty value; a missing key is absent from the query.

Does the fragment reach the server?

No. The browser keeps the fragment client-side and excludes it from the HTTP request target.

Which array convention should I choose?

Choose the convention your server parser documents, then test its raw request and parsed output.