1 | # qs <sup>[![Version Badge][2]][1]</sup>
|
2 |
|
3 | [![Build Status][3]][4]
|
4 | [![dependency status][5]][6]
|
5 | [![dev dependency status][7]][8]
|
6 | [![License][license-image]][license-url]
|
7 | [![Downloads][downloads-image]][downloads-url]
|
8 |
|
9 | [![npm badge][11]][1]
|
10 |
|
11 | A querystring parsing and stringifying library with some added security.
|
12 |
|
13 | Lead Maintainer: [Jordan Harband](https://github.com/ljharb)
|
14 |
|
15 | The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
|
16 |
|
17 | ## Usage
|
18 |
|
19 | ```javascript
|
20 | var qs = require('qs');
|
21 | var assert = require('assert');
|
22 |
|
23 | var obj = qs.parse('a=c');
|
24 | assert.deepEqual(obj, { a: 'c' });
|
25 |
|
26 | var str = qs.stringify(obj);
|
27 | assert.equal(str, 'a=c');
|
28 | ```
|
29 |
|
30 | ### Parsing Objects
|
31 |
|
32 | [](#preventEval)
|
33 | ```javascript
|
34 | qs.parse(string, [options]);
|
35 | ```
|
36 |
|
37 | **qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`.
|
38 | For example, the string `'foo[bar]=baz'` converts to:
|
39 |
|
40 | ```javascript
|
41 | assert.deepEqual(qs.parse('foo[bar]=baz'), {
|
42 | foo: {
|
43 | bar: 'baz'
|
44 | }
|
45 | });
|
46 | ```
|
47 |
|
48 | When using the `plainObjects` option the parsed value is returned as a null object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
|
49 |
|
50 | ```javascript
|
51 | var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
|
52 | assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
|
53 | ```
|
54 |
|
55 | By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.
|
56 |
|
57 | ```javascript
|
58 | var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
|
59 | assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } });
|
60 | ```
|
61 |
|
62 | URI encoded strings work too:
|
63 |
|
64 | ```javascript
|
65 | assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
|
66 | a: { b: 'c' }
|
67 | });
|
68 | ```
|
69 |
|
70 | You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
|
71 |
|
72 | ```javascript
|
73 | assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
|
74 | foo: {
|
75 | bar: {
|
76 | baz: 'foobarbaz'
|
77 | }
|
78 | }
|
79 | });
|
80 | ```
|
81 |
|
82 | By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like
|
83 | `'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
|
84 |
|
85 | ```javascript
|
86 | var expected = {
|
87 | a: {
|
88 | b: {
|
89 | c: {
|
90 | d: {
|
91 | e: {
|
92 | f: {
|
93 | '[g][h][i]': 'j'
|
94 | }
|
95 | }
|
96 | }
|
97 | }
|
98 | }
|
99 | }
|
100 | };
|
101 | var string = 'a[b][c][d][e][f][g][h][i]=j';
|
102 | assert.deepEqual(qs.parse(string), expected);
|
103 | ```
|
104 |
|
105 | This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`:
|
106 |
|
107 | ```javascript
|
108 | var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
|
109 | assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
|
110 | ```
|
111 |
|
112 | The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number.
|
113 |
|
114 | For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
|
115 |
|
116 | ```javascript
|
117 | var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
|
118 | assert.deepEqual(limited, { a: 'b' });
|
119 | ```
|
120 |
|
121 | To bypass the leading question mark, use `ignoreQueryPrefix`:
|
122 |
|
123 | ```javascript
|
124 | var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
|
125 | assert.deepEqual(prefixed, { a: 'b', c: 'd' });
|
126 | ```
|
127 |
|
128 | An optional delimiter can also be passed:
|
129 |
|
130 | ```javascript
|
131 | var delimited = qs.parse('a=b;c=d', { delimiter: ';' });
|
132 | assert.deepEqual(delimited, { a: 'b', c: 'd' });
|
133 | ```
|
134 |
|
135 | Delimiters can be a regular expression too:
|
136 |
|
137 | ```javascript
|
138 | var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
|
139 | assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' });
|
140 | ```
|
141 |
|
142 | Option `allowDots` can be used to enable dot notation:
|
143 |
|
144 | ```javascript
|
145 | var withDots = qs.parse('a.b=c', { allowDots: true });
|
146 | assert.deepEqual(withDots, { a: { b: 'c' } });
|
147 | ```
|
148 |
|
149 | ### Parsing Arrays
|
150 |
|
151 | **qs** can also parse arrays using a similar `[]` notation:
|
152 |
|
153 | ```javascript
|
154 | var withArray = qs.parse('a[]=b&a[]=c');
|
155 | assert.deepEqual(withArray, { a: ['b', 'c'] });
|
156 | ```
|
157 |
|
158 | You may specify an index as well:
|
159 |
|
160 | ```javascript
|
161 | var withIndexes = qs.parse('a[1]=c&a[0]=b');
|
162 | assert.deepEqual(withIndexes, { a: ['b', 'c'] });
|
163 | ```
|
164 |
|
165 | Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number
|
166 | to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving
|
167 | their order:
|
168 |
|
169 | ```javascript
|
170 | var noSparse = qs.parse('a[1]=b&a[15]=c');
|
171 | assert.deepEqual(noSparse, { a: ['b', 'c'] });
|
172 | ```
|
173 |
|
174 | Note that an empty string is also a value, and will be preserved:
|
175 |
|
176 | ```javascript
|
177 | var withEmptyString = qs.parse('a[]=&a[]=b');
|
178 | assert.deepEqual(withEmptyString, { a: ['', 'b'] });
|
179 |
|
180 | var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
|
181 | assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
|
182 | ```
|
183 |
|
184 | **qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
|
185 | instead be converted to an object with the index as the key:
|
186 |
|
187 | ```javascript
|
188 | var withMaxIndex = qs.parse('a[100]=b');
|
189 | assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });
|
190 | ```
|
191 |
|
192 | This limit can be overridden by passing an `arrayLimit` option:
|
193 |
|
194 | ```javascript
|
195 | var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
|
196 | assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
|
197 | ```
|
198 |
|
199 | To disable array parsing entirely, set `parseArrays` to `false`.
|
200 |
|
201 | ```javascript
|
202 | var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
|
203 | assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });
|
204 | ```
|
205 |
|
206 | If you mix notations, **qs** will merge the two items into an object:
|
207 |
|
208 | ```javascript
|
209 | var mixedNotation = qs.parse('a[0]=b&a[b]=c');
|
210 | assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });
|
211 | ```
|
212 |
|
213 | You can also create arrays of objects:
|
214 |
|
215 | ```javascript
|
216 | var arraysOfObjects = qs.parse('a[][b]=c');
|
217 | assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });
|
218 | ```
|
219 |
|
220 | ### Stringifying
|
221 |
|
222 | [](#preventEval)
|
223 | ```javascript
|
224 | qs.stringify(object, [options]);
|
225 | ```
|
226 |
|
227 | When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:
|
228 |
|
229 | ```javascript
|
230 | assert.equal(qs.stringify({ a: 'b' }), 'a=b');
|
231 | assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
|
232 | ```
|
233 |
|
234 | This encoding can be disabled by setting the `encode` option to `false`:
|
235 |
|
236 | ```javascript
|
237 | var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
|
238 | assert.equal(unencoded, 'a[b]=c');
|
239 | ```
|
240 |
|
241 | Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:
|
242 | ```javascript
|
243 | var encodedValues = qs.stringify(
|
244 | { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
|
245 | { encodeValuesOnly: true }
|
246 | );
|
247 | assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
|
248 | ```
|
249 |
|
250 | This encoding can also be replaced by a custom encoding method set as `encoder` option:
|
251 |
|
252 | ```javascript
|
253 | var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
|
254 | // Passed in values `a`, `b`, `c`
|
255 | return // Return encoded string
|
256 | }})
|
257 | ```
|
258 |
|
259 | _(Note: the `encoder` option does not apply if `encode` is `false`)_
|
260 |
|
261 | Analogue to the `encoder` there is a `decoder` option for `parse` to override decoding of properties and values:
|
262 |
|
263 | ```javascript
|
264 | var decoded = qs.parse('x=z', { decoder: function (str) {
|
265 | // Passed in values `x`, `z`
|
266 | return // Return decoded string
|
267 | }})
|
268 | ```
|
269 |
|
270 | Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
|
271 |
|
272 | When arrays are stringified, by default they are given explicit indices:
|
273 |
|
274 | ```javascript
|
275 | qs.stringify({ a: ['b', 'c', 'd'] });
|
276 | // 'a[0]=b&a[1]=c&a[2]=d'
|
277 | ```
|
278 |
|
279 | You may override this by setting the `indices` option to `false`:
|
280 |
|
281 | ```javascript
|
282 | qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
|
283 | // 'a=b&a=c&a=d'
|
284 | ```
|
285 |
|
286 | You may use the `arrayFormat` option to specify the format of the output array:
|
287 |
|
288 | ```javascript
|
289 | qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
|
290 | // 'a[0]=b&a[1]=c'
|
291 | qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
|
292 | // 'a[]=b&a[]=c'
|
293 | qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
|
294 | // 'a=b&a=c'
|
295 | ```
|
296 |
|
297 | When objects are stringified, by default they use bracket notation:
|
298 |
|
299 | ```javascript
|
300 | qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
|
301 | // 'a[b][c]=d&a[b][e]=f'
|
302 | ```
|
303 |
|
304 | You may override this to use dot notation by setting the `allowDots` option to `true`:
|
305 |
|
306 | ```javascript
|
307 | qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
|
308 | // 'a.b.c=d&a.b.e=f'
|
309 | ```
|
310 |
|
311 | Empty strings and null values will omit the value, but the equals sign (=) remains in place:
|
312 |
|
313 | ```javascript
|
314 | assert.equal(qs.stringify({ a: '' }), 'a=');
|
315 | ```
|
316 |
|
317 | Key with no values (such as an empty object or array) will return nothing:
|
318 |
|
319 | ```javascript
|
320 | assert.equal(qs.stringify({ a: [] }), '');
|
321 | assert.equal(qs.stringify({ a: {} }), '');
|
322 | assert.equal(qs.stringify({ a: [{}] }), '');
|
323 | assert.equal(qs.stringify({ a: { b: []} }), '');
|
324 | assert.equal(qs.stringify({ a: { b: {}} }), '');
|
325 | ```
|
326 |
|
327 | Properties that are set to `undefined` will be omitted entirely:
|
328 |
|
329 | ```javascript
|
330 | assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
|
331 | ```
|
332 |
|
333 | The query string may optionally be prepended with a question mark:
|
334 |
|
335 | ```javascript
|
336 | assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
|
337 | ```
|
338 |
|
339 | The delimiter may be overridden with stringify as well:
|
340 |
|
341 | ```javascript
|
342 | assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
|
343 | ```
|
344 |
|
345 | If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option:
|
346 |
|
347 | ```javascript
|
348 | var date = new Date(7);
|
349 | assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
|
350 | assert.equal(
|
351 | qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
|
352 | 'a=7'
|
353 | );
|
354 | ```
|
355 |
|
356 | You may use the `sort` option to affect the order of parameter keys:
|
357 |
|
358 | ```javascript
|
359 | function alphabeticalSort(a, b) {
|
360 | return a.localeCompare(b);
|
361 | }
|
362 | assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
|
363 | ```
|
364 |
|
365 | Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
|
366 | If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
|
367 | pass an array, it will be used to select properties and array indices for stringification:
|
368 |
|
369 | ```javascript
|
370 | function filterFunc(prefix, value) {
|
371 | if (prefix == 'b') {
|
372 | // Return an `undefined` value to omit a property.
|
373 | return;
|
374 | }
|
375 | if (prefix == 'e[f]') {
|
376 | return value.getTime();
|
377 | }
|
378 | if (prefix == 'e[g][0]') {
|
379 | return value * 2;
|
380 | }
|
381 | return value;
|
382 | }
|
383 | qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
|
384 | // 'a=b&c=d&e[f]=123&e[g][0]=4'
|
385 | qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });
|
386 | // 'a=b&e=f'
|
387 | qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
|
388 | // 'a[0]=b&a[2]=d'
|
389 | ```
|
390 |
|
391 | ### Handling of `null` values
|
392 |
|
393 | By default, `null` values are treated like empty strings:
|
394 |
|
395 | ```javascript
|
396 | var withNull = qs.stringify({ a: null, b: '' });
|
397 | assert.equal(withNull, 'a=&b=');
|
398 | ```
|
399 |
|
400 | Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
|
401 |
|
402 | ```javascript
|
403 | var equalsInsensitive = qs.parse('a&b=');
|
404 | assert.deepEqual(equalsInsensitive, { a: '', b: '' });
|
405 | ```
|
406 |
|
407 | To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
|
408 | values have no `=` sign:
|
409 |
|
410 | ```javascript
|
411 | var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
|
412 | assert.equal(strictNull, 'a&b=');
|
413 | ```
|
414 |
|
415 | To parse values without `=` back to `null` use the `strictNullHandling` flag:
|
416 |
|
417 | ```javascript
|
418 | var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
|
419 | assert.deepEqual(parsedStrictNull, { a: null, b: '' });
|
420 | ```
|
421 |
|
422 | To completely skip rendering keys with `null` values, use the `skipNulls` flag:
|
423 |
|
424 | ```javascript
|
425 | var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
|
426 | assert.equal(nullsSkipped, 'a=b');
|
427 | ```
|
428 |
|
429 | ### Dealing with special character sets
|
430 |
|
431 | By default the encoding and decoding of characters is done in `utf-8`. If you
|
432 | wish to encode querystrings to a different character set (i.e.
|
433 | [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
|
434 | [`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
|
435 |
|
436 | ```javascript
|
437 | var encoder = require('qs-iconv/encoder')('shift_jis');
|
438 | var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });
|
439 | assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I');
|
440 | ```
|
441 |
|
442 | This also works for decoding of query strings:
|
443 |
|
444 | ```javascript
|
445 | var decoder = require('qs-iconv/decoder')('shift_jis');
|
446 | var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });
|
447 | assert.deepEqual(obj, { a: 'こんにちは!' });
|
448 | ```
|
449 |
|
450 | ### RFC 3986 and RFC 1738 space encoding
|
451 |
|
452 | RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible.
|
453 | In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'.
|
454 |
|
455 | ```
|
456 | assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
|
457 | assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
|
458 | assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
|
459 | ```
|
460 |
|
461 | [1]: https://npmjs.org/package/qs
|
462 | [2]: http://versionbadg.es/ljharb/qs.svg
|
463 | [3]: https://api.travis-ci.org/ljharb/qs.svg
|
464 | [4]: https://travis-ci.org/ljharb/qs
|
465 | [5]: https://david-dm.org/ljharb/qs.svg
|
466 | [6]: https://david-dm.org/ljharb/qs
|
467 | [7]: https://david-dm.org/ljharb/qs/dev-status.svg
|
468 | [8]: https://david-dm.org/ljharb/qs?type=dev
|
469 | [9]: https://ci.testling.com/ljharb/qs.png
|
470 | [10]: https://ci.testling.com/ljharb/qs
|
471 | [11]: https://nodei.co/npm/qs.png?downloads=true&stars=true
|
472 | [license-image]: http://img.shields.io/npm/l/qs.svg
|
473 | [license-url]: LICENSE
|
474 | [downloads-image]: http://img.shields.io/npm/dm/qs.svg
|
475 | [downloads-url]: http://npm-stat.com/charts.html?package=qs
|