Bracket Notation
Learn how bracket notation encodes structured data like nested objects and arrays in flat key-value formats such as query strings and form data.
OpenAPI Serializer, OpenAPI Handler, and OpenAPI Link use bracket notation whenever nested data must be represented outside plain JSON.
Rules
-
Repeated keys become arrays.
color=red&color=blue -> { color: ['red', 'blue'] } -
Append
[]to push into an array.color[]=red&color[]=blue -> { color: ['red', 'blue'] } -
Append
[number]to target an explicit array index.color[0]=red&color[2]=blue -> { color: ['red', <empty>, 'blue'] }::: info Missing indexes create sparse arrays.
Explicit indexes may leave at most
1,000empty slots per input by default. An index that would exceed that turns its array into an object, for examplecolor[5000]=bluebecomes{ color: { 5000: 'blue' } }. To change the limit, configuremaxDeserializingEmptySlots:const serializer = new OpenAPISerializer({ bracketNotation: { maxDeserializingEmptySlots: 10_000, } }):::
-
Append
[key]to target an object property.color[red]=true&color[blue]=false -> { color: { red: 'true', blue: 'false' } }
Limitations
Bracket notation is designed to express structured data in constrained environments, so it has a few unavoidable limitations:
- Cannot represent empty structures like empty objects
{}or empty arrays[]. - Cannot represent an array at the root level. For example,
0=red&1=bluebecomes{ 0: 'red', 1: 'blue' }, not['red', 'blue']. - Cannot represent objects whose keys are all numbers, because they can be mistaken for array indexes.
- Cannot reliably represent keys that contain
[or].
Examples
URL Query
curl 'http://example.com/api/example?name[first]=John&name[last]=Doe'
This query is parsed as:
{
"name": {
"first": "John",
"last": "Doe"
}
}
Form Data
curl -X POST http://example.com/api/example \
-F 'name[first]=John' \
-F 'name[last]=Doe'
This form data is parsed as:
{
"name": {
"first": "John",
"last": "Doe"
}
}
Complex Example
curl -X POST http://example.com/api/example \
-F 'data[names][0][first]=John1' \
-F 'data[names][0][last]=Doe1' \
-F 'data[names][1][first]=John2' \
-F 'data[names][1][last]=Doe2' \
-F 'data[ages][0]=18' \
-F 'data[ages][2]=25' \
-F 'data[files][]=@/path/to/file1' \
-F 'data[files][]=@/path/to/file2'
This form data is parsed as:
{
"data": {
"names": [
{ "first": "John1", "last": "Doe1" },
{ "first": "John2", "last": "Doe2" }
],
"ages": ["18", "<empty>", "25"],
"files": ["<binary data>", "<binary data>"]
}
}
Learn More
The bracket notation is a small, self-contained module, making it easy to understand. To explore its behavior in detail, see the source code.