UNPKG

19.6 kBMarkdownView Raw
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
11A querystring parsing and stringifying library with some added security.
12
13Lead Maintainer: [Jordan Harband](https://github.com/ljharb)
14
15The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
16
17## Usage
18
19```javascript
20var qs = require('qs');
21var assert = require('assert');
22
23var obj = qs.parse('a=c');
24assert.deepEqual(obj, { a: 'c' });
25
26var str = qs.stringify(obj);
27assert.equal(str, 'a=c');
28```
29
30### Parsing Objects
31
32[](#preventEval)
33```javascript
34qs.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 `[]`.
38For example, the string `'foo[bar]=baz'` converts to:
39
40```javascript
41assert.deepEqual(qs.parse('foo[bar]=baz'), {
42 foo: {
43 bar: 'baz'
44 }
45});
46```
47
48When 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
51var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
52assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
53```
54
55By 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
58var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
59assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } });
60```
61
62URI encoded strings work too:
63
64```javascript
65assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
66 a: { b: 'c' }
67});
68```
69
70You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
71
72```javascript
73assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
74 foo: {
75 bar: {
76 baz: 'foobarbaz'
77 }
78 }
79});
80```
81
82By 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
86var 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};
101var string = 'a[b][c][d][e][f][g][h][i]=j';
102assert.deepEqual(qs.parse(string), expected);
103```
104
105This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`:
106
107```javascript
108var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
109assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
110```
111
112The 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
114For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
115
116```javascript
117var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
118assert.deepEqual(limited, { a: 'b' });
119```
120
121To bypass the leading question mark, use `ignoreQueryPrefix`:
122
123```javascript
124var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
125assert.deepEqual(prefixed, { a: 'b', c: 'd' });
126```
127
128An optional delimiter can also be passed:
129
130```javascript
131var delimited = qs.parse('a=b;c=d', { delimiter: ';' });
132assert.deepEqual(delimited, { a: 'b', c: 'd' });
133```
134
135Delimiters can be a regular expression too:
136
137```javascript
138var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
139assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' });
140```
141
142Option `allowDots` can be used to enable dot notation:
143
144```javascript
145var withDots = qs.parse('a.b=c', { allowDots: true });
146assert.deepEqual(withDots, { a: { b: 'c' } });
147```
148
149If you have to deal with legacy browsers or services, there's
150also support for decoding percent-encoded octets as iso-8859-1:
151
152```javascript
153var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });
154assert.deepEqual(oldCharset, { a: '§' });
155```
156
157Some services add an initial `utf8=✓` value to forms so that old
158Internet Explorer versions are more likely to submit the form as
159utf-8. Additionally, the server can check the value against wrong
160encodings of the checkmark character and detect that a query string
161or `application/x-www-form-urlencoded` body was *not* sent as
162utf-8, eg. if the form had an `accept-charset` parameter or the
163containing page had a different character set.
164
165**qs** supports this mechanism via the `charsetSentinel` option.
166If specified, the `utf8` parameter will be omitted from the
167returned object. It will be used to switch to `iso-8859-1`/`utf-8`
168mode depending on how the checkmark is encoded.
169
170**Important**: When you specify both the `charset` option and the
171`charsetSentinel` option, the `charset` will be overridden when
172the request contains a `utf8` parameter from which the actual
173charset can be deduced. In that sense the `charset` will behave
174as the default charset rather than the authoritative charset.
175
176```javascript
177var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', {
178 charset: 'iso-8859-1',
179 charsetSentinel: true
180});
181assert.deepEqual(detectedAsUtf8, { a: 'ø' });
182
183// Browsers encode the checkmark as &#10003; when submitting as iso-8859-1:
184var detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', {
185 charset: 'utf-8',
186 charsetSentinel: true
187});
188assert.deepEqual(detectedAsIso8859_1, { a: 'ø' });
189```
190
191If you want to decode the `&#...;` syntax to the actual character,
192you can specify the `interpretNumericEntities` option as well:
193
194```javascript
195var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
196 charset: 'iso-8859-1',
197 interpretNumericEntities: true
198});
199assert.deepEqual(detectedAsIso8859_1, { a: '☺' });
200```
201
202It also works when the charset has been detected in `charsetSentinel`
203mode.
204
205### Parsing Arrays
206
207**qs** can also parse arrays using a similar `[]` notation:
208
209```javascript
210var withArray = qs.parse('a[]=b&a[]=c');
211assert.deepEqual(withArray, { a: ['b', 'c'] });
212```
213
214You may specify an index as well:
215
216```javascript
217var withIndexes = qs.parse('a[1]=c&a[0]=b');
218assert.deepEqual(withIndexes, { a: ['b', 'c'] });
219```
220
221Note 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
222to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving
223their order:
224
225```javascript
226var noSparse = qs.parse('a[1]=b&a[15]=c');
227assert.deepEqual(noSparse, { a: ['b', 'c'] });
228```
229
230Note that an empty string is also a value, and will be preserved:
231
232```javascript
233var withEmptyString = qs.parse('a[]=&a[]=b');
234assert.deepEqual(withEmptyString, { a: ['', 'b'] });
235
236var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
237assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
238```
239
240**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
241instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
242
243```javascript
244var withMaxIndex = qs.parse('a[100]=b');
245assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });
246```
247
248This limit can be overridden by passing an `arrayLimit` option:
249
250```javascript
251var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
252assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
253```
254
255To disable array parsing entirely, set `parseArrays` to `false`.
256
257```javascript
258var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
259assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });
260```
261
262If you mix notations, **qs** will merge the two items into an object:
263
264```javascript
265var mixedNotation = qs.parse('a[0]=b&a[b]=c');
266assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });
267```
268
269You can also create arrays of objects:
270
271```javascript
272var arraysOfObjects = qs.parse('a[][b]=c');
273assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });
274```
275
276Some people use comma to join array, **qs** can parse it:
277```javascript
278var arraysOfObjects = qs.parse('a=b,c', { comma: true })
279assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
280```
281(_this cannot convert nested objects, such as `a={b:1},{c:d}`_)
282
283### Stringifying
284
285[](#preventEval)
286```javascript
287qs.stringify(object, [options]);
288```
289
290When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:
291
292```javascript
293assert.equal(qs.stringify({ a: 'b' }), 'a=b');
294assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
295```
296
297This encoding can be disabled by setting the `encode` option to `false`:
298
299```javascript
300var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
301assert.equal(unencoded, 'a[b]=c');
302```
303
304Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:
305```javascript
306var encodedValues = qs.stringify(
307 { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
308 { encodeValuesOnly: true }
309);
310assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
311```
312
313This encoding can also be replaced by a custom encoding method set as `encoder` option:
314
315```javascript
316var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
317 // Passed in values `a`, `b`, `c`
318 return // Return encoded string
319}})
320```
321
322_(Note: the `encoder` option does not apply if `encode` is `false`)_
323
324Analogue to the `encoder` there is a `decoder` option for `parse` to override decoding of properties and values:
325
326```javascript
327var decoded = qs.parse('x=z', { decoder: function (str) {
328 // Passed in values `x`, `z`
329 return // Return decoded string
330}})
331```
332
333You can encode keys and values using different logic by using the type argument provided to the encoder:
334
335```javascript
336var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
337 if (type === 'key') {
338 return // Encoded key
339 } else if (type === 'value') {
340 return // Encoded value
341 }
342}})
343```
344
345The type argument is also provided to the decoder:
346
347```javascript
348var decoded = qs.parse('x=z', { decoder: function (str, defaultEncoder, charset, type) {
349 if (type === 'key') {
350 return // Decoded key
351 } else if (type === 'value') {
352 return // Decoded value
353 }
354}})
355```
356
357Examples 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.
358
359When arrays are stringified, by default they are given explicit indices:
360
361```javascript
362qs.stringify({ a: ['b', 'c', 'd'] });
363// 'a[0]=b&a[1]=c&a[2]=d'
364```
365
366You may override this by setting the `indices` option to `false`:
367
368```javascript
369qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
370// 'a=b&a=c&a=d'
371```
372
373You may use the `arrayFormat` option to specify the format of the output array:
374
375```javascript
376qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
377// 'a[0]=b&a[1]=c'
378qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
379// 'a[]=b&a[]=c'
380qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
381// 'a=b&a=c'
382qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
383// 'a=b,c'
384```
385
386When objects are stringified, by default they use bracket notation:
387
388```javascript
389qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
390// 'a[b][c]=d&a[b][e]=f'
391```
392
393You may override this to use dot notation by setting the `allowDots` option to `true`:
394
395```javascript
396qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
397// 'a.b.c=d&a.b.e=f'
398```
399
400Empty strings and null values will omit the value, but the equals sign (=) remains in place:
401
402```javascript
403assert.equal(qs.stringify({ a: '' }), 'a=');
404```
405
406Key with no values (such as an empty object or array) will return nothing:
407
408```javascript
409assert.equal(qs.stringify({ a: [] }), '');
410assert.equal(qs.stringify({ a: {} }), '');
411assert.equal(qs.stringify({ a: [{}] }), '');
412assert.equal(qs.stringify({ a: { b: []} }), '');
413assert.equal(qs.stringify({ a: { b: {}} }), '');
414```
415
416Properties that are set to `undefined` will be omitted entirely:
417
418```javascript
419assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
420```
421
422The query string may optionally be prepended with a question mark:
423
424```javascript
425assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
426```
427
428The delimiter may be overridden with stringify as well:
429
430```javascript
431assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
432```
433
434If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option:
435
436```javascript
437var date = new Date(7);
438assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
439assert.equal(
440 qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
441 'a=7'
442);
443```
444
445You may use the `sort` option to affect the order of parameter keys:
446
447```javascript
448function alphabeticalSort(a, b) {
449 return a.localeCompare(b);
450}
451assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
452```
453
454Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
455If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
456pass an array, it will be used to select properties and array indices for stringification:
457
458```javascript
459function filterFunc(prefix, value) {
460 if (prefix == 'b') {
461 // Return an `undefined` value to omit a property.
462 return;
463 }
464 if (prefix == 'e[f]') {
465 return value.getTime();
466 }
467 if (prefix == 'e[g][0]') {
468 return value * 2;
469 }
470 return value;
471}
472qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
473// 'a=b&c=d&e[f]=123&e[g][0]=4'
474qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });
475// 'a=b&e=f'
476qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
477// 'a[0]=b&a[2]=d'
478```
479
480### Handling of `null` values
481
482By default, `null` values are treated like empty strings:
483
484```javascript
485var withNull = qs.stringify({ a: null, b: '' });
486assert.equal(withNull, 'a=&b=');
487```
488
489Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
490
491```javascript
492var equalsInsensitive = qs.parse('a&b=');
493assert.deepEqual(equalsInsensitive, { a: '', b: '' });
494```
495
496To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
497values have no `=` sign:
498
499```javascript
500var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
501assert.equal(strictNull, 'a&b=');
502```
503
504To parse values without `=` back to `null` use the `strictNullHandling` flag:
505
506```javascript
507var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
508assert.deepEqual(parsedStrictNull, { a: null, b: '' });
509```
510
511To completely skip rendering keys with `null` values, use the `skipNulls` flag:
512
513```javascript
514var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
515assert.equal(nullsSkipped, 'a=b');
516```
517
518If you're communicating with legacy systems, you can switch to `iso-8859-1`
519using the `charset` option:
520
521```javascript
522var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
523assert.equal(iso, '%E6=%E6');
524```
525
526Characters that don't exist in `iso-8859-1` will be converted to numeric
527entities, similar to what browsers do:
528
529```javascript
530var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
531assert.equal(numeric, 'a=%26%239786%3B');
532```
533
534You can use the `charsetSentinel` option to announce the character by
535including an `utf8=✓` parameter with the proper encoding if the checkmark,
536similar to what Ruby on Rails and others do when submitting forms.
537
538```javascript
539var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
540assert.equal(sentinel, 'utf8=%E2%9C%93&a=%E2%98%BA');
541
542var isoSentinel = qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' });
543assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');
544```
545
546### Dealing with special character sets
547
548By default the encoding and decoding of characters is done in `utf-8`,
549and `iso-8859-1` support is also built in via the `charset` parameter.
550
551If you wish to encode querystrings to a different character set (i.e.
552[Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
553[`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
554
555```javascript
556var encoder = require('qs-iconv/encoder')('shift_jis');
557var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });
558assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I');
559```
560
561This also works for decoding of query strings:
562
563```javascript
564var decoder = require('qs-iconv/decoder')('shift_jis');
565var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });
566assert.deepEqual(obj, { a: 'こんにちは!' });
567```
568
569### RFC 3986 and RFC 1738 space encoding
570
571RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible.
572In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'.
573
574```
575assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
576assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
577assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
578```
579
580## Security
581
582Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
583
584## qs for enterprise
585
586Available as part of the Tidelift Subscription
587
588The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
589
590[1]: https://npmjs.org/package/qs
591[2]: http://versionbadg.es/ljharb/qs.svg
592[3]: https://api.travis-ci.org/ljharb/qs.svg
593[4]: https://travis-ci.org/ljharb/qs
594[5]: https://david-dm.org/ljharb/qs.svg
595[6]: https://david-dm.org/ljharb/qs
596[7]: https://david-dm.org/ljharb/qs/dev-status.svg
597[8]: https://david-dm.org/ljharb/qs?type=dev
598[9]: https://ci.testling.com/ljharb/qs.png
599[10]: https://ci.testling.com/ljharb/qs
600[11]: https://nodei.co/npm/qs.png?downloads=true&stars=true
601[license-image]: http://img.shields.io/npm/l/qs.svg
602[license-url]: LICENSE
603[downloads-image]: http://img.shields.io/npm/dm/qs.svg
604[downloads-url]: http://npm-stat.com/charts.html?package=qs