httpism

HTTP client with middleware and good defaults

HTTPism

httpism is a node and browser HTTP client that does a few things differently:

  • middleware: customise a HTTP client for your API by sticking together middleware, for example, for content handlers or authentication schemes.
  • hypermedia: responses can be used to make further requests relative to the response URI, just like a browser.
  • useful by default: sends and receives JSON, throws exceptions on 400-500s, follows redirects. Of course, you can disable this stuff when it gets in your way, or hit raw HTTP and streams when you need to get clever.
  • promises: no messing about with callbacks.

NPM: httpism

npm install httpism

Then

var httpism = require('httpism');

Compatible with browserify too!

httpism.get('http://example.com/').then(function (response) {
  console.log('json', response.body);
}, function (error) {
  console.log('uh oh', error);
});

POST JSON

httpism.post('http://example.com/', {name: 'Betty Boo'}).then(function (response) {
  console.log('json', response.body);
}, function (error) {
  console.log('uh oh', error);
});

Specify a base URL:

var example = httpism.api('http://example.com/');
 
// GET http://example.com/a
example.get('a').then(function (response) {
  console.log(response.body);
});

Specify some options:

var loggingHttpism = httpism.api({exceptions: false});
 
loggingHttpism.get('http://example.com/').then(function (response) {
  console.log(response.body);
});

Add some middleware:

var authHttpism = httpism.api(function (request, next) {
  request.url += '?apikey=myapikey';
  return next();
});
 
// GET https://secretapi.com/?apikey=myapikey
authHttpism.get('https://secretapi.com/').then(function (response) {
  console.log(response.body);
});

See more about apis.

The browser version has a few differences from the node version:

  • Relative URLs are relative to the current browser location.
  • No support for streams.
  • Redirects aren't optional, browsers always follow redirects.
  • Logging is removed, since most (if not all?) browsers now have a network debug tab.

However, everything else works as described here.

  • httpism.js: 18K
  • httpism.min.js: 8.6K
  • httpism.min.js.gz: 3.2K

httpism uses debug so you can enable logging just by setting the DEBUG environment variable to httpism:*:

DEBUG=httpism:* node app.js

More information in debug's README.

httpism.method (url, [options])
response.method (url, [options])
  • url a string url, full or relative to the response, or '' to request the response again
  • options request options, see options.
  • response a response from another request.

returns a promise

POST, PUT, PATCH, OPTIONS

httpism.method (url, data, [options])
response.method (url, data, [options])
  • url a string url, full or relative to the response, or '' to request the response again
  • data the data to send
    • by default a JS object is encoded as JSON and sent as application/json
    • a JS object with options {form: true} is url-encoded and sent as application/x-www-form-urlencoded
    • a stream (where typeof(stream.pipe) === 'function') is sent as is. Be sure to set Content-Type header: {headers: {'content-type': '...'}}.
  • options request options, see options.
  • response a response from another request.

