A request library that returns promises, inspired by request

Overview

then-request

A request library that returns promises and supports both browsers and node.js

Build Status Dependency Status NPM version

Sponsor

Installation

npm install then-request

Usage

request(method, url, options, callback?)

The following examples all work on both client and server.

var request = require('then-request');

request('GET', 'http://example.com').done(function (res) {
  console.log(res.getBody());
});

request('POST', 'http://example.com/json-api', {json: {some: 'values'}}).getBody('utf8').then(JSON.parse).done(function (res) {
  console.log(res);
});

var FormData = request.FormData;
var data = new FormData();

data.append('some', 'values');

request('POST', 'http://example.com/form-api', {form: data}).done(function (res) {
  console.log(res.getBody());
});

Or with ES6

import request, {FormData} from 'then-request';

request('GET', 'http://example.com').done((res) => {
  console.log(res.getBody());
});

request('POST', 'http://example.com/json-api', {json: {some: 'values'}}).getBody('utf8').then(JSON.parse).done((res) => {
  console.log(res);
});

var FormData = request.FormData;
var data = new FormData();

data.append('some', 'values');

request('POST', 'http://example.com/form-api', {form: data}).done((res) => {
  console.log(res.getBody());
});

Method:

An HTTP method (e.g. GET, POST, PUT, DELETE or HEAD). It is not case sensitive.

URL:

A url as a string (e.g. http://example.com). Relative URLs are allowed in the browser.

Options:

  • qs - an object containing querystring values to be appended to the uri
  • headers - http headers (default: {})
  • body - body for PATCH, POST and PUT requests. Must be a Buffer, ReadableStream or String (only strings are accepted client side)
  • json - sets body but to JSON representation of value and adds Content-type: application/json. Does not have any affect on how the response is treated.
  • form - You can pass a FormData instance to the form option, this will manage all the appropriate headers for you. Does not have any affect on how the response is treated.
  • cache - only used in node.js (browsers already have their own caches) Can be 'memory', 'file' or your own custom implementaton (see https://github.com/ForbesLindesay/http-basic#implementing-a-cache).
  • followRedirects - defaults to true but can be explicitly set to false on node.js to prevent then-request following redirects automatically.
  • maxRedirects - sets the maximum number of redirects to follow before erroring on node.js (default: Infinity)
  • allowRedirectHeaders (default: null) - an array of headers allowed for redirects (none if null).
  • gzip - defaults to true but can be explicitly set to false on node.js to prevent then-request automatically supporting the gzip encoding on responses.
  • agent - (default: false) - An Agent to controll keep-alive. When set to false use an Agent with default values.
  • timeout (default: false) - times out if no response is returned within the given number of milliseconds.
  • socketTimeout (default: false) - calls req.setTimeout internally which causes the request to timeout if no new data is seen for the given number of milliseconds. This option is ignored in the browser.
  • retry (default: false) - retry GET requests. Set this to true to retry when the request errors or returns a status code greater than or equal to 400 (can also be a function that takes (err, req, attemptNo) => shouldRetry)
  • retryDelay (default: 200) - the delay between retries (can also be set to a function that takes (err, res, attemptNo) => delay)
  • maxRetries (default: 5) - the number of times to retry before giving up.

Returns:

A Promise is returned that eventually resolves to the Response. The resulting Promise also has an additional .getBody(encoding?) method that is equivallent to calling .then(function (res) { return res.getBody(encoding?); }).

Response

Note that even for status codes that represent an error, the promise will be resolved as the request succeeded. You can call getBody if you want to error on invalid status codes. The response has the following properties:

  • statusCode - a number representing the HTTP status code
  • headers - http response headers
  • body - a string if in the browser or a buffer if on the server
  • url - the URL that was requested (in the case of redirects on the server, this is the final url that was requested)

It also has a method getBody(encoding?) which looks like:

function getBody(encoding) {
  if (this.statusCode >= 300) {
    var err = new Error('Server responded with status code ' + this.statusCode + ':\n' + this.body.toString(encoding));
    err.statusCode = this.statusCode;
    err.headers = this.headers;
    err.body = this.body;
    throw err;
  }
  return encoding ? this.body.toString(encoding) : this.body;
}

FormData

var FormData = require('then-request').FormData;

Form data either exposes the node.js module, form-data, or the builtin browser object FormData, as appropriate.

They have broadly the same API, with the exception that form-data handles node.js streams and Buffers, while FormData handles the browser's File Objects.

License

MIT

Comments
  • CORS errors resolve to statusCode: 0

    CORS errors resolve to statusCode: 0

    Try this in a browser:

    request('GET', 'http://yahoo.com')
    .then(function(res) {
      console.log("Success:", JSON.stringify(res));
    })
    

    This will fire off a CORS handshake:

    => OPTIONS "http://yahoo.com/" \
      access-control-request-headers:"x-requested-with" \
      Access-Control-Request-Method:"GET"
    
    <= HTTP/1.1 401 Forbidden
    

    This gets you this result, however:

    Success: "{"statusCode":0,"headers":{},"body":""}"
    
    opened by rstacruz 5
  • Not working with 'sepia'

    Not working with 'sepia'

    It'd be nice to have then-request work with sepia.

    For now, this is what happens:

    /···/node_modules/sepia/src/cache.js:130
              callback(res);
              ^
    TypeError: undefined is not a function
        at /···/node_modules/then-request/index.js:73:16
        at /···/node_modules/then-request/node_modules/http-basic/index.js:84:14
        at /···/node_modules/then-request/node_modules/http-basic/index.js:126:16
        at /···/node_modules/then-request/node_modules/http-basic/index.js:232:5
        at playback (/···/node_modules/sepia/src/cache.js:130:11)
        at EventEmitter.req.end (/···/node_modules/sepia/src/cache.js:145:9)
        at request (/···/node_modules/then-request/node_modules/http-basic/index.js:259:9)
        at request (/···/node_modules/then-request/node_modules/http-basic/index.js:88:12)
        at /···/node_modules/then-request/node_modules/http-basic/index.js:124:16
        at /···/node_modules/then-request/node_modules/http-basic/index.js:232:5
        at playback (/···/node_modules/sepia/src/cache.js:130:11)
        at EventEmitter.req.end (/···/node_modules/sepia/src/cache.js:145:9)
        at request (/···/node_modules/then-request/node_modules/http-basic/index.js:259:9)
        at request (/···/node_modules/then-request/node_modules/http-basic/index.js:88:12)
        at Function.request (/···/node_modules/then-request/node_modules/http-basic/index.js:63:12)
        at /···/node_modules/then-request/index.js:59:30
    
    opened by rstacruz 4
  • When trying to determine whether the request is cross-domain, check t…

    When trying to determine whether the request is cross-domain, check t…

    …he request url instead of options.uri which might be set to something else

    I didn't see options.uri documented anywhere and I don't see why options.uri would ever be different then url.

    opened by ryankaplan 3
  • Preserve header casing

    Preserve header casing

    Unfortunately there are apps out there that require specific header cases. For example phantomjs. The current implementation of forcing all headers to be lower-case makes phantomjs ignore or at least misinterpret the body.

    See: https://github.com/groupon-testium/webdriver-http-sync/issues/25

    Edit: Sorry, thought I tried running the tests locally and they passed. Fixing now.

    opened by jkrems 3
  • redirect url and maximum follow

    redirect url and maximum follow

    1. It would be cool to know the final url when following redirects, other modules had use events to achieve this, I am not sure the best way for a promise-based approach, establish some convention that pass headers along when following redirects?
    2. It would be a useful to set followRedirects as number instead of boolean, so users may specify the maximum number of jumps. I assume timeout is per redirect so it doesn't trigger timeout.
    opened by bitinn 3
  • can't support https with  'UNABLE_TO_VERIFY_LEAF_SIGNATURE'

    can't support https with 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'

    download https url error: { Error: unable to verify the first certificate at TLSSocket. (_tls_wrap.js:1105:38) at emitNone (events.js:106:13) at TLSSocket.emit (events.js:208:7) at TLSSocket._finishInit (_tls_wrap.js:639:8) at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:469:38) code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' }

    opened by liuwei000000 2
  • [Query] Synchronous function using then-request ??

    [Query] Synchronous function using then-request ??

    I want to write a synchronous function, which return the rest response which it receive from server. For example:

    var request = require('then-request');
    function get(address) {                           ------->  address = http://www.google.com
        request('GET', address).done(function (res) {
            console.log(res.getBody());
        });
       console.log("This should be executed after receiving the response from the server");
    }
    

    The above function should exit only when it receive response from the server.... In other words: printing of "This should be executed after receiving the response from the server" should be done after receiving the response from server that is after printing res.getBody()

    I am not sure about the working of then-request will it provide this feature by default or there is any other way to do this ?

    opened by jay11ca39 2
  • Ability to use agent option

    Ability to use agent option

    We would like to use custom agent object when we use the then-request. As far as I know http-basic library uses agent option. It would be great if then-request has this feature too.

    opened by molgun 2
  • `options.uri` isn't documented and is extraneous

    `options.uri` isn't documented and is extraneous

    Right now for cross-domain requests you have to pass options.uri which, for my use-case, is always the same as the url that I'm requesting. So why not remove options.uri and just check against url instead?

    Here's a PR that makes this change.

    Another approach would be to default options.uri to url and to let the user set it to something else if they need to. I don't see why you would ever need to do that, but I'm happy to amend the PR if there's an argument for it.

    opened by ryankaplan 2
  • Callback is not executed when request fails due to lower level network issue

    Callback is not executed when request fails due to lower level network issue

    Hi,

    I have a pretty simplistic use of this library:

    logRequestInfo(method, url);
    request(method, url, {json: json, headers: headers}).then(function (response) {
        logResponseInfo(response);
        done();
    });
    

    When a request fails, but the API returns a response with an error code e.g. 404, then the response gets printed.

    PUT http://localhost:9000/api/endpoint
    >> 404
    

    This is expected.

    The problem is when the underlying API is down. The aforementioned code breaks completely and no response gets ever printed.

    PUT http://localhost:9000/api/endpoint
    

    Processing is stopped.

    How can I handle errors in this case?

    Thanks, Marcin

    opened by marcingrabda 2
  • request error when pathname contains trailling slash followed by search string

    request error when pathname contains trailling slash followed by search string

    var request = require('then-request')
    
    get_url_status_code = url => {
      request('HEAD', url)
        .then(({ statusCode }) => console.log(`status: ${statusCode}`))
        .catch(err => console.log(err))
    }
    
    query_with_slash = with_slash =>
      `https://cn.bing.com/search` + (with_slash ? '/' : '') + '?q=hello%20world'
    
    // The link from bing not work
    url = query_with_slash(true)
    get_url_status_code(url)
    
    // After some magical modify, work
    url = query_with_slash(false)
    get_url_status_code(url)
    

    Result:

    { Error: unexpected end of file
        at Gunzip.zlibOnError (zlib.js:153:15) errno: -5, code: 'Z_BUF_ERROR' }
    status: 200
    
    opened by snowman 1
  • Unable to call API with certificates

    Unable to call API with certificates

    We are unable to make API call with certificates which we are using in our api framework with sync-request node module.

    process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' : We don't want to use this as we have certs available to us. Any suggestions - how to make sync-request work with certs?

    opened by guptapranay 1
  • Enable retry on non-GET requests?

    Enable retry on non-GET requests?

    Hi,

    I was curious why the built-in retry logic only functions for GET requests. Could it be extended so clients could retry for POST requests, or whatever method is used for the request? This is something we have a use case for (yes, I am aware of the dangers in general in retrying a failed POST request, we have a use case where this is desired behavior).

    Ie. Would a pull request that modified this line https://github.com/then/then-request/blob/master/src/browser.ts#L65 be accepted

    -if (options.retry && method === 'GET') {
    +if (options.retry) {
    
    opened by AaronHarris 3
  • GET request is sending Content-Length header

    GET request is sending Content-Length header

    here:

    var body = options.body ? options.body : new Buffer(0); if (typeof body === 'string') body = new Buffer(body); assert(Buffer.isBuffer(body), 'body should be a Buffer or a String'); if (!headers.has('Content-Length')) { headers.set('Content-Length', body.length); }

    Setting body to an empty dictionary so that body.length would be undefined doesn't help either because it checks what kind of a thing the body is.

    opened by 7macaw 0
  • README issues

    README issues

    There are a couple of things im not sure I understand from the readme.

    Firstly, the example reads:

      request('GET', 'http://example.com').done(...)
    

    Shoud that done(...) be then(...)? I see that the promise output from the call supports both, but the A+ spec doesn't even mention done() - so I would assume the most idiomatic use would be with then.

    It is also a little unclear ( to people like me still feeling out the idiosyncrasies of promises ) that the getBody(encoding?) function also returns a promise.

    Lastly somewhere you have affect when I think you mean effect, not that this last makes things any less clear.

    I would be glad to fix those up if my assumptions are correct.

    opened by refactorized 4
  • How do users authenticate to services

    How do users authenticate to services

    Thanks for a great library. I can't seem to find any info on authentication, is this supported?

    As an example, I'm trying to implement a basic form post with user authentication for this service: https://documentation.mailgun.com/api-sending.html#examples

    Are there any docs or examples about how to use the curl equivalent of

    curl -s --user 'api:YOUR_API_KEY' https://domain.com -F from='User <mailgun@YOUR_DOMAIN_NAME>'

    opened by 0o-de-lally 1
Owner
then (Promises/A+ implementations)
then (Promises/A+ implementations)
Tiny JavaScript library (1kB) by CurrencyRate.today, providing simple way and advanced number, money and currency formatting and removes all formatting/cruft and returns the raw float value.

Zero dependency tiny JavaScript library (1kB bytes) by CurrencyRate.today, providing simple way and advanced number, money and currency formatting and removes all formatting/cruft and returns the raw float value.

Yurii De 11 Nov 8, 2022
I forgot about el.outerHTML so I made this, it takes a DOM element and returns its html as string

htmlToString Convert html/DOM element to string Works with rendered and virtual DOM Installation npm install htmltostring Or using CDN <script src="ht

Shuvo 4 Jul 22, 2022
A simple website that returns a random advice.

Advice Preview ?? Technologies This project was developed with the following technologies: HTML CSS JavaScript API's Advice Slip JSON API ?? Project A

Jeffer Marcelino 4 Sep 2, 2022
Given an object and a property, replaces a property descriptor (or deletes it), and returns a thunk to restore it.

Given an object and a property, replaces a property descriptor (or deletes it), and returns a thunk to restore it.

Jordan Harband 7 Apr 20, 2022
Fix for Object.hasOwnProperty, which normally just returns a boolean, which is not good when you care about strong typing.

Welcome to ts-has-own-property ?? Fix for Object.hasOwnProperty, which normally just returns a boolean, which is not good when you care about strong t

Funtal Foundation 1 Jul 4, 2022
Fix for Object.keys, which normally just returns an array of strings, which is not good when you care about strong typing

Welcome to ts-object-keys ?? Fix for Object.keys, which normally just returns an array of strings, which is not good when you care about strong typing

Funtal Foundation 1 Jul 4, 2022
Tries to execute sync/async function, returns a specified default value if the function throws

good-try Tries to execute sync/async function, returns a specified default value if the function throws. Why Why not nice-try with it's 70+ million do

Antonio Stoilkov 14 Dec 8, 2022
Run async code one after another by scheduling promises.

promise-scheduler Run async code in a synchronous order by scheduling promises, with the possibility to cancel pending or active tasks. Optimized for

Matthias 2 Dec 17, 2021
Resolve parallel promises in key-value pairs whilst maintaining type information

async-kv Resolves promises in key-value pairs maintaining type information. Prerequisites NodeJS 12 or later Installation npm i async-kv yarn add asyn

Tony Tamplin 4 Feb 17, 2022
🐶 Learn JS Promises, with your friend 👑 Princess!

?? Learn JS Promises, with your friend ?? Princess!

Baylee Schmeisser 10 Jun 9, 2022
Converts an iterable, iterable of Promises, or async iterable into a Promise of an Array.

iterate-all A utility function that converts any of these: Iterable<T> Iterable<Promise<T>> AsyncIterable<T> AsyncIterable<Promise<T>> Into this: Prom

Lily Scott 8 Jun 7, 2022
A polyfill for ES6-style Promises

ES6-Promise (subset of rsvp.js) This is a polyfill of the ES6 Promise. The implementation is a subset of rsvp.js extracted by @jakearchibald, if you'r

Stefan Penner 7.3k Dec 28, 2022
A Promise-compatible abstraction that defers resolving/rejecting promises to another closure.

Deferred Promise The DeferredPromise class is a Promise-compatible abstraction that defers resolving/rejecting promises to another closure. This class

Open Draft 21 Dec 15, 2022
Remembering promises that were made!

remember-promise A simple utility to remember promises that were made! It is greatly inspired by the p-memoize utility but with additional built-in fe

reda 41 Dec 15, 2022
A minimalist Javascript library to perform AJAX POST and GET Request.

minAjax.js A minimalist Javascript library to perform AJAX POST and GET Request. #Check Pretty Documentation http://flouthoc.github.io/minAjax.js/ #Us

null 6 Apr 27, 2021
Browser library compatible with Node.js request package

Browser Request: The easiest HTTP library you'll ever see Browser Request is a port of Mikeal Rogers's ubiquitous and excellent [request][req] package

Iris Couch 357 Nov 11, 2022
AppRun is a JavaScript library for developing high-performance and reliable web applications using the elm inspired architecture, events and components.

AppRun AppRun is a JavaScript library for building reliable, high-performance web applications using the Elm-inspired architecture, events, and compon

Yiyi Sun 1.1k Dec 20, 2022
Standalone AJAX library inspired by jQuery/zepto

ajax Standalone AJAX library inspired by jQuery/zepto Installation component-install ForbesLindesay/ajax Then load using: var ajax = require('ajax');

Forbes Lindesay 365 Dec 17, 2022
A progressive image loading library. Inspired by Medium’s similar technique.

Blurry Image Load Synopsis A lightweight, zero-dependency library that loads images on demand. Until the images are loaded, a very small version of ea

Dominic Brant 32 Dec 10, 2022