UNPKG

19.8 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
230You may also use `allowSparse` option to parse sparse arrays:
231
232```javascript
233var sparseArray = qs.parse('a[1]=2&a[3]=5', { allowSparse: true });
234assert.deepEqual(sparseArray, { a: [, '2', , '5'] });
235```
236
237Note that an empty string is also a value, and will be preserved:
238
239```javascript
240var withEmptyString = qs.parse('a[]=&a[]=b');
241assert.deepEqual(withEmptyString, { a: ['', 'b'] });
242
243var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
244assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
245```
246
247**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
248instead 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.
249
250```javascript
251var withMaxIndex = qs.parse('a[100]=b');
252assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });
253```
254
255This limit can be overridden by passing an `arrayLimit` option:
256
257```javascript
258var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
259assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
260```
261
262To disable array parsing entirely, set `parseArrays` to `false`.
263
264```javascript
265var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
266assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });
267```
268
269If you mix notations, **qs** will merge the two items into an object:
270
271```javascript
272var mixedNotation = qs.parse('a[0]=b&a[b]=c');
273assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });
274```
275
276You can also create arrays of objects:
277
278```javascript
279var arraysOfObjects = qs.parse('a[][b]=c');
280assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });
281```
282
283Some people use comma to join array, **qs** can parse it:
284```javascript
285var arraysOfObjects = qs.parse('a=b,c', { comma: true })
286assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
287```
288(_this cannot convert nested objects, such as `a={b:1},{c:d}`_)
289
290### Stringifying
291
292[](#preventEval)
293```javascript
294qs.stringify(object, [options]);
295```
296
297When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:
298
299```javascript
300assert.equal(qs.stringify({ a: 'b' }), 'a=b');
301assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
302```
303
304This encoding can be disabled by setting the `encode` option to `false`:
305
306```javascript
307var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
308assert.equal(unencoded, 'a[b]=c');
309```
310
311Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:
312```javascript
313var encodedValues = qs.stringify(
314 { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
315 { encodeValuesOnly: true }
316);
317assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
318```
319
320This encoding can also be replaced by a custom encoding method set as `encoder` option:
321
322```javascript
323var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
324 // Passed in values `a`, `b`, `c`
325 return // Return encoded string
326}})
327```
328
329_(Note: the `encoder` option does not apply if `encode` is `false`)_
330
331Analogue to the `encoder` there is a `decoder` option for `parse` to override decoding of properties and values:
332
333```javascript
334var decoded = qs.parse('x=z', { decoder: function (str) {
335 // Passed in values `x`, `z`
336 return // Return decoded string
337}})
338```
339
340You can encode keys and values using different logic by using the type argument provided to the encoder:
341
342```javascript
343var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
344 if (type === 'key') {
345 return // Encoded key
346 } else if (type === 'value') {
347 return // Encoded value
348 }
349}})
350```
351
352The type argument is also provided to the decoder:
353
354```javascript
355var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {
356 if (type === 'key') {
357 return // Decoded key
358 } else if (type === 'value') {
359 return // Decoded value
360 }
361}})
362```
363
364Examples 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.
365
366When arrays are stringified, by default they are given explicit indices:
367
368```javascript
369qs.stringify({ a: ['b', 'c', 'd'] });
370// 'a[0]=b&a[1]=c&a[2]=d'
371```
372
373You may override this by setting the `indices` option to `false`:
374
375```javascript
376qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
377// 'a=b&a=c&a=d'
378```
379
380You may use the `arrayFormat` option to specify the format of the output array:
381
382```javascript
383qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
384// 'a[0]=b&a[1]=c'
385qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
386// 'a[]=b&a[]=c'
387qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
388// 'a=b&a=c'
389qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
390// 'a=b,c'
391```
392
393When objects are stringified, by default they use bracket notation:
394
395```javascript
396qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
397// 'a[b][c]=d&a[b][e]=f'
398```
399
400You may override this to use dot notation by setting the `allowDots` option to `true`:
401
402```javascript
403qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
404// 'a.b.c=d&a.b.e=f'
405```
406
407Empty strings and null values will omit the value, but the equals sign (=) remains in place:
408
409```javascript
410assert.equal(qs.stringify({ a: '' }), 'a=');
411```
412
413Key with no values (such as an empty object or array) will return nothing:
414
415```javascript
416assert.equal(qs.stringify({ a: [] }), '');
417assert.equal(qs.stringify({ a: {} }), '');
418assert.equal(qs.stringify({ a: [{}] }), '');
419assert.equal(qs.stringify({ a: { b: []} }), '');
420assert.equal(qs.stringify({ a: { b: {}} }), '');
421```
422
423Properties that are set to `undefined` will be omitted entirely:
424
425```javascript
426assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
427```
428
429The query string may optionally be prepended with a question mark:
430
431```javascript
432assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
433```
434
435The delimiter may be overridden with stringify as well:
436
437```javascript
438assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
439```
440
441If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option:
442
443```javascript
444var date = new Date(7);
445assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
446assert.equal(
447 qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
448 'a=7'
449);
450```
451
452You may use the `sort` option to affect the order of parameter keys:
453
454```javascript
455function alphabeticalSort(a, b) {
456 return a.localeCompare(b);
457}
458assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
459```
460
461Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
462If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
463pass an array, it will be used to select properties and array indices for stringification:
464
465```javascript
466function filterFunc(prefix, value) {
467 if (prefix == 'b') {
468 // Return an `undefined` value to omit a property.
469 return;
470 }
471 if (prefix == 'e[f]') {
472 return value.getTime();
473 }
474 if (prefix == 'e[g][0]') {
475 return value * 2;
476 }
477 return value;
478}
479qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
480// 'a=b&c=d&e[f]=123&e[g][0]=4'
481qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });
482// 'a=b&e=f'
483qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
484// 'a[0]=b&a[2]=d'
485```
486
487### Handling of `null` values
488
489By default, `null` values are treated like empty strings:
490
491```javascript
492var withNull = qs.stringify({ a: null, b: '' });
493assert.equal(withNull, 'a=&b=');
494```
495
496Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
497
498```javascript
499var equalsInsensitive = qs.parse('a&b=');
500assert.deepEqual(equalsInsensitive, { a: '', b: '' });
501```
502
503To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
504values have no `=` sign:
505
506```javascript
507var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
508assert.equal(strictNull, 'a&b=');
509```
510
511To parse values without `=` back to `null` use the `strictNullHandling` flag:
512
513```javascript
514var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
515assert.deepEqual(parsedStrictNull, { a: null, b: '' });
516```
517
518To completely skip rendering keys with `null` values, use the `skipNulls` flag:
519
520```javascript
521var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
522assert.equal(nullsSkipped, 'a=b');
523```
524
525If you're communicating with legacy systems, you can switch to `iso-8859-1`
526using the `charset` option:
527
528```javascript
529var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
530assert.equal(iso, '%E6=%E6');
531```
532
533Characters that don't exist in `iso-8859-1` will be converted to numeric
534entities, similar to what browsers do:
535
536```javascript
537var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
538assert.equal(numeric, 'a=%26%239786%3B');
539```
540
541You can use the `charsetSentinel` option to announce the character by
542including an `utf8=✓` parameter with the proper encoding if the checkmark,
543similar to what Ruby on Rails and others do when submitting forms.
544
545```javascript
546var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
547assert.equal(sentinel, 'utf8=%E2%9C%93&a=%E2%98%BA');
548
549var isoSentinel = qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' });
550assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');
551```
552
553### Dealing with special character sets
554
555By default the encoding and decoding of characters is done in `utf-8`,
556and `iso-8859-1` support is also built in via the `charset` parameter.
557
558If you wish to encode querystrings to a different character set (i.e.
559[Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
560[`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
561
562```javascript
563var encoder = require('qs-iconv/encoder')('shift_jis');
564var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });
565assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I');
566```
567
568This also works for decoding of query strings:
569
570```javascript
571var decoder = require('qs-iconv/decoder')('shift_jis');
572var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });
573assert.deepEqual(obj, { a: 'こんにちは!' });
574```
575
576### RFC 3986 and RFC 1738 space encoding
577
578RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible.
579In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'.
580
581```
582assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
583assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
584assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
585```
586
587## Security
588
589Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
590
591## qs for enterprise
592
593Available as part of the Tidelift Subscription
594
595The 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)
596
597[1]: https://npmjs.org/package/qs
598[2]: http://versionbadg.es/ljharb/qs.svg
599[3]: https://api.travis-ci.org/ljharb/qs.svg
600[4]: https://travis-ci.org/ljharb/qs
601[5]: https://david-dm.org/ljharb/qs.svg
602[6]: https://david-dm.org/ljharb/qs
603[7]: https://david-dm.org/ljharb/qs/dev-status.svg
604[8]: https://david-dm.org/ljharb/qs?type=dev
605[9]: https://ci.testling.com/ljharb/qs.png
606[10]: https://ci.testling.com/ljharb/qs
607[11]: https://nodei.co/npm/qs.png?downloads=true&stars=true
608[license-image]: http://img.shields.io/npm/l/qs.svg
609[license-url]: LICENSE
610[downloads-image]: http://img.shields.io/npm/dm/qs.svg
611[downloads-url]: http://npm-stat.com/charts.html?package=qs