justinhoward/recite

View on GitHub
src/extensions/JsonExtension.js

Summary

Maintainability
A
1 hr
Test Coverage
'use strict';
var isPlainObject = require('../utilities/isPlainObject');

/**
 * Provides JSON awareness to Http
 *
 * Registering this extension adds the `getJson`, and `setJson`
 * methods. It also adds request and response listeners that watch
 * for `application/json` content types and encode/decode JSON
 * content bodies.
 *
 * @class Http.extensions.JsonExtension
 */
function JsonExtension() {}

var proto = JsonExtension.prototype;

/**
 * Register this extension
 *
 * Usually done via {@link Http#addExtension}
 *
 * @param {Http} http The Http instance to register to
 */
proto.register = function(http) {
  this.addListeners(http.getDispatcher());
  if (!http.getJson) {
    http.getJson = JsonExtension.getJson;
  }

  if (!http.postJson) {
    http.postJson = JsonExtension.postJson;
  }

  if (!http.requestJson) {
    http.requestJson = JsonExtension.requestJson;
  }
};

/**
 * Registers the event listeners with a dispatcher
 *
 * This is automatically done when registering the extension
 *
 * @param {Hoopla} dispatcher The `Hoopla` dispatcher instance
 */
proto.addListeners = function(dispatcher) {
  dispatcher.addListener('http.request', JsonExtension.httpRequestListener);
  dispatcher.addListener('http.response', JsonExtension.httpResponseListener);
};

/**
 * Creates an HTTP GET request with JSON headers
 *
 * Sets the `Content-type` header to `application/json`
 *
 * @method getJson
 * @memberof Http.extensions.JsonExtension
 * @see {@link Http.extensions.JsonExtension#requestJson}
 * @param {string} url The request URL
 * @param {Object} attributes Get parameters as an object of keys/values
 * @param {Headers|Object} headers Additional request headers
 * @return {Http.Request} The request object
 */
JsonExtension.getJson = function(url, attributes, headers) {
  var request = this.get(url, attributes, headers);
  return requestToJson(request);
};

/**
 * Creates an HTTP POST request with JSON headers
 *
 * Sets the `Content-type` header to `application/json`
 * If `contents` is given, it will be JSON stringified.
 *
 * @method postJson
 * @memberof Http.extensions.JsonExtension
 * @see {@link Http.extensions.JsonExtension#requestJson}
 * @param {string} url The request URL
 * @param {*} contents The body contents
 * @param {Headers|Object} headers Additional request headers
 * @return {Http.Request} The request object
 */
JsonExtension.postJson = function(url, contents, headers) {
  var request = this.post(url, contents, headers);
  return requestToJson(request);
};

/**
 * Creates an HTTP request with JSON headers
 *
 * Sets the `Content-type` header to `application/json`
 * If `contents` is given, it will be JSON stringified.
 *
 * This method is added to the `Http` instance when the extension is registered.
 * Call it with
 *
 * ```
 * http.requestJson('PUT', 'http://example.com', {foo: 123});
 * ```
 *
 * @param {string} method The HTTP method
 * @param {string} url The request url
 * @param {*} contents The request body contents
 * @param {Headers|Object} [headers] Additional request headers
 * @return {Http.Request} The request object
 */
JsonExtension.requestJson = function(method, url, contents, headers) {
  var request = this.request(method, url, contents, headers);
  return requestToJson(request);
};

/**
 * A request listener that automatically encodes
 * the request body as JSON when the `content-type` header
 * is set to `application/json`
 *
 * Can be manually registered with
 *
 * ```
 * dispatcher.addListener('http.request', JsonExtension.httpRequestListener);
 * ```
 * @method httpRequestListener
 * @memberof Http.extensions.JsonExtension
 * @param {Hoopla.Event} event The `http.request` event object
 */
JsonExtension.httpRequestListener = function(event) {
  var request = event.getRequest();
  if (request.getHeaders().getContentType() === 'application/json') {
    var contents = request.getContents();
    if (isPlainObject(contents)) {
      request.setContents(JSON.stringify(contents));
    }
  }
};

/**
 * A response listener that automatically encodes
 * the response body as JSON when the `content-type` header
 * is set to `application/json`
 *
 * Can be manually registered with
 *
 * ```
 * dispatcher.addListener('http.response', JsonExtension.httpResponseListener);
 * ```
 *
 * @method httpResponseListener
 * @memberof Http.extensions.JsonExtension
 * @param {Hoopla.Event} event The `http.request` event object
 */
JsonExtension.httpResponseListener = function(event) {
  var response = event.getResponse();
  if (response.getHeaders().getContentType() === 'application/json') {
    var contents = response.getContents();
    if (typeof contents === 'string') {
      response.setContents(JSON.parse(contents));
    }
  }
};

function requestToJson(request) {
  var headers = request.getHeaders();
  headers.set('content-type', 'application/json');
  headers.set('accept', 'application/json');
  return request;
}

module.exports = JsonExtension;