@gramex/url v2.0.2
@gramex/url
url encodes/decodes objects into form-urlencoded query strings. For example:
encode({ a: 1, b: [2, 3] }); // "a=1&b=2&b=3"
decode("a=1&b=2&b=3"); // {a: "1", b: ["2", "3"]}
update({ a: 2 }, "a=&b=3"); // {b: "3"}Alternatives
This library focuses on 3 features:
- Type conversion, e.g.
?a=1becomes{'a': 1}instead of{'a': '1'} - Array values, e.g.
?a=1&a=2becomes{'a': [1, 2]} - Nested keys, e.g.
?a.b=1becomes{'a': {'b': 1}}
Use the FIRST alternative below that meets your need:
| Alternatives | Type conversion | Array values | Nested keys | Why? |
|---|---|---|---|---|
| URLSearchParams | No | No | Yes | Native browser feature |
| query-string | Yes | Yes | No | Lightweight ES Module |
| qs | No | Yes | Yes | Most popular library |
| @gramex/url | Yes | Yes | Yes | Has all features above |
Installation
Install via npm:
npm install @gramex/urlUse locally as an ES module:
<script type="module">
import { encode, decode, update } from "./node_modules/@gramex/url/dist/url.js";
</script>Use locally as a script:
<script src="./node_modules/@gramex/url/dist/network.min.js"></script>
<script>
gramex.url.encode(...)
gramex.url.decode(...)
gramex.url.update(...)
</script>Use via CDN as an ES Module:
<script type="module">
import { encode, decode, update } from "https://cdn.jsdelivr.net/npm/@gramex/url@2/dist/url.js";
</script>Use via CDN as a script:
<script src="https://cdn.jsdelivr.net/npm/@gramex/url@1/dist/url.min.js"></script>
<script>
gramex.url.encode(...)
gramex.url.decode(...)
gramex.url.update(...)
</script>encode
encode(object, [settings]) encodes object into a form-urlencoded query string.
object is any JSON serializable object.
settings is an optional object with the following properties:
listBracket: appends[]to arrays. Default:falseencode({a: [1, 2]})➜"a=1&a=2"encode({a: [1, 2]}, {listBracket: true})➜"a[]=1&a[]=2"
listIndex: appends[0],[1], ... to arrays. OverrideslistBracket. Default:falseencode({a: [1, 2]})➜"a=1&a=2"encode({a: [1, 2]}, {listIndex: true})➜"a[0]=1&a[1]=2",
objBracket: uses[key]instead of.key. Default:falseencode({a: {b: 1}})➜"a.b=1"encode({a: {b: 1}}, {objBracket: true})➜"a[b]=1"
sortKeys: sorts keys. Default:falseencode({b: 2, a: 1})➜"b=2&a=1"encode({b: 2, a: 1}, {sortKeys: true})➜"a=1&b=2"
drop: list of values to drop. Default:[]encode({a: "", b: null})➜"a=&b=null"encode({a: "", b: null}, {drop: ["", null]})➜""
More examples:
encode({ a: { b: [1, 2] } }); // "a.b=1&a.b=2"
encode({ a: [{ b: 1 }, { b: 2 }] }); // "a.b=1&a.b=2" -- same as above!
encode({ a: { b: [1, 2] } }, { listBracket: true }); // "a.b[]=1&a.b[]=2"
encode({ a: [{ b: 1 }, { b: 2 }] }, { listBracket: true }); // "a[].b=1&a[].b=2"
encode({ a: { b: [1, { c: 2 }] } }); // "a.b=1&a.b.c=2"
encode({ a: { b: [1, { c: 2 }] } }, { listBracket: true }); // "a.b[]=1&a.b[].c=2"decode
decode(url, [settings]) decodes a form-urlencoded query string into an object
url is any URL query string.
settings is an optional object with the following properties:
convert: converts numbers, boolean, null and undefined into native JavaScript. Default:falsedecode("a=1e2&b=true&c=null&d=x")➜{a: "1e2", b: "true", c: "null", d: "x"}decode("a=1e2&b=true&c=null&d=x", {convert: true})➜{a: 100, b: true, c: null, d: "x"}
forceList: always saves values as arrays. Default:falsedecode("a=1")➜{a: 1}decode("a=1", {forceList: true})➜{a: [1]},
pruneString: removes empty strings. Default:falsedecode("a=")➜{a: ""}decode("a=", {pruneString: true})➜{}
Notes:
- If a key ends with
[](e.g.a[]=1) it is converted to an array (likeforceList) and values are appended. - If a key has a
.(e.g.a.b=1) it is converted to an object and sub-keys are nested.
More examples:
decode("a.b=1&a.c=2"); // {a: {b: "1", c: "2"}}
decode("a.b=1&a[c]=2"); // {a: {b: "1", c: "2"}}
decode("a.b=1&a[]=2"); // {a: [{b: "1"}, "2"]}
decode(`a=2&a[]=3`); // `{"a": ["2", "3"]}`
decode("a[]=1&a[]=2"); // {a: ["1", "2"]}
decode("a[]=1&b[]=2"); // {a: ["1"], b: ["2"]}
decode("a.b[]=1&a.b[]=2"); // {a: {b: ["1", "2"]}}update
update(object, url, [settings]) updates an object with a form-urlencoded query string.
object is any JSON serializable object.
url is any URL query string. It uses the following conventions:
a=1setsobject.ato1update({a: "0"}, "a=1")➜{a: "1"}update({a: ["0", "1"]}, "a=1&a=2")➜{a: ["1", "2"]}
a[]=1forcesobject.ainto a list and appends1to it.update({}, "a[]=1")➜{a: "1"}(sinceforceListdefaults to `false)update({a: "0"}, "a[]=1")➜{a: ["0", "1"]}
a.b=1forcesobject.ainto an object ({val: val}if the value is a scalar) and setsobject.a.bto1update({}, "a.b=1")➜{a: {b: "1"}}update({a: "0"}, "a.b=1")➜{a: {"0": "0", b: "1"}}update({a: {b: "0"}}, "a.b=1")➜{a: {b: "1"}}
a.b[]=1forcesobject.a.binto a list (e.g.[val]) and appends1update({}, "a.b[]=1")➜{a: {b: "1"}}(sinceforceListdefaults to `false)update({a: "1"}, "a.b[]=2")➜{a: {"1": "1", b: ["2"]}}update({}, "a.b=1&a[]=2")➜{ a: [{ b: "1" }, "2"] }
a-=removesobject.aupdate({a: "1"}, "a-=")➜{}update({a: ["0", "1"]}, "a-=")➜{}
a-=1removes1fromobject.aupdate({a: "1"}, "a-=1")➜{}update({a: ["0", "1"]}, "a-=1")➜{a: ["0"]}
a~=1toggles1inobject.aupdate({a: "0"}, "a~=1")➜{a: ["0", "1"]}update({a: "1"}, "a~=1")➜{}update({a: ["1"]}, "a~=1", {drop: []})➜{a: []}update({a: ["0", "1"]}, "a~=1")➜{a: ["0"]}
settings is an optional object with the following properties:
convert: converts numbers, boolean, null and undefined into native JavaScript. Default:falseupdate({a: 100, b: true}, "a-=1e2&b=true")➜{a: 100, b: true}update({a: 100, b: true}, "a-=1e2&b=true", {convert: true})➜{}
forceList: always saves values as arrays. Default:falseupdate({}, "a=1")➜{a: 1}update({}, "a=1", {forceList: true})➜{a: [1]},
pruneString: removes empty strings. Default:falseupdate({"a": ""}, "b=")➜{a: "", b: ""}update({"a": ""}, "b=", {pruneString: true})➜{}
pruneObject: removes empty objects. Default:trueupdate({"a": {}}, "b=2")➜{b: 2}update({"a": {}}, "b=2", {pruneObject: true})➜{a: {}, b: 2}
pruneArray: removes empty arrays. Default:trueupdate({"a": []}, "b=2")➜{b: 2}update({"a": []}, "b=2", {pruneArray: true})➜{a: [], b: 2}
More examples:
update({ a: 1 }, "a.b=2"); // {a: [1, {b: "2"}]}
update({ a: { b: "1" } }, "a.b-=1"); // {}Release notes
- 2.0.0: 7 Oct 2023.
update()implemented- Breaking change:
decode({drop})is not supported. Usedecode({pruneString, pruneObject, pruneArray})instead.
- Breaking change:
- 1.1.0: 22 May 2022.
decode()implemented - 1.0.0: 21 May 2023.
encode()implemented
Authors
Anand S s.anand@gramener.com