UNPKG

23.2 kBMarkdownView Raw
1
2# SuperAgent
3
4 SuperAgent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!
5
6 request
7 .post('/api/pet')
8 .send({ name: 'Manny', species: 'cat' })
9 .set('X-API-Key', 'foobar')
10 .set('Accept', 'application/json')
11 .end(function(err, res){
12 if (err || !res.ok) {
13 alert('Oh no! error');
14 } else {
15 alert('yay got ' + JSON.stringify(res.body));
16 }
17 });
18
19## Test documentation
20
21 The following [test documentation](docs/test.html) was generated with [Mocha's](http://mochajs.org/) "doc" reporter, and directly reflects the test suite. This provides an additional source of documentation.
22
23## Request basics
24
25 A request can be initiated by invoking the appropriate method on the `request` object, then calling `.end()` to send the request. For example a simple __GET__ request:
26
27 request
28 .get('/search')
29 .end(function(err, res){
30
31 });
32
33 A method string may also be passed:
34
35 request('GET', '/search').end(callback);
36
37ES6 promises are supported. *Instead* of `.end()` you can call `.then()`:
38
39 request('GET', '/search').then(success, failure);
40
41 The __Node__ client may also provide absolute URLs. In browsers absolute URLs won't work unless the server implements [CORS](#cors).
42
43 request
44 .get('http://example.com/search')
45 .end(function(err, res){
46
47 });
48
49 The __Node__ client supports making requests to [Unix Domain Sockets](http://en.wikipedia.org/wiki/Unix_domain_socket):
50
51 // pattern: https?+unix://SOCKET_PATH/REQUEST_PATH
52 // Use `%2F` as `/` in SOCKET_PATH
53 request
54 .get('http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search')
55 .end(function(err, res){
56
57 });
58
59 __DELETE__, __HEAD__, __PATCH__, __POST__, and __PUT__ requests can also be used, simply change the method name:
60
61 request
62 .head('/favicon.ico')
63 .end(function(err, res){
64
65 });
66
67 __DELETE__ can be also called as `.del()` for compatibility with old IE where `delete` is a reserved word.
68
69 The HTTP method defaults to __GET__, so if you wish, the following is valid:
70
71 request('/search', function(err, res){
72
73 });
74
75## Setting header fields
76
77 Setting header fields is simple, invoke `.set()` with a field name and value:
78
79 request
80 .get('/search')
81 .set('API-Key', 'foobar')
82 .set('Accept', 'application/json')
83 .end(callback);
84
85 You may also pass an object to set several fields in a single call:
86
87 request
88 .get('/search')
89 .set({ 'API-Key': 'foobar', Accept: 'application/json' })
90 .end(callback);
91
92## `GET` requests
93
94 The `.query()` method accepts objects, which when used with the __GET__ method will form a query-string. The following will produce the path `/search?query=Manny&range=1..5&order=desc`.
95
96 request
97 .get('/search')
98 .query({ query: 'Manny' })
99 .query({ range: '1..5' })
100 .query({ order: 'desc' })
101 .end(function(err, res){
102
103 });
104
105 Or as a single object:
106
107 request
108 .get('/search')
109 .query({ query: 'Manny', range: '1..5', order: 'desc' })
110 .end(function(err, res){
111
112 });
113
114 The `.query()` method accepts strings as well:
115
116 request
117 .get('/querystring')
118 .query('search=Manny&range=1..5')
119 .end(function(err, res){
120
121 });
122
123 Or joined:
124
125 request
126 .get('/querystring')
127 .query('search=Manny')
128 .query('range=1..5')
129 .end(function(err, res){
130
131 });
132
133## `HEAD` requests
134
135You can also use the `.query()` method for HEAD requests. The following will produce the path `/users?email=joe@smith.com`.
136
137 request
138 .head('/users')
139 .query({ email: 'joe@smith.com' })
140 .end(function(err, res){
141
142 });
143
144## `POST` / `PUT` requests
145
146 A typical JSON __POST__ request might look a little like the following, where we set the Content-Type header field appropriately, and "write" some data, in this case just a JSON string.
147
148 request.post('/user')
149 .set('Content-Type', 'application/json')
150 .send('{"name":"tj","pet":"tobi"}')
151 .end(callback)
152
153 Since JSON is undoubtably the most common, it's the _default_! The following example is equivalent to the previous.
154
155 request.post('/user')
156 .send({ name: 'tj', pet: 'tobi' })
157 .end(callback)
158
159 Or using multiple `.send()` calls:
160
161 request.post('/user')
162 .send({ name: 'tj' })
163 .send({ pet: 'tobi' })
164 .end(callback)
165
166 By default sending strings will set the `Content-Type` to `application/x-www-form-urlencoded`,
167 multiple calls will be concatenated with `&`, here resulting in `name=tj&pet=tobi`:
168
169 request.post('/user')
170 .send('name=tj')
171 .send('pet=tobi')
172 .end(callback);
173
174 SuperAgent formats are extensible, however by default "json" and "form" are supported. To send the data as `application/x-www-form-urlencoded` simply invoke `.type()` with "form", where the default is "json". This request will __POST__ the body "name=tj&pet=tobi".
175
176 request.post('/user')
177 .type('form')
178 .send({ name: 'tj' })
179 .send({ pet: 'tobi' })
180 .end(callback)
181
182## Setting the `Content-Type`
183
184 The obvious solution is to use the `.set()` method:
185
186 request.post('/user')
187 .set('Content-Type', 'application/json')
188
189 As a short-hand the `.type()` method is also available, accepting
190 the canonicalized MIME type name complete with type/subtype, or
191 simply the extension name such as "xml", "json", "png", etc:
192
193 request.post('/user')
194 .type('application/json')
195
196 request.post('/user')
197 .type('json')
198
199 request.post('/user')
200 .type('png')
201
202## Serializing request body
203
204SuperAgent will automatically serialize JSON and forms. If you want to send the payload in a custom format, you can replace the built-in serialization with `.serialize()` method.
205
206## Retrying requests
207
208When given the `.retry()` method, SuperAgent will automatically retry requests, if they fail in a way that is transient or could be due to a flaky Internet connection. `.retry()` takes an optional argument which is the maximum number of times to retry failed requests; the default is 3 times.
209
210 request
211 .get('http://example.com/search')
212 .retry(2)
213 .end(callback);
214
215## Setting Accept
216
217In a similar fashion to the `.type()` method it is also possible to set the `Accept` header via the short hand method `.accept()`. Which references `request.types` as well allowing you to specify either the full canonicalized MIME type name as `type/subtype`, or the extension suffix form as "xml", "json", "png", etc. for convenience:
218
219 request.get('/user')
220 .accept('application/json')
221
222 request.get('/user')
223 .accept('json')
224
225 request.post('/user')
226 .accept('png')
227
228### Facebook and Accept JSON
229
230If you are calling Facebook's API, be sure to send an `Accept: application/json` header in your request. If you don't do this, Facebook will respond with `Content-Type: text/javascript; charset=UTF-8`, which SuperAgent will not parse and thus `res.body` will be undefined. You can do this with either `req.accept('json')` or `req.header('Accept', 'application/json')`. See [issue 1078](https://github.com/visionmedia/superagent/issues/1078) for details.
231
232## Query strings
233
234 `res.query(obj)` is a method which may be used to build up a query-string. For example populating `?format=json&dest=/login` on a __POST__:
235
236 request
237 .post('/')
238 .query({ format: 'json' })
239 .query({ dest: '/login' })
240 .send({ post: 'data', here: 'wahoo' })
241 .end(callback);
242
243 By default the query string is not assembled in any particular order. An asciibetically-sorted query string can be enabled with `req.sortQuery()`. You may also provide a custom sorting comparison function with `req.sortQuery(myComparisonFn)`. The comparison function should take 2 arguments and return a negative/zero/positive integer.
244
245```js
246 // default order
247 request.get('/user')
248 .query('name=Nick')
249 .query('search=Manny')
250 .sortQuery()
251 .end(callback)
252
253 // customized sort function
254 request.get('/user')
255 .query('name=Nick')
256 .query('search=Manny')
257 .sortQuery(function(a, b){
258 return a.length - b.length;
259 })
260 .end(callback)
261```
262
263## TLS options
264
265In Node.js SuperAgent supports methods to configure HTTPS requests:
266
267- `.ca()`: Set the CA certificate(s) to trust
268- `.cert()`: Set the client certificate chain(s)
269- `.key()`: Set the client private key(s)
270- `.pfx()`: Set the client PFX or PKCS12 encoded private key and certificate chain
271
272For more information, see Node.js [https.request docs](https://nodejs.org/api/https.html#https_https_request_options_callback).
273
274```js
275var key = fs.readFileSync('key.pem'),
276 cert = fs.readFileSync('cert.pem');
277
278request
279 .post('/client-auth')
280 .key(key)
281 .cert(cert)
282 .end(callback);
283```
284
285```js
286var ca = fs.readFileSync('ca.cert.pem');
287
288request
289 .post('https://localhost/private-ca-server')
290 .ca(ca)
291 .end(callback);
292```
293
294## Parsing response bodies
295
296 SuperAgent will parse known response-body data for you, currently supporting `application/x-www-form-urlencoded`, `application/json`, and `multipart/form-data`.
297
298 You can set a custom parser (that takes precedence over built-in parsers) with the `.buffer(true).parse(fn)` method. If response buffering is not enabled (`.buffer(false)`) then the `response` event will be emitted without waiting for the body parser to finish, so `response.body` won't be available.
299
300### JSON / Urlencoded
301
302 The property `res.body` is the parsed object, for example if a request responded with the JSON string '{"user":{"name":"tobi"}}', `res.body.user.name` would be "tobi". Likewise the x-www-form-urlencoded value of "user[name]=tobi" would yield the same result. Only one level of nesting is supported. If you need more complex data, send JSON instead.
303
304 Arrays are sent by repeating the key. `.send({color: ['red','blue']})` sends `color=red&color=blue`. If you want the array keys to contain `[]` in their name, you must add it yourself, as SuperAgent doesn't add it automatically.
305
306### Multipart
307
308 The Node client supports _multipart/form-data_ via the [Formidable](https://github.com/felixge/node-formidable) module. When parsing multipart responses, the object `res.files` is also available to you. Suppose for example a request responds with the following multipart body:
309
310 --whoop
311 Content-Disposition: attachment; name="image"; filename="tobi.png"
312 Content-Type: image/png
313
314 ... data here ...
315 --whoop
316 Content-Disposition: form-data; name="name"
317 Content-Type: text/plain
318
319 Tobi
320 --whoop--
321
322 You would have the values `res.body.name` provided as "Tobi", and `res.files.image` as a `File` object containing the path on disk, filename, and other properties.
323
324### Binary
325
326In browsers, you may use `.responseType('blob')` to request handling of binary response bodies. This API is unnecessary when running in node.js. The supported argument values for this method are
327
328- `'blob'` passed through to the XmlHTTPRequest `responseType` property
329- `'arraybuffer'` passed through to the XmlHTTPRequest `responseType` property
330
331```js
332req.get('/binary.data')
333 .responseType('blob')
334 .end(function (error, res) {
335 // res.body will be a browser native Blob type here
336 });
337```
338
339For more information, see the Mozilla Developer Network [xhr.responseType docs](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType).
340
341## Response properties
342
343 Many helpful flags and properties are set on the `Response` object, ranging from the response text, parsed response body, header fields, status flags and more.
344
345### Response text
346
347 The `res.text` property contains the unparsed response body string. This
348 property is always present for the client API, and only when the mime type
349 matches "text/*", "*/json", or "x-www-form-urlencoded" by default for node. The
350 reasoning is to conserve memory, as buffering text of large bodies such as multipart files or images is extremely inefficient.
351
352 To force buffering see the "Buffering responses" section.
353
354### Response body
355
356 Much like SuperAgent can auto-serialize request data, it can also automatically parse it. When a parser is defined for the Content-Type, it is parsed, which by default includes "application/json" and "application/x-www-form-urlencoded". The parsed object is then available via `res.body`.
357
358### Response header fields
359
360 The `res.header` contains an object of parsed header fields, lowercasing field names much like node does. For example `res.header['content-length']`.
361
362### Response Content-Type
363
364 The Content-Type response header is special-cased, providing `res.type`, which is void of the charset (if any). For example the Content-Type of "text/html; charset=utf8" will provide "text/html" as `res.type`, and the `res.charset` property would then contain "utf8".
365
366### Response status
367
368 The response status flags help determine if the request was a success, among other useful information, making SuperAgent ideal for interacting with RESTful web services. These flags are currently defined as:
369
370 var type = status / 100 | 0;
371
372 // status / class
373 res.status = status;
374 res.statusType = type;
375
376 // basics
377 res.info = 1 == type;
378 res.ok = 2 == type;
379 res.clientError = 4 == type;
380 res.serverError = 5 == type;
381 res.error = 4 == type || 5 == type;
382
383 // sugar
384 res.accepted = 202 == status;
385 res.noContent = 204 == status || 1223 == status;
386 res.badRequest = 400 == status;
387 res.unauthorized = 401 == status;
388 res.notAcceptable = 406 == status;
389 res.notFound = 404 == status;
390 res.forbidden = 403 == status;
391
392## Aborting requests
393
394 To abort requests simply invoke the `req.abort()` method.
395
396## Timeouts
397
398Sometimes networks and servers get "stuck" and never respond after accepting a request. Set timeouts to avoid requests waiting forever.
399
400 * `req.timeout({deadline:ms})` or `req.timeout(ms)` (where `ms` is a number of milliseconds > 0) sets a deadline for the entire request (including all redirects) to complete. If the response isn't fully downloaded within that time, the request will be aborted.
401
402 * `req.timeout({response:ms})` sets maximum time to wait for the first byte to arrive from the server, but it does not limit how long the entire download can take. Response timeout should be a few seconds longer than just the time it takes server to respond, because it also includes time to make DNS lookup, TCP/IP and TLS connections.
403
404You should use both `deadline` and `response` timeouts. This way you can use a short response timeout to detect unresponsive networks quickly, and a long deadline to give time for downloads on slow, but reliable, networks.
405
406 request
407 .get('/big-file?network=slow')
408 .timeout({
409 response: 5000, // Wait 5 seconds for the server to start sending,
410 deadline: 60000, // but allow 1 minute for the file to finish loading.
411 })
412 .end(function(err, res){
413 if (err.timeout) { /* timed out! */ }
414 });
415
416Timeout errors have a `.timeout` property.
417
418## Authentication
419
420 In both Node and browsers auth available via the `.auth()` method:
421
422 request
423 .get('http://local')
424 .auth('tobi', 'learnboost')
425 .end(callback);
426
427
428 In the _Node_ client Basic auth can be in the URL as "user:pass":
429
430 request.get('http://tobi:learnboost@local').end(callback);
431
432 By default only `Basic` auth is used. In browser you can add `{type:'auto'}` to enable all methods built-in in the browser (Digest, NTLM, etc.):
433
434 request.auth('digest', 'secret', {type:'auto'})
435
436## Following redirects
437
438 By default up to 5 redirects will be followed, however you may specify this with the `res.redirects(n)` method:
439
440 request
441 .get('/some.png')
442 .redirects(2)
443 .end(callback);
444
445## Preserving cookies
446
447 In Node SuperAgent does not save cookies by default, but you can use the `.agent()` method to create a copy of SuperAgent that saves cookies. Each copy has a separate cookie jar.
448
449 const agent = request.agent();
450 agent
451 .post('/login')
452 .then(() => {
453 return agent.get('/cookied-page');
454 });
455
456 In browsers cookies are managed automatically by the browser, and there is no `.agent()` method.
457
458## Piping data
459
460 The Node client allows you to pipe data to and from the request. For example piping a file's contents as the request:
461
462 const request = require('superagent');
463 const fs = require('fs');
464
465 const stream = fs.createReadStream('path/to/my.json');
466 const req = request.post('/somewhere');
467 req.type('json');
468 stream.pipe(req);
469
470 Or piping the response to a file:
471
472 const stream = fs.createWriteStream('path/to/my.json');
473 const req = request.get('/some.json');
474 req.pipe(stream);
475
476## Multipart requests
477
478 SuperAgent is also great for _building_ multipart requests for which it provides methods `.attach()` and `.field()`.
479
480### Attaching files
481
482 As mentioned a higher-level API is also provided, in the form of `.attach(name, [path], [filename])` and `.field(name, value)`/`.field(object)`. Attaching several files is simple, you can also provide a custom filename for the attachment, otherwise the basename of the attached file is used.
483
484 request
485 .post('/upload')
486 .attach('avatar', 'path/to/tobi.png', 'user.png')
487 .attach('image', 'path/to/loki.png')
488 .attach('file', 'path/to/jane.png')
489 .end(callback);
490
491### Field values
492
493 Much like form fields in HTML, you can set field values with the `.field(name, value)` method. Suppose you want to upload a few images with your name and email, your request might look something like this:
494
495 request
496 .post('/upload')
497 .field('user[name]', 'Tobi')
498 .field('user[email]', 'tobi@learnboost.com')
499 .field('friends[]', ['loki', 'jane'])
500 .attach('image', 'path/to/tobi.png')
501 .end(callback);
502
503## Compression
504
505 The node client supports compressed responses, best of all, you don't have to do anything! It just works.
506
507## Buffering responses
508
509 To force buffering of response bodies as `res.text` you may invoke `req.buffer()`. To undo the default of buffering for text responses such
510 as "text/plain", "text/html" etc you may invoke `req.buffer(false)`.
511
512 When buffered the `res.buffered` flag is provided, you may use this to
513 handle both buffered and unbuffered responses in the same callback.
514
515## CORS
516
517 For security reasons, browsers will block cross-origin requests unless the server opts-in using CORS headers. Browsers will also make extra __OPTIONS__ requests to check what HTTP headers and methods are allowed by the server. [Read more about CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS).
518
519 The `.withCredentials()` method enables the ability to send cookies
520 from the origin, however only when `Access-Control-Allow-Origin` is _not_ a wildcard ("*"), and `Access-Control-Allow-Credentials` is "true".
521
522 request
523 .get('http://api.example.com:4001/')
524 .withCredentials()
525 .then(function(res){
526 assert.equal(200, res.status);
527 assert.equal('tobi', res.text);
528 })
529
530## Error handling
531
532Your callback function will always be passed two arguments: error and response. If no error occurred, the first argument will be null:
533
534 request
535 .post('/upload')
536 .attach('image', 'path/to/tobi.png')
537 .end(function(err, res){
538
539 });
540
541An "error" event is also emitted, with you can listen for:
542
543 request
544 .post('/upload')
545 .attach('image', 'path/to/tobi.png')
546 .on('error', handle)
547 .end(function(err, res){
548
549 });
550
551 Note that a 4xx or 5xx response with super agent **are** considered an error by default. For example if you get a 500 or 403 response, this status information will be available via `err.status`. Errors from such responses also contain an `err.response` field with all of the properties mentioned in "[Response properties](#response-properties)". The library behaves in this way to handle the common case of wanting success responses and treating HTTP error status codes as errors while still allowing for custom logic around specific error conditions.
552
553 Network failures, timeouts, and other errors that produce no response will contain no `err.status` or `err.response` fields.
554
555 If you wish to handle 404 or other HTTP error responses, you can query the `err.status` property.
556 When an HTTP error occurs (4xx or 5xx response) the `res.error` property is an `Error` object,
557 this allows you to perform checks such as:
558
559 if (err && err.status === 404) {
560 alert('oh no ' + res.body.message);
561 }
562 else if (err) {
563 // all other error types we handle generically
564 }
565
566Alternatively, you can use the `.ok(callback)` method to decide whether a response is an error or not. The callback to the `ok` function gets a response and returns `true` if the response should be interpreted as success.
567
568 request.get('/404')
569 .ok(res => res.status < 500)
570 .then(response => {
571 // reads 404 page as a successful response
572 })
573
574## Progress tracking
575
576SuperAgent fires `progress` events on upload and download of large files.
577
578 request.post(url)
579 .attach(file)
580 .on('progress', event => {
581 /* the event is:
582 {
583 direction: "upload" or "download"
584 percent: 0 to 100 // may be missing if file size is unknown
585 total: // total file size, may be missing
586 loaded: // bytes downloaded or uploaded so far
587 } */
588 })
589 .end()
590
591## Promise and Generator support
592
593SuperAgent's request is a "thenable" object that's compatible with JavaScript promises and `async`/`await` syntax. Do not call `.end()` if you're using promises.
594
595Libraries like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa) can `yield` on any SuperAgent method:
596
597 const req = request
598 .get('http://local')
599 .auth('tobi', 'learnboost');
600 const res = yield req;
601
602Note that SuperAgent expects the global `Promise` object to be present. You'll need a polyfill to use promises in Internet Explorer or Node.js 0.10.
603
604## Browser and node versions
605
606SuperAgent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.
607
608If want to use WebPack to compile code for Node.JS, you *must* specify [node target](webpack.github.io/docs/configuration.html#target) in its configuration.
609
610### Using browser version in electron
611
612[Electron](http://electron.atom.io/) developers report if you would prefer to use the browser version of SuperAgent instead of the Node version, you can `require('superagent/superagent')`. Your requests will now show up in the Chrome developer tools Network tab. Note this environment is not covered by automated test suite and not officially supported.