/**
* Represent a Reket response structure base. Non readonly attributes depend of the HTTP call.
* @typedef {Object<string, *>|Array} ReketResponse
*
* @property {Object} getConfig readonly property that expose the original config of
* the request.
* @property {Object} getHeaders readonly property that expose the response headers returned
* by the HTTP call.
* @property {Object} getRequest readonly property that expose the original request that
* has been send.
* @property {string} getStatus readonly property that expose the response status
* (e.g. 200, 304, ...).
* @property {string} getStatusText readonly property that expose the status text of
* the response (e.g. "OK", "Not Modified", ...).
* @property {bool} isReketResponse readonly and internal only property.
*/
/**
* Creates a response with data exposed and other response attributes exposed as readonly.
* This format will avoid having to access `response.data` in order to get the data.
* Imagine we have a HTTP with response promise as follow:
* ```
* "data": {
* "shi": "ming",
* "foo": "bar",
* "me": "zot"
* },
* "headers": {
* ...
* }
* ```
* To access data in the promise you have to do something like:
* ```
* Reket.get('/my/url').then((response) => {
* const foo = response.data.foo;
* // or const { foo } = response.data;
* // and then access the headers
* const headers = response.headers;
* });
* ```
*
* With ReketResponse format it's possible to get directly foo from response like so:
* ```
* Reket.get('/my/url').then((response) => {
* const foo = response.foo;
* // or const { foo } = response;
* // and then access the headers
* const headers = response.getHeaders;
* });
* ```
*
* @param {*} options.data The data returned by the HTTP call.
* @param {Object} options.config The original config of the request.
* @param {Object} options.headers The response headers returned by the HTTP call.
* @param {Object} options.request The original request that has been send.
* @param {string} options.status The response status (e.g. 200, 304, ...)
* @param {string} options.statusText The status text of the response (e.g. "OK",
* "Not Modified", ...)
*
* @return {ReketResponse}
*/
export const buildReketResponse = ({
data,
config,
headers,
request,
status,
statusText,
}) => {
const props = {};
let responseData = data;
let response = {};
// detect type of response data
if (!Array.isArray(responseData)) {
// if not an array (Object, string, number, ...)
if (typeof responseData !== 'object' || responseData === null) {
// and not an object (number, string, null, ...).
// Treat it as an object and wrap data into an object with value as key.
// If HTTP data response is `"response"` the reket response object will look like:
//
// ```
// {
// value: 'response'
// }
// ```
responseData = {
value: responseData,
};
}
// build an object with all properties of http call response.
// Those properties are enumerable in the Object, meaning that `Object.keys(obj)`
// will list that properties.
Object.keys(responseData).forEach((attrName) => {
props[attrName] = {
value: responseData[attrName],
writable: true,
enumerable: true,
};
});
Object.defineProperties(response, props);
} else {
// if response data is an array, do not modify it's prototype.
response = data;
}
// define the readonly properties of the response.
Object.defineProperties(response, {
getConfig: {
value: config,
writable: false,
enumerable: false,
},
getHeaders: {
value: headers,
writable: false,
enumerable: false,
},
getRequest: {
value: request,
writable: false,
enumerable: false,
},
getStatus: {
value: status,
writable: false,
enumerable: false,
},
getStatusText: {
value: statusText,
writable: false,
enumerable: false,
},
isReketResponse: {
value: true,
writable: false,
enumerable: false,
},
});
return response;
};
export default {
buildReketResponse,
};
Source