Responses are objects that contain

  • url the full URL of the response. In the browser, this will be root-relative if the request is for the same domain as the current page. This can be different to the request.url if there was a redirect.
  • headers the headers of the response
  • body the body of the response. Depending on the Content-Type header:
    • application/json a object
    • application/x-www-form-urlencoded a object
    • text/* or application/javascript a string
    • on the server, anything else is returned as a Node stream, be careful to close it!. In the browser, anything else is returned as a string.

Cookies can be stored with tough-cookie. Just set options.cookies to an instance of a ToughCookie.CookieJar to store cookies sent from the server, and correspondingly, cookies that match the domain will be sent back to the server.

var ToughCookie = require('tough-cookie');
 
// make a new client that uses the cookie jar 
var client = httpism.api('http://example.com/', {cookies: new ToughCookie.CookieJar()});
 
client.post('/login', {username: 'jerome', password: 'password123'}, {form: true}).then(function () {
  return client.get('/profile').then(function (profileResponse) {
    console.log(profileResponse.body);
  });
});

All responses are full httpism clients, just with their base URI set to the HREF of the response. They respond to all the HTTP methods, as well as api(), see apis below.

httpism.get('http://example.com/api/').then(function (api) {
  // api.body is:
  // {
  //   "documentsLink": "documents"
  // }
 
  // so we navigate to http://example.com/api/documents
  api.get(api.body.documentsLink).then(function (documents) {
    console.log('documents', documents.body);
  });
});
  • exceptions: default true, throw exceptions on reception of 400-500 status codes. Set to false to simply return the response.
  • redirect: default true, follow redirects for 300, 301, 302, 303 and 307 status codes with Location response headers. Set to false to simply return the redirect response.
  • headers: default undefined, can be set to an object that is merged with middleware headers.
  • basicAuth: use Basic Authentication, pass an object { username: 'bob', password: "bob's secret" }.
  • querystring: default undefined, can be set to an object containing fields that are URL-encoded and merged with the querystring already on the URL, if any.
  • form: when true, treats the incoming JSON data as a form and encodes it as application/x-www-form-urlencoded.
  • responseBody: can be used to force the parsing of the response, ignoring the Content-Type, it can be a string of one of the following:
    • 'stream': always downloads the response as a stream
    • 'json': always parses the response as a JSON object
    • 'text': always parses the response as text
    • 'form': always parses the response as a URL-encoded form
    • undefined: parse response based on Content-Type, the default.
  • proxy: a proxy URL, if present all requests will be run throught the proxy. This works if the environment variable http_proxy is set too.
  • http: default undefined, object containing options that are passed to Node.js http.request(). Many of these options are ignored by default, so you should set agent: undefined to force a new agent to honour the options.
  • https: default undefined, object containing options that are passed to Node.js https.request(). Many of these options are ignored by default, so you should set agent: undefined to force a new agent to honour the options.

API clients give you a way to build or customise a HTTP client for the purpose of accessing a particular web API. Web APIs will often have special authorization, headers, or URL conventions that are common across all calls, and you only want to have to specify those things once.

You can create API clients, either from httpism, giving you a fairly complete HTTP client, or from httpism.raw giving you no frills streaming HTTP client to do what you will with.

var api = httpism.api([url], [options], [middleware]);
var api = httpism.raw.api([url], [options], [middleware]);
var api = response.api([url], [options], [middleware]);
  • url a URL string, which could be relative to the response, or absolute.

  • options options object to be used for all calls with this api. If api is called on a response, the options are merged with that responses api.

  • middleware a middleware function or array of middleware functions. Requests in middleware are processed from the beginning of the array to the end, and responses from the end of the array to the beginning. See middleware. Middleware specified on the new api is prepended to the middleware currently in the api.

  • httpism is the basic client, with all the goodies described above.

  • httpism.raw is a raw client that has no other middleware.

  • response is a response from another request.

Middleware commonly works like this:

function middleware(request, next, httpism) {
  // change request
  request.url = ...;
  return next().then(function (response) {
    // change response
    response.body = ...;
    return response;
  });
}
  • request is an object with the following properties:
    • url the full URL of the request, e.g. http://example.com/path?query=value
    • method the method of the request, e.g. GET or POST
    • headers the headers of the request as an object. All headers are lower-cased as per Node.js conventions. E.g. { 'content-type': 'application/json' }
    • options the options as passed through from the request, either from the api or the individual request. E.g. {exceptions: true}.
    • body the body of the request. Will be undefined for get() etc, otherwise will be the object specified as the second argument to methods like post().
  • next is a function that passes control onto the next middleware, it returns a promise of the response.
  • httpism is a httpism api object, for which you can make further requests inside the middleware. For example, the redirect middleware uses this.

The following middleware are available in var middleware = require('httpism/middleware'):

  • middleware.json sends and receives JSON objects as application/json, also sets Accept: application/json on request.
  • middleware.text sends strings as text/plain and receives strings when text/* or application/javascript.
  • middleware.exception throws an exception when the response status code is 400-500.
  • middleware.logger logs requests and responses.
  • middleware.redirect follows redirects.
  • middleware.headers honours options.headers.
  • middleware.form when options.form == true sends and receives URL-encoded JS objects application/x-www-form-urlencoded.
  • middleware.querystring merges the URL-encoded options.querystring into the request URL.

See middleware.pogo for more info.

License

BSD