URI Charge Notation designed to encode arbitrary JavaScript values as part of URI.
URI charge represents everything what JSON does, and even more. E.g. it is able to represent BigInt values natively.
The notation is extensible, so it may represent something that needs a special representation. So, the Infinity, negative Infinity and NaN values are representable within URI charge with standard extensions enabled.
URI charge may present in various parts of URI. E.g. within query:
?find=includes(first_name(john))&order=first_name(asc(!))second_name(asc(!))birthday(asc(-))&range=from(10)to(20)
Any JavaScript primitive, except Symbol and undefined (which stands value absence), has its representation within URI charge.
Numbers encoded as is:
- Any string started with decimal digit (
"0" (U+OO30)
-"9" (U+OO39)
) treated as positive number. - Any string starting with hyphen (
"-" (U+002D)
) followed by decimal digit treated as negative number.
The number string can be percent-encoded.
Negative zero encoded as -0
.
Hexadecimal and binary formats are also supported. For that, the string should start with 0x
/-0x
and 0b
/-0b
respectively.
Decimal digits also supported: 3.14159265359
, 0.1E-23
. Note that the leading 0
can not be omitted.
BigInt values encoded as decimal string preceded by 0n
or -0n
prefix:
?from=-0n12344543&to=0n4354354452354
true
encoded as!
- exactly one exclamation mark ("!" (U+0021)
).false
encoded as-
- exactly one hyphen ("-" (U+002D)
).
null
encoded as --
- exactly two hyphens ("-" (U+002D)
).
String represented as percent-encoded value.
Additionally:
- Since parentheses (
"(" (U+0028)
and")" (U+0029)
) and comma ("," (U+002C)
) have special meaning within URI charge, they should be percent-encoded. - When encoded value starts with apostrophe (
"'" (U+0027)
), the apostrophe is stripped, and the actual string value starts from the second symbol. - A quoted string starting with apostrophe may include balanced set of parentheses (
"(" (U+0028)
and")" (U+0029)
). I.e. each closing parenthesis should match the opening one preceding it. A comma ("," (U+002C)
) is considered a part of such string only if it is enclosed into parentheses. This may be used to place unchanged URI charge as a string value. - Since decimal digits,
"!" (U+0021)
,"$" (U+0024)
,"'" (U+0027)
, and"-" (U+002D)
prefixes have special meaning, they should be escaped with apostrophe ("'" (U+0027)
).
Empty string may be left as is or encoded as single apostrophe ("'" (U+0027)
).
?first=John&middle='&last=Doe&birthday='1970-01-01
Raw value is the one not yet processed as numeric value, null
(--
), or false
(-
).
Data schema may change the way the raw value parsed. E.g. it may wish to always treat it as string.
This, however, does not affect quoted strings, or values starting with "!" (U+0021)
or "$" (U+0024)
.
List corresponds to JavaScript array literal.
List encoded as series of item values separated by comma ("," (U+002C)
).
foo,bar,baz
represents an array like
["foo", "bar", "baz"]
Leading and trailing comma ignored within list. So the list above can be encoded as:
,foo,bar,baz
foo,bar,baz,
,foo,bar,baz,
Empty list encoded as single comma ("," (U+002C)
). This is possible, because such comma is ignored.
List with single item has to contain at leas one (leading or trailing comma to distinguish it from single value:
,foo
foo,
,foo,
An item value is encoded within URI charge. Thus, it can be anything:
- boolean value:
!,-
- number:
-128,127
- empty string:
,'
or,,
An list item containing another (nested) list should be enclosed into parentheses:
(foo,bar),(baz)
represents an array like
[["foo", "bar"], ["baz"]]
Note that comma is completely optional after nested list. So the list above can be encoded as:
(foo,bar)(baz)
Any level of nesting supported:
(1,(2.1,(2.1.1,2.1.2))((3.1.1,3.1.2)4.1)5)
Map corresponds to JavaScript object literal.
Map encoded as series of key/value entries. Each entry encoded as key followed by value enclosed into parentheses.
column(first_name)includes(john)
represents an object like
{
"column": "first_name",
"includes": "john"
}
Empty map has special representation: $
An entry value is encoded within URI charge. Thus, it can be anything:
- boolean value:
foo(!)bar(-)
- number:
from(-128)to(127)
null
:is-null(--)
- nested map:
foo(bar(baz))
- nested empty map:
foo($)
- list:
foo(bar,baz)
- empty list:
foo(,)
- multidimensional list: `foo((item1.1,item1.2)(item2.1,item2.2))
- empty string:
foo()
Map entry may be specified multiple times. However, it is up to parser (or data schema) how to interpret this. E.g. multiple values may be treated as list items. By default, the last entry value overrides preceding ones.
The following rules apply to entry keys:
- Since parentheses (
"(" (U+0028)
and")" (U+0029)
) and comma ("," (U+002C)
) have special meaning within URI charge, they should be percent-encoded. - When encoded value starts with dollar sign (
"$" (U+0024)
), the dollar sign is stripped, and the actual key value starts from the second symbol. This can be used to escape symbols that have special meaning, except parentheses, that should be percent-encoded. - Since
"!" (U+0021)
,"$" (U+0024)
, and"'" (U+0027)
prefixes have special meaning, they should be escaped with dollar sign ("$" (U+0024)
). - Empty key represented by single dollar sign (
"$" (U+0024)
).
A special case when key prefixed with dollar sign is not followed by value is treated as entry with empty string
value. I.e. $key
is the same as $key()
. Note that this rule does not work for single $
symbol, which stands
for empty object. The $()
has to be used for object with empty key and empty value ({ '': '' }
).
A map may have suffix. I.e. the last entry key without value. Such suffix is treated as entry with empty string
value. So, foo(bar)suffix
is the same as foo(bar)suffix()
or foo(bar)suffix(')
).
URI Charge Notation can be extended with custom entities. An entity is an opaque syntax construct that don't have special meaning, unless recognized by custom handler.
Entity starts with exclamation mark ("!" (U+0021)
) followed by entity name. Entity name should not include
apostrophe ("'" (U+0027)
) or other delimiters.
The following entities supported by standard "Non-Finite Numbers" extension:
!Infinity
is treated asInfinity
(positive infinity) numeric value.!-Infinity
is treated as-Infinity
(negative infinity) numeric value.!NaN
is treated asNaN
(not-a-number) value.
Formatted data extends URI Charge Notation with additional data formats, such as base64.
Formatted data starts with exclamation mark ("!" (U+0021)
) followed by format name, apostrophe ("'" (U+0027)
),
and arbitrary data in the named format. The data may include e.g. balanced set of parentheses, just like a quoted string.
Example formatted data:
!base64'SGVsbG8sIFdvcmxkIQ
Metadata can be attached to any value. For that, any number of metadata attributes may precede the value.
Metadata attribute starts with exclamation mark ("!" (U+0021)
) followed by attribute name and value enclosed into
parentheses.
Unlike entities and formatted data, metadata attribute don't have to be recognized.
Charge processor may use metadata e.g. as data processing parameter:
content-type(text,plain)charset(utf-8)base64'SGVsbG8sIFdvcmxkIQ