UNPKG

32.8 kBMarkdownView Raw
1<a href="http://promisesaplus.com/">
2 <img src="https://promises-aplus.github.io/promises-spec/assets/logo-small.png" align="right" alt="Promises/A+ logo" />
3</a>
4
5# Request-Promise
6
7[![Gitter](https://img.shields.io/badge/gitter-join_chat-blue.svg?style=flat-square&maxAge=2592000)](https://gitter.im/request/request-promise?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
8[![Build Status](https://img.shields.io/travis/request/request-promise/master.svg?style=flat-square&maxAge=2592000)](https://travis-ci.org/request/request-promise)
9[![Coverage Status](https://img.shields.io/coveralls/request/request-promise.svg?style=flat-square&maxAge=2592000)](https://coveralls.io/r/request/request-promise)
10[![Dependency Status](https://img.shields.io/david/request/request-promise.svg?style=flat-square&maxAge=2592000)](https://david-dm.org/request/request-promise)
11[![Known Vulnerabilities](https://snyk.io/test/npm/request-promise/badge.svg?style=flat-square&maxAge=2592000)](https://snyk.io/test/npm/request-promise)
12
13The simplified HTTP request client 'request' with Promise support. Powered by Bluebird.
14
15[Request](https://github.com/request/request) and [Bluebird](https://github.com/petkaantonov/bluebird) are pretty awesome, but I found myself using the same design pattern. Request-Promise adds a Bluebird-powered `.then(...)` method to Request call objects. By default, http response codes other than 2xx will cause the promise to be rejected. This can be overwritten by setting `options.simple = false`.
16
17Also check out the new libraries that are **very similar to `request-promise` v4**:
18- [`request-promise-native`](https://github.com/request/request-promise-native) v1 &ndash; Does not depend on Bluebird and uses native ES6 promises instead.
19- [`request-promise-any`](https://github.com/request/request-promise-any) v1 &ndash; Allows you to register any Promise library supported by [`any-promise`](https://www.npmjs.com/package/any-promise).
20
21---
22
23## Migration from v3 to v4
24
251. `request` became a peer dependency. Thus make sure that `request` is installed into your project as a direct dependency. (`npm install --save request`)
262. Continuation Local Storage is no longer supported. However, you [can get back the support](https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage) by using `request-promise-any`.
273. When you migrated your `transform` function to v3 and had to add `if (!(/^2/.test('' + response.statusCode))) { return resolveWithFullResponse ? response : body; }` you may now set the option `transform2xxOnly = true` instead.
28
29## Migration from v2 to v3
30
311. The handling of the `transform` function got overhauled. This has two effects:
32 - `StatusCodeError.response` is the transformed instead of the original response now. This error is thrown for non-2xx responses when `options.simple` is `true` (default). Please update your `transform` functions to also cover the transformation of non-2xx responses. To get the old behavior you may add `if (!(/^2/.test('' + response.statusCode))) { return resolveWithFullResponse ? response : body; }` to the first line of your `transform` functions that are used for requests with `options.simple === true`. However, you may prefer updating your `transform` functions to being able to transform 2xx as well as non-2xx responses because this decouples their implementation from the use of the `simple` option when doing requests.
33 - If a transform operation throws an error, the request will be rejected with a `TransformError`. Its `cause` attribute contains the error thrown by the transform operation. Previously, the request was rejected directly with the error thrown by the transform operation. Wrapping it into a `TransformError` makes the error handling easier.
34
352. Bluebird got updated from v2 to v3. This won't make a difference for most use cases. However, if you use advanced Promise chains starting with the Promise returned by Request-Promise, please check [Bluebird's new features and changes](http://bluebirdjs.com/docs/new-in-bluebird-3.html).
36
37---
38
39## Installation
40
41This module is installed via npm:
42
43```
44npm install --save request
45npm install --save request-promise
46```
47
48`request` is defined as a peer-dependency and thus has to be installed separately.
49
50## Cheat Sheet
51
52``` js
53var rp = require('request-promise');
54```
55
56Since `request-promise` wraps around `request` everything that works with `request` also works with `request-promise`. Also check out the [`request` docs](https://github.com/request/request) for more examples.
57
58### Crawl a webpage
59
60``` js
61rp('http://www.google.com')
62 .then(function (htmlString) {
63 // Process html...
64 })
65 .catch(function (err) {
66 // Crawling failed...
67 });
68```
69
70### Crawl a webpage better
71
72``` js
73var cheerio = require('cheerio'); // Basically jQuery for node.js
74
75var options = {
76 uri: 'http://www.google.com',
77 transform: function (body) {
78 return cheerio.load(body);
79 }
80};
81
82rp(options)
83 .then(function ($) {
84 // Process html like you would with jQuery...
85 })
86 .catch(function (err) {
87 // Crawling failed or Cheerio choked...
88 });
89```
90
91### GET something from a JSON REST API
92
93``` js
94var options = {
95 uri: 'https://api.github.com/user/repos',
96 qs: {
97 access_token: 'xxxxx xxxxx' // -> uri + '?access_token=xxxxx%20xxxxx'
98 },
99 headers: {
100 'User-Agent': 'Request-Promise'
101 },
102 json: true // Automatically parses the JSON string in the response
103};
104
105rp(options)
106 .then(function (repos) {
107 console.log('User has %d repos', repos.length);
108 })
109 .catch(function (err) {
110 // API call failed...
111 });
112```
113
114### POST data to a JSON REST API
115
116Set `option.body` to your data and `json: true` to encode the body as JSON. See below for HTML forms.
117
118``` js
119var options = {
120 method: 'POST',
121 uri: 'http://api.posttestserver.com/post',
122 body: {
123 some: 'payload'
124 },
125 json: true // Automatically stringifies the body to JSON
126};
127
128rp(options)
129 .then(function (parsedBody) {
130 // POST succeeded...
131 })
132 .catch(function (err) {
133 // POST failed...
134 });
135```
136
137### POST like HTML forms do
138
139Pass your data to `options.form` to encode the body the same way as HTML forms do:
140
141``` js
142var options = {
143 method: 'POST',
144 uri: 'http://posttestserver.com/post.php',
145 form: {
146 // Like <input type="text" name="name">
147 name: 'Josh'
148 },
149 headers: {
150 /* 'content-type': 'application/x-www-form-urlencoded' */ // Is set automatically
151 }
152};
153
154rp(options)
155 .then(function (body) {
156 // POST succeeded...
157 })
158 .catch(function (err) {
159 // POST failed...
160 });
161```
162
163If you want to include a file upload then use `options.formData`:
164
165``` js
166var options = {
167 method: 'POST',
168 uri: 'http://posttestserver.com/post.php',
169 formData: {
170 // Like <input type="text" name="name">
171 name: 'Jenn',
172 // Like <input type="file" name="file">
173 file: {
174 value: fs.createReadStream('test/test.jpg'),
175 options: {
176 filename: 'test.jpg',
177 contentType: 'image/jpg'
178 }
179 }
180 },
181 headers: {
182 /* 'content-type': 'multipart/form-data' */ // Is set automatically
183 }
184};
185
186rp(options)
187 .then(function (body) {
188 // POST succeeded...
189 })
190 .catch(function (err) {
191 // POST failed...
192 });
193```
194
195### Include a cookie
196
197``` js
198var tough = require('tough-cookie');
199
200// Easy creation of the cookie - see tough-cookie docs for details
201let cookie = new tough.Cookie({
202 key: "some_key",
203 value: "some_value",
204 domain: 'api.mydomain.com',
205 httpOnly: true,
206 maxAge: 31536000
207});
208
209// Put cookie in an jar which can be used across multiple requests
210var cookiejar = rp.jar();
211cookiejar.setCookie(cookie, 'https://api.mydomain.com');
212// ...all requests to https://api.mydomain.com will include the cookie
213
214var options = {
215 uri: 'https://api.mydomain.com/...',
216 jar: cookiejar // Tells rp to include cookies in jar that match uri
217};
218
219rp(options)
220 .then(function (body) {
221 // Request succeeded...
222 })
223 .catch(function (err) {
224 // Request failed...
225 });
226```
227
228### Get the full response instead of just the body
229
230``` js
231var options = {
232 method: 'DELETE',
233 uri: 'http://my-server/path/to/resource/1234',
234 resolveWithFullResponse: true // <--- <--- <--- <---
235};
236
237rp(options)
238 .then(function (response) {
239 console.log("DELETE succeeded with status %d", response.statusCode);
240 })
241 .catch(function (err) {
242 // Delete failed...
243 });
244```
245
246### Get a rejection only if the request failed for technical reasons
247
248``` js
249var options = {
250 uri: 'http://www.google.com/this-page-does-not-exist.html',
251 simple: false // <--- <--- <--- <---
252};
253
254rp(options)
255 .then(function (body) {
256 // Request succeeded but might as well be a 404
257 // Usually combined with resolveWithFullResponse = true to check response.statusCode
258 })
259 .catch(function (err) {
260 // Request failed due to technical reasons...
261 });
262```
263
264---
265
266**For more options checkout the [Request docs](https://github.com/request/request#requestoptions-callback).**
267
268---
269
270## API in Detail
271
272Consider Request-Promise being:
273
274- A Request object
275 - With an [identical API](https://github.com/request/request): `require('request-promise') == require('request')` so to say
276 - However, **STREAMING THE RESPONSE** (e.g. `.pipe(...)`) is **DISCOURAGED** because Request-Promise would grow the memory footprint for large requests unnecessarily high. Use the original Request library for that. You can use both libraries in the same project.
277- Plus some methods on a request call object:
278 - `rp(...).then(...)` or e.g. `rp.post(...).then(...)` which turn `rp(...)` and `rp.post(...)` into promises
279 - `rp(...).catch(...)` or e.g. `rp.del(...).catch(...)` which is the same method as provided by Bluebird promises
280 - Errors that the `request` library would pass to the callback are wrapped by `request-promise` and then passed to the catch handler. See [code example](https://github.com/request/request-promise#thenonfulfilled-onrejected) below.
281 - `rp(...).finally(...)` or e.g. `rp.put(...).finally(...)` which is the same method as provided by Bluebird promises
282 - `rp(...).cancel()` or e.g. `rp.get(...).cancel()` which cancels the request
283 - `rp(...).promise()` or e.g. `rp.head(...).promise()` which returns the underlying promise so you can access the full [Bluebird API](https://github.com/petkaantonov/bluebird/blob/master/API.md)
284- Plus some additional options:
285 - `simple = true` which is a boolean to set whether status codes other than 2xx should also reject the promise
286 - `resolveWithFullResponse = false` which is a boolean to set whether the promise should be resolved with the full response or just the response body
287 - `transform` which takes a function to transform the response into a custom value with which the promise is resolved
288 - `transform2xxOnly = false` which is a boolean to set whether the transform function is applied to all responses or only to those with a 2xx status code
289
290The objects returned by request calls like `rp(...)` or e.g. `rp.post(...)` are regular Promises/A+ compliant promises and can be assimilated by any compatible promise library.
291
292The methods `.then(...)`, `.catch(...)`, and `.finally(...)` - which you can call on the request call objects - return a full-fledged Bluebird promise. That means you have the full [Bluebird API](https://github.com/petkaantonov/bluebird/blob/master/API.md) available for further chaining. E.g.: `rp(...).then(...).spread(...)` If, however, you need a method other than `.then(...)`, `.catch(...)`, or `.finally(...)` to be **FIRST** in the chain, use `.promise()`: `rp(...).promise().bind(...).then(...)`
293
294### .then(onFulfilled, onRejected)
295
296``` js
297// As a Request user you would write:
298var request = require('request');
299
300request('http://google.com', function (err, response, body) {
301 if (err) {
302 handleError({ error: err, response: response, ... });
303 } else if (!(/^2/.test('' + response.statusCode))) { // Status Codes other than 2xx
304 handleError({ error: body, response: response, ... });
305 } else {
306 process(body);
307 }
308});
309
310// As a Request-Promise user you can now write the equivalent code:
311var rp = require('request-promise');
312
313rp('http://google.com')
314 .then(process, handleError);
315```
316
317``` js
318// The same is available for all http method shortcuts:
319request.post('http://example.com/api', function (err, response, body) { ... });
320rp.post('http://example.com/api').then(...);
321```
322
323### .catch(onRejected)
324
325``` js
326rp('http://google.com')
327 .catch(handleError);
328
329// ... is syntactical sugar for:
330
331rp('http://google.com')
332 .then(null, handleError);
333
334
335// However, this:
336rp('http://google.com')
337 .then(process)
338 .catch(handleError);
339
340// ... is safer than:
341rp('http://google.com')
342 .then(process, handleError);
343```
344
345For more info on `.then(process).catch(handleError)` versus `.then(process, handleError)`, see Bluebird docs on [promise anti-patterns](http://bluebirdjs.com/docs/anti-patterns.html#the-.then).
346
347### .finally(onFinished)
348
349``` js
350rp('http://google.com')
351 .finally(function () {
352 // This is called after the request finishes either successful or not successful.
353 });
354```
355
356### .cancel()
357
358This method cancels the request using [Bluebird's cancellation feature](http://bluebirdjs.com/docs/api/cancellation.html).
359
360When `.cancel()` is called:
361
362- the promise will neither be resolved nor rejected and
363- the request is [aborted](https://nodejs.org/dist/latest-v6.x/docs/api/http.html#http_request_abort).
364
365### .promise() - For advanced use cases
366
367In order to not pollute the Request call objects with the methods of the underlying Bluebird promise, only `.then(...)`, `.catch(...)`, and `.finally(...)` were exposed to cover most use cases. The effect is that any methods of a Bluebird promise other than `.then(...)`, `.catch(...)`, or `.finally(...)` cannot be used as the **FIRST** method in the promise chain:
368
369``` js
370// This works:
371rp('http://google.com').then(function () { ... });
372rp('http://google.com').catch(function () { ... });
373
374// This works as well since additional methods are only used AFTER the FIRST call in the chain:
375rp('http://google.com').then(function () { ... }).spread(function () { ... });
376rp('http://google.com').catch(function () { ... }).error(function () { ... });
377
378// Using additional methods as the FIRST call in the chain does not work:
379// rp('http://google.com').bind(this).then(function () { ... });
380
381// Use .promise() in these cases:
382rp('http://google.com').promise().bind(this).then(function () { ... });
383```
384
385### Fulfilled promises and the `resolveWithFullResponse` option
386
387``` js
388// Per default the body is passed to the fulfillment handler:
389rp('http://google.com')
390 .then(function (body) {
391 // Process the html of the Google web page...
392 });
393
394// The resolveWithFullResponse options allows to pass the full response:
395rp({ uri: 'http://google.com', resolveWithFullResponse: true })
396 .then(function (response) {
397 // Access response.statusCode, response.body etc.
398 });
399
400```
401
402### Rejected promises and the `simple` option
403
404``` js
405// The rejection handler is called with a reason object...
406rp('http://google.com')
407 .catch(function (reason) {
408 // Handle failed request...
409 });
410
411// ... and would be equivalent to this Request-only implementation:
412var options = { uri: 'http://google.com' };
413
414request(options, function (err, response, body) {
415 var reason;
416 if (err) {
417 reason = {
418 cause: err,
419 error: err,
420 options: options,
421 response: response
422 };
423 } else if (!(/^2/.test('' + response.statusCode))) { // Status Codes other than 2xx
424 reason = {
425 statusCode: response.statusCode,
426 error: body,
427 options: options,
428 response: response
429 };
430 }
431
432 if (reason) {
433 // Handle failed request...
434 }
435});
436
437
438// If you pass the simple option as false...
439rp({ uri: 'http://google.com', simple: false })
440 .catch(function (reason) {
441 // Handle failed request...
442 });
443
444// ... the equivalent Request-only code would be:
445request(options, function (err, response, body) {
446 if (err) {
447 var reason = {
448 cause: err,
449 error: err,
450 options: options,
451 response: response
452 };
453 // Handle failed request...
454 }
455});
456// E.g. a 404 would now fulfill the promise.
457// Combine it with resolveWithFullResponse = true to check the status code in the fulfillment handler.
458```
459
460With version 0.4 the reason objects became Error objects with identical properties to ensure backwards compatibility. These new Error types allow targeted catch blocks:
461
462``` js
463var errors = require('request-promise/errors');
464
465rp('http://google.com')
466 .catch(errors.StatusCodeError, function (reason) {
467 // The server responded with a status codes other than 2xx.
468 // Check reason.statusCode
469 })
470 .catch(errors.RequestError, function (reason) {
471 // The request failed due to technical reasons.
472 // reason.cause is the Error object Request would pass into a callback.
473 });
474```
475
476### The `transform` function
477
478You can pass a function to `options.transform` to generate a custom fulfillment value when the promise gets resolved.
479
480``` js
481// Just for fun you could reverse the response body:
482var options = {
483 uri: 'http://google.com',
484 transform: function (body, response, resolveWithFullResponse) {
485 return body.split('').reverse().join('');
486 }
487};
488
489rp(options)
490 .then(function (reversedBody) {
491 // ;D
492 });
493
494
495// However, you could also do something useful:
496var $ = require('cheerio'); // Basically jQuery for node.js
497
498function autoParse(body, response, resolveWithFullResponse) {
499 // FIXME: The content type string could contain additional values like the charset.
500 // Consider using the `content-type` library for a robust comparison.
501 if (response.headers['content-type'] === 'application/json') {
502 return JSON.parse(body);
503 } else if (response.headers['content-type'] === 'text/html') {
504 return $.load(body);
505 } else {
506 return body;
507 }
508}
509
510options.transform = autoParse;
511
512rp(options)
513 .then(function (autoParsedBody) {
514 // :)
515 });
516
517
518// You can go one step further and set the transform as the default:
519var rpap = rp.defaults({ transform: autoParse });
520
521rpap('http://google.com')
522 .then(function (autoParsedBody) {
523 // :)
524 });
525
526rpap('http://echojs.com')
527 .then(function (autoParsedBody) {
528 // =)
529 });
530```
531
532The third `resolveWithFullResponse` parameter of the transform function is equivalent to the option passed with the request. This allows to distinguish whether just the transformed body or the whole response shall be returned by the transform function:
533
534``` js
535function reverseBody(body, response, resolveWithFullResponse) {
536 response.body = response.body.split('').reverse().join('');
537 return resolveWithFullResponse ? response : response.body;
538}
539```
540
541As of Request-Promise v3 the transform function is ALWAYS executed for non-2xx responses. When `options.simple` is set to `true` (default) then non-2xx responses are rejected with a `StatusCodeError`. In this case the error contains the transformed response:
542
543``` js
544var options = {
545 uri: 'http://the-server.com/will-return/404',
546 simple: true,
547 transform: function (body, response, resolveWithFullResponse) { /* ... */ }
548};
549
550rp(options)
551 .catch(errors.StatusCodeError, function (reason) {
552 // reason.response is the transformed response
553 });
554```
555
556You may set `options.transform2xxOnly = true` to only execute the transform function for responses with a 2xx status code. For other status codes &ndash; independent of any other settings, e.g. `options.simple` &ndash; the transform function is not executed.
557
558#### Error handling
559
560If the transform operation fails (throws an error) the request will be rejected with a `TransformError`:
561
562``` js
563var errors = require('request-promise/errors');
564
565var options = {
566 uri: 'http://google.com',
567 transform: function (body, response, resolveWithFullResponse) {
568 throw new Error('Transform failed!');
569 }
570};
571
572rp(options)
573 .catch(errors.TransformError, function (reason) {
574 console.log(reason.cause.message); // => Transform failed!
575 // reason.response is the original response for which the transform operation failed
576 });
577```
578
579## Experimental Support for Continuation Local Storage
580
581Continuation Local Storage is no longer supported. However, you [can get back the support](https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage) by using `request-promise-any`.
582
583## Debugging
584
585The ways to debug the operation of Request-Promise are the same [as described](https://github.com/request/request#debugging) for Request. These are:
586
5871. Launch the node process like `NODE_DEBUG=request node script.js` (`lib,request,otherlib` works too).
5882. Set `require('request-promise').debug = true` at any time (this does the same thing as #1).
5893. Use the [request-debug module](https://github.com/nylen/request-debug) to view request and response headers and bodies. Instrument Request-Promise with `require('request-debug')(rp);`.
590
591## Mocking Request-Promise
592
593Usually you want to mock the whole request function which is returned by `require('request-promise')`. This is not possible by using a mocking library like [sinon.js](http://sinonjs.org) alone. What you need is a library that ties into the module loader and makes sure that your mock is returned whenever the tested code is calling `require('request-promise')`. [Mockery](https://github.com/mfncooper/mockery) is one of such libraries.
594
595@florianschmidt1994 kindly shared his solution:
596```javascript
597before(function (done) {
598
599 var filename = "fileForResponse";
600 mockery.enable({
601 warnOnReplace: false,
602 warnOnUnregistered: false,
603 useCleanCache: true
604 });
605
606 mockery.registerMock('request-promise', function () {
607 var response = fs.readFileSync(__dirname + '/data/' + filename, 'utf8');
608 return Bluebird.resolve(response.trim());
609 });
610
611 done();
612});
613
614after(function (done) {
615 mockery.disable();
616 mockery.deregisterAll();
617 done();
618});
619
620describe('custom test case', function () {
621 // Test some function/module/... which uses request-promise
622 // and it will always receive the predefined "fileForResponse" as data, e.g.:
623 var rp = require('request-promise');
624 rp(...).then(function(data) {
625 // ➞ data is what is in fileForResponse
626 });
627});
628```
629
630Based on that you may now build a more sophisticated mock. [Sinon.js](http://sinonjs.org) may be of help as well.
631
632## Contributing
633
634To set up your development environment:
635
6361. clone the repo to your desktop,
6372. in the shell `cd` to the main folder,
6383. hit `npm install`,
6394. hit `npm install gulp -g` if you haven't installed gulp globally yet, and
6405. run `gulp dev`. (Or run `node ./node_modules/.bin/gulp dev` if you don't want to install gulp globally.)
641
642`gulp dev` watches all source files and if you save some changes it will lint the code and execute all tests. The test coverage report can be viewed from `./coverage/lcov-report/index.html`.
643
644If you want to debug a test you should use `gulp test-without-coverage` to run all tests without obscuring the code by the test coverage instrumentation.
645
646## Change History
647
648- v4.2.5 (2019-11-03)
649 - Security fix: bumped `request-promise-core` which bumps `lodash` to `^4.17.15`. See [vulnerabilty reports](https://snyk.io/vuln/search?q=lodash&type=npm).
650 *(Thanks to @rishabh-chowdhary for reporting this in pull request [#326](https://github.com/request/promise-core/pull/326).)*
651- v4.2.4 (2019-02-14)
652 - Corrected mistakenly set `tough-cookie` version, now `^2.3.3`
653 *(Thanks to @evocateur for pointing this out.)*
654 - If you installed `request-promise@4.2.3` please make sure after the upgrade that `request` and `request-promise` use the same physical copy of `tough-cookie`.
655- v4.2.3 (2019-02-14)
656 - Using stricter `tough-cookie@~2.3.3` to avoid installing `tough-cookie@3` which introduces breaking changes
657 *(Thanks to @aomdoa for pull request [#299](https://github.com/request/request-promise/pull/299))*
658 - Security fix: bumped `lodash` to `^4.17.11`, see [vulnerabilty reports](https://snyk.io/vuln/search?q=lodash&type=npm)
659- v4.2.2 (2017-09-22)
660 - Upgraded `tough-cookie` to a version without regex DoS vulnerability
661 *(Thanks to @rouanw for [pull request #226](https://github.com/request/request-promise/pull/226))*
662- v4.2.1 (2017-05-07)
663 - Fix that allows to use `tough-cookie` for cookie creation
664 *(Thanks to @ScottyMJacobson for reporting [issue #183](https://github.com/request/request-promise/issues/183))*
665 - Added [cookie handling example](https://github.com/request/request-promise#include-a-cookie) to the cheat sheet
666 *(Thanks to @chovy and @ProfessorTom for [asking for it](https://github.com/request/request-promise/issues/79))*
667- v4.2.0 (2017-03-16)
668 - Updated `bluebird` to v3.5
669 *(Thanks to @acinader for [pull request #181](https://github.com/request/request-promise/pull/181))*
670- v4.1.1 (2016-08-08)
671 - Renamed internally used package `@request/promise-core` to `request-promise-core` because there where [too](https://github.com/request/request-promise/issues/137) [many](https://github.com/request/request-promise/issues/141) issues with the scoped package name
672 *(Thanks to @cabrinoob, @crazy4groovy, @dsandor, @KpjComp, @lorenwest, @Reisyukaku, @tehChromic, @todd for providing helpful information.)*
673- v4.1.0 (2016-07-30)
674 - Added cancellation support
675 *(Thanks to @not-an-aardvark for [pull request #123](https://github.com/request/request-promise/pull/123))*
676- v4.0.2 (2016-07-18)
677 - Fix for using with module bundlers like Webpack and Browserify
678- v4.0.1 (2016-07-17)
679 - Fixed `@request/promise-core` version for safer versioning
680- v4.0.0 (2016-07-15)
681 - **Breaking Change**: `request` is declared as a peer dependency which has to be installed separately by the user now
682 - **Breaking Change**: Dropped support for Continuation Local Storage since [`request-promise-any`](https://github.com/request/request-promise-any) can be [used](https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage) for that now
683 - Introduced the `transform2xxOnly` option to ease the breaking change regarding the new `transform` handling in v3.0.0
684 *(Thanks to @stevage for pointing out the effect of the breaking change in [issue #131](https://github.com/request/request-promise/issues/131))*
685 - Resolved issues [#65](https://github.com/request/request-promise/issues/65) and [#71](https://github.com/request/request-promise/issues/71) by publishing nearly identical libraries to support other Promise implementations: [`request-promise-native`](https://github.com/request/request-promise-native) and [`request-promise-any`](https://github.com/request/request-promise-any)
686 *(Thanks to @benjamingr, @eilgin, @gillesdemey, @hildjj, @iggycoloma, @jonathanong, @knpwrs, @MarkHerhold, @massimocode, @mikeal, @niftylettuce, @raitucarp, @sherdeadlock, @tonylukasavage, and @vgoloviznin for the valuable discussions!)*
687 - Relicensed this library with the ISC license
688- v3.0.0 (2016-04-16)
689 - **Breaking Change**: Overhauled the handling of the `transform` function
690 *(Thanks to @Limess for explaining the need in [issue #86](https://github.com/request/request-promise/issues/86))*
691 - **Breaking Change**: Updated `bluebird` to v3
692 *(Thanks to @BrandonSmith for [pull request #103](https://github.com/request/request-promise/pull/103))*
693 - Improved `StatusCodeError.message`
694 - Updated `lodash` to v4.6
695 - Improved README in regard to `.catch(...)` best practice
696 *(Thanks to @RebootJeff for [pull request #98](https://github.com/request/request-promise/pull/98))*
697- v2.0.1 (2016-02-17)
698 - Updated `lodash` to v4
699 *(Thanks to @ratson for [pull request #94](https://github.com/request/request-promise/pull/94))*
700- v2.0.0 (2016-01-12)
701 - **Breaking Change**: Removed explicit `cls-bluebird` dependency which has to be installed by the user now
702 *(Thanks to @hildjj for his [pull request #75](https://github.com/request/request-promise/pull/75))*
703 - `npm shrinkwrap` now works for `npm@3` users who don't use `continuation-local-storage`
704 *(Thanks to @toboid and @rstacruz for reporting the issue in [issue #70](https://github.com/request/request-promise/issues/70) and [issue #82](https://github.com/request/request-promise/issues/82))*
705- v1.0.2 (2015-10-22)
706 - Removed `continuation-local-storage` from peer dependencies as it was unnecessary
707 *(Thanks to @mrhyde for working on a better solution discussed in [issue #70](https://github.com/request/request-promise/issues/70))*
708- v1.0.1 (2015-10-14)
709 - Fixed a npm warning by marking `continuation-local-storage` as a peer dependency
710- v1.0.0 (2015-10-11)
711 - **Breaking Change**: Some errors that were previously thrown synchronously - e.g. for wrong input parameters - are now passed to the rejected promise instead
712 *(Thanks to @josnidhin for suggesting that in [issue #43](https://github.com/request/request-promise/issues/43))*
713 - **Breaking Change**: Request-Promise does not load its own Bluebird prototype anymore. If you use Bluebird in your project and altered the prototype then Request-Promise may use your altered Bluebird prototype internally.
714 - For HEAD requests the headers instead of an empty body is returned (unless `resolveWithFullResponse = true` is used)
715 *(Thanks to @zcei for proposing the change in [issue #58](https://github.com/request/request-promise/issues/58))*
716 - Extended `transform` function by a third `resolveWithFullResponse` parameter
717 - Added experimental support for continuation local storage
718 *(Thanks to @silverbp preparing this in [issue #64](https://github.com/request/request-promise/issues/64))*
719 - Added node.js 4 to the Travis CI build
720 - Updated the README
721 *(Thanks to many people for their feedback in issues [#55](https://github.com/request/request-promise/issues/55) and [#59](https://github.com/request/request-promise/issues/59))*
722- v0.4.3 (2015-07-27)
723 - Reduced overhead by just requiring used lodash functions instead of the whole lodash library
724 *(Thanks to @luanmuniz for [pull request #54](https://github.com/request/request-promise/pull/54))*
725 - Updated dependencies
726- v0.4.2 (2015-04-12)
727 - Updated dependencies
728- v0.4.1 (2015-03-20)
729 - Improved Error types to work in browsers without v8 engine
730 *(Thanks to @nodiis for [pull request #40](https://github.com/request/request-promise/pull/40))*
731- v0.4.0 (2015-02-08)
732 - Introduced Error types used for the reject reasons (See last part [this section](#rejected-promises-and-the-simple-option))
733 *(Thanks to @jakecraige for starting the discussion in [issue #38](https://github.com/request/request-promise/issues/38))*
734 - **Minor Breaking Change:** The reject reason objects became actual Error objects. However, `typeof reason === 'object'` still holds true and the error objects have the same properties as the previous reason objects. If the reject handler only accesses the properties on the reason object - which is usually the case - no migration is required.
735 - Added io.js and node.js 0.12 to the Travis CI build
736- v0.3.3 (2015-01-19)
737 - Fixed handling possibly unhandled rejections to work with the latest version of Bluebird
738 *(Thanks to @slang800 for reporting this in [issue #36](https://github.com/request/request-promise/issues/36))*
739- v0.3.2 (2014-11-17)
740 - Exposed `.finally(...)` to allow using it as the first method in the promise chain
741 *(Thanks to @hjpbarcelos for his [pull request #28](https://github.com/request/request-promise/pull/28))*
742- v0.3.1 (2014-11-11)
743 - Added the `.promise()` method for advanced Bluebird API usage
744 *(Thanks to @devo-tox for his feedback in [issue #27](https://github.com/request/request-promise/issues/27))*
745- v0.3.0 (2014-11-10)
746 - Carefully rewritten from scratch to make Request-Promise a drop-in replacement for Request
747
748## License (ISC)
749
750In case you never heard about the [ISC license](http://en.wikipedia.org/wiki/ISC_license) it is functionally equivalent to the MIT license.
751
752See the [LICENSE file](LICENSE) for details.