Files
js-openstack-lib/src/util/http.js
Michael Krotscheck 7767d0183c Removed request and response interception.
The request/response interception has not yet been used, and
introduced quite a bit of complexity, especially surrounding fetchMock.
Furthermore, they made our DSVM tests fail, as the browser's implementation
of Request requires that a request body be accessed using the regular
json(), text(), etc. promise generators. Since this would have
simply added more complexity to an already complex, unused feature,
we've simply removed the feature.

Change-Id: I4cdf7b7106c771f0562de47e8835076d48d03a31
2016-08-30 14:22:52 -07:00

143 lines
4.6 KiB
JavaScript

/*
* Copyright (c) 2016 Hewlett Packard Enterprise Development L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing permissions and limitations
* under the License.
*/
import 'isomorphic-fetch';
/**
* This utility class provides an abstraction layer for HTTP calls via fetch(). Its purpose is
* to provide common, SDK-wide behavior for all HTTP requests. Included are:
*
* - Access to default headers.
* - Convenience GET/PUT/POST/DELETE methods.
* - Passing 4xx and 5xx responses to the catch() handler.
*
* In the future, this class chould also be extended to provide:
*
* - Some form of progress() support for large uploads and downloads (perhaps via introduction of Q)
* - Convenience decoding of the response body, depending on Content-Type.
* - Internal error handling (At this time, HTTP errors are passed to then() rather than catch()).
* - Other features.
*/
export default class Http {
/**
* The default headers which will be sent with every request. A copy of these headers will be
* added to the Request instance passed through the interceptor chain, and may be
* modified there.
*
* @returns {{string: string}} A mapping of 'headerName': 'headerValue'
*/
get defaultHeaders () {
return this._defaultHeaders;
}
/**
* Create a new HTTP handler.
*/
constructor () {
// Add default response interceptors.
this._defaultHeaders = {
'Content-Type': 'application/json'
};
}
/**
* Make a decorated HTTP request.
*
* @param {String} method The HTTP method.
* @param {String} url The request URL.
* @param {{}} headers A map of HTTP headers.
* @param {{}} body The body. It will be JSON-Encoded by the handler.
* @returns {Promise} A promise which will resolve with the processed request response.
*/
httpRequest (method, url, headers = {}, body) {
// Sanitize the headers...
headers = Object.assign({}, headers, this.defaultHeaders);
// Build the request
const init = {method, headers};
// The Request() constructor will throw an error if the method is GET/HEAD, and there's a body.
if (['GET', 'HEAD'].indexOf(method) === -1 && body) {
init.body = JSON.stringify(body);
}
const request = new Request(url, init);
// Build the wrapper promise.
return new Promise((resolve, reject) => {
let promise = fetch(request.url, init);
// Fetch will treat all http responses (2xx, 3xx, 4xx, 5xx, etc) as successful responses.
// This will catch all 4xx and 5xx responses and return them to the catch() handler. Note
// that it's up to the downstream developer to determine whether what they received is an
// error or a failed response.
promise.then((response) => {
if (response.status >= 400) {
return reject(response);
} else {
return response;
}
});
promise.then((response) => resolve(response), (error) => reject(error));
});
}
/**
* Make a raw GET request against a particular URL.
*
* @param {String} url The request URL.
* @returns {Promise} A promise which will resolve with the processed request response.
*/
httpGet (url) {
return this.httpRequest('GET', url, {}, null);
}
/**
* Make a raw PUT request against a particular URL.
*
* @param {String} url The request URL.
* @param {{}} body The body. It will be JSON-Encoded by the handler.
* @returns {Promise} A promise which will resolve with the processed request response.
*/
httpPut (url, body) {
return this.httpRequest('PUT', url, {}, body);
}
/**
* Make a raw POST request against a particular URL.
*
* @param {String} url The request URL.
* @param {{}} body The body. It will be JSON-Encoded by the handler.
* @returns {Promise} A promise which will resolve with the processed request response.
*/
httpPost (url, body) {
return this.httpRequest('POST', url, {}, body);
}
/**
* Make a raw DELETE request against a particular URL.
*
* @param {String} url The request URL.
* @returns {Promise} A promise which will resolve with the processed request response.
*/
httpDelete (url) {
return this.httpRequest('DELETE', url, {}, null);
}
}