feature #253: add support for response type "json"

This commit is contained in:
Sefa Ilkimen
2019-09-26 04:31:08 +02:00
parent 2ce1fc407d
commit 34a559bc6e
8 changed files with 150 additions and 35 deletions
+1
View File
@@ -3,6 +3,7 @@
## 2.2.0 ## 2.2.0
- Feature #239: add enumeration style object for error codes - Feature #239: add enumeration style object for error codes
- Feature #253: add support for response type "json"
## 2.1.1 ## 2.1.1
+2 -1
View File
@@ -205,7 +205,8 @@ The options object contains following keys:
* `params`: query params to be appended to the URL (only applicable on `get`, `head`, `delete`, `upload` or `download` methods) * `params`: query params to be appended to the URL (only applicable on `get`, `head`, `delete`, `upload` or `download` methods)
* `serializer`: data serializer to be used (only applicable on `post`, `put` or `patch` methods), defaults to global serializer value, see [setDataSerializer](#setDataSerializer) for supported values * `serializer`: data serializer to be used (only applicable on `post`, `put` or `patch` methods), defaults to global serializer value, see [setDataSerializer](#setDataSerializer) for supported values
* `responseType`: expected response type, defaults to `text`, needs to be one of the following values: * `responseType`: expected response type, defaults to `text`, needs to be one of the following values:
* `text`: data is returned as decoded string, use this for all kinds of string responses (e.g. JSON, XML, HTML, plain text, etc.) * `text`: data is returned as decoded string, use this for all kinds of string responses (e.g. XML, HTML, plain text, etc.)
* `json` data is treated as JSON and returned as parsed object
* `arraybuffer`: data is returned as [ArrayBuffer instance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) * `arraybuffer`: data is returned as [ArrayBuffer instance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)
* `blob`: data is returned as [Blob instance](https://developer.mozilla.org/en-US/docs/Web/API/Blob) * `blob`: data is returned as [Blob instance](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
* `timeout`: timeout value for the request in seconds, defaults to global timeout value * `timeout`: timeout value for the request in seconds, defaults to global timeout value
+101 -3
View File
@@ -4,6 +4,7 @@ const should = chai.should();
describe('Advanced HTTP public interface', function () { describe('Advanced HTTP public interface', function () {
const messages = require('../www/messages'); const messages = require('../www/messages');
let http = {}; let http = {};
const noop = () => { /* intentionally doing nothing */ }; const noop = () => { /* intentionally doing nothing */ };
@@ -13,16 +14,17 @@ describe('Advanced HTTP public interface', function () {
const jsUtil = require('../www/js-util'); const jsUtil = require('../www/js-util');
const ToughCookie = require('../www/umd-tough-cookie'); const ToughCookie = require('../www/umd-tough-cookie');
const lodash = require('../www/lodash'); const lodash = require('../www/lodash');
const errorCodes = require('../www/error-codes');
const WebStorageCookieStore = require('../www/local-storage-store')(ToughCookie, lodash); const WebStorageCookieStore = require('../www/local-storage-store')(ToughCookie, lodash);
const cookieHandler = require('../www/cookie-handler')(null, ToughCookie, WebStorageCookieStore); const cookieHandler = require('../www/cookie-handler')(null, ToughCookie, WebStorageCookieStore);
const helpers = require('../www/helpers')(jsUtil, cookieHandler, messages); const helpers = require('../www/helpers')(jsUtil, cookieHandler, messages, errorCodes);
const urlUtil = require('../www/url-util')(jsUtil); const urlUtil = require('../www/url-util')(jsUtil);
return { exec: noop, cookieHandler, urlUtil: urlUtil, helpers, globalConfigs }; return { exec: noop, cookieHandler, urlUtil: urlUtil, helpers, globalConfigs, errorCodes };
}; };
const loadHttp = (deps) => { const loadHttp = (deps) => {
http = require('../www/public-interface')(deps.exec, deps.cookieHandler, deps.urlUtil, deps.helpers, deps.globalConfigs); http = require('../www/public-interface')(deps.exec, deps.cookieHandler, deps.urlUtil, deps.helpers, deps.globalConfigs, deps.errorCodes);
}; };
beforeEach(() => { beforeEach(() => {
@@ -377,4 +379,100 @@ describe('Common helpers', function () {
.should.throw(messages.INVALID_FOLLOW_REDIRECT_VALUE); .should.throw(messages.INVALID_FOLLOW_REDIRECT_VALUE);
}); });
}); });
describe('injectRawResponseHandler()', function () {
const jsUtil = require('../www/js-util');
const messages = require('../www/messages');
const errorCodes = require('../www/error-codes');
const fakeBase64 = { toArrayBuffer: () => 'fakeArrayBuffer' };
global.Blob = function (array, meta) {
this.isFakeBlob = true;
this.array = array;
this.meta = meta;
};
it('does not change response data if it is an ArrayBuffer', () => {
const helpers = require('../www/helpers')(jsUtil, null, messages, null, errorCodes);
const buffer = new ArrayBuffer(5);
const handler = helpers.injectRawResponseHandler(
'arraybuffer',
response => response.data.should.be.equal(buffer)
);
handler({ data: buffer });
});
it('does not change response data if it is a Blob', () => {
const fakeJsUtil = { getTypeOf: () => 'Blob' };
const helpers = require('../www/helpers')(fakeJsUtil, null, messages, null, errorCodes);
const handler = helpers.injectRawResponseHandler(
'blob',
response => response.data.should.be.equal('fakeData')
);
handler({ data: 'fakeData' });
});
it('does not change response data if response type is "text"', () => {
const helpers = require('../www/helpers')(jsUtil, null, messages, null, errorCodes);
const example = 'exampleText';
const handler = helpers.injectRawResponseHandler(
'text',
response => response.data.should.be.equal(example)
);
handler({ data: example });
});
it('handles response type "json" correctly', () => {
const fakeData = { myString: 'bla', myNumber: 10 };
const helpers = require('../www/helpers')(jsUtil, null, messages, null, errorCodes);
const handler = helpers.injectRawResponseHandler(
'json',
response => response.data.should.be.eql(fakeData)
);
handler({ data: JSON.stringify(fakeData) });
});
it('handles response type "arraybuffer" correctly', () => {
const helpers = require('../www/helpers')(jsUtil, null, messages, fakeBase64, errorCodes);
const handler = helpers.injectRawResponseHandler(
'arraybuffer',
response => response.data.should.be.equal('fakeArrayBuffer')
);
handler({ data: 'myString' });
});
it('handles response type "blob" correctly', () => {
const helpers = require('../www/helpers')(jsUtil, null, messages, fakeBase64, errorCodes);
const handler = helpers.injectRawResponseHandler(
'blob',
(response) => {
response.data.isFakeBlob.should.be.equal(true);
response.data.array.should.be.eql(['fakeArrayBuffer']);
response.data.meta.type.should.be.equal('fakeType');
}
);
handler({ data: 'myString', headers: { 'content-type': 'fakeType'} });
});
it('calls failure callback when post-processing fails', () => {
const helpers = require('../www/helpers')(jsUtil, null, messages, fakeBase64, errorCodes);
const handler = helpers.injectRawResponseHandler(
'json',
null,
(response) => {
response.status.should.be.equal(errorCodes.POST_PROCESSING_FAILED);
response.error.should.include('Unexpected token N in JSON at position 0');
}
);
handler({ data: 'NotValidJson' });
});
});
}) })
+3 -2
View File
@@ -7,14 +7,15 @@ var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
var exec = require('cordova/exec'); var exec = require('cordova/exec');
var base64 = require('cordova/base64'); var base64 = require('cordova/base64');
var messages = require(pluginId + '.messages'); var messages = require(pluginId + '.messages');
var errorCodes = require(pluginId + '.error-codes');
var globalConfigs = require(pluginId + '.global-configs'); var globalConfigs = require(pluginId + '.global-configs');
var jsUtil = require(pluginId + '.js-util'); var jsUtil = require(pluginId + '.js-util');
var ToughCookie = require(pluginId + '.tough-cookie'); var ToughCookie = require(pluginId + '.tough-cookie');
var lodash = require(pluginId + '.lodash'); var lodash = require(pluginId + '.lodash');
var WebStorageCookieStore = require(pluginId + '.local-storage-store')(ToughCookie, lodash); var WebStorageCookieStore = require(pluginId + '.local-storage-store')(ToughCookie, lodash);
var cookieHandler = require(pluginId + '.cookie-handler')(window.localStorage, ToughCookie, WebStorageCookieStore); var cookieHandler = require(pluginId + '.cookie-handler')(window.localStorage, ToughCookie, WebStorageCookieStore);
var helpers = require(pluginId + '.helpers')(jsUtil, cookieHandler, messages, base64); var helpers = require(pluginId + '.helpers')(jsUtil, cookieHandler, messages, base64, errorCodes);
var urlUtil = require(pluginId + '.url-util')(jsUtil); var urlUtil = require(pluginId + '.url-util')(jsUtil);
var publicInterface = require(pluginId + '.public-interface')(exec, cookieHandler, urlUtil, helpers, globalConfigs); var publicInterface = require(pluginId + '.public-interface')(exec, cookieHandler, urlUtil, helpers, globalConfigs, errorCodes);
module.exports = publicInterface; module.exports = publicInterface;
+9
View File
@@ -0,0 +1,9 @@
module.exports = {
GENERIC: -1,
SSL_EXCEPTION: -2,
SERVER_NOT_FOUND: -3,
TIMEOUT: -4,
UNSUPPORTED_URL: -5,
NOT_CONNECTED: -6,
POST_PROCESSING_FAILED: -7,
};
+30 -17
View File
@@ -1,9 +1,9 @@
module.exports = function init(jsUtil, cookieHandler, messages, base64) { module.exports = function init(jsUtil, cookieHandler, messages, base64, errorCodes) {
var validSerializers = ['urlencoded', 'json', 'utf8']; var validSerializers = ['urlencoded', 'json', 'utf8'];
var validCertModes = ['default', 'nocheck', 'pinned', 'legacy']; var validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
var validClientAuthModes = ['none', 'systemstore', 'buffer']; var validClientAuthModes = ['none', 'systemstore', 'buffer'];
var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download']; var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download'];
var validResponseTypes = ['text','arraybuffer', 'blob']; var validResponseTypes = ['text', 'json', 'arraybuffer', 'blob'];
var interface = { var interface = {
b64EncodeUnicode: b64EncodeUnicode, b64EncodeUnicode: b64EncodeUnicode,
@@ -234,30 +234,43 @@ module.exports = function init(jsUtil, cookieHandler, messages, base64) {
} }
} }
function injectRawResponseHandler(responseType, cb) { function injectRawResponseHandler(responseType, success, failure) {
return function (response) { return function (response) {
var dataType = jsUtil.getTypeOf(response.data); var dataType = jsUtil.getTypeOf(response.data);
// don't need post-processing if it's already binary type (on browser platform) // don't need post-processing if it's already binary type (on browser platform)
if (dataType === 'ArrayBuffer' || dataType === 'Blob') { if (dataType === 'ArrayBuffer' || dataType === 'Blob') {
return cb(response); return success(response);
} }
// arraybuffer try {
if (responseType === validResponseTypes[1]) { // json
var buffer = base64.toArrayBuffer(response.data); if (responseType === validResponseTypes[1]) {
response.data = buffer; response.data = JSON.parse(response.data);
} }
// blob // arraybuffer
if (responseType === validResponseTypes[2]) { else if (responseType === validResponseTypes[2]) {
var buffer = base64.toArrayBuffer(response.data); response.data = base64.toArrayBuffer(response.data);
var type = response.headers['content-type'] || ''; }
var blob = new Blob([ buffer ], { type: type });
response.data = blob;
}
cb(response); // blob
else if (responseType === validResponseTypes[3]) {
var buffer = base64.toArrayBuffer(response.data);
var type = response.headers['content-type'] || '';
var blob = new Blob([ buffer ], { type: type });
response.data = blob;
}
success(response);
} catch (error) {
failure({
status: errorCodes.POST_PROCESSING_FAILED,
error: messages.POST_PROCESSING_FAILED + ' ' + error.message,
url: response.url,
headers: response.headers
});
}
} }
} }
+1
View File
@@ -16,4 +16,5 @@ module.exports = {
INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value', INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value',
MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function', MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function',
MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function', MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function',
POST_PROCESSING_FAILED: 'advanced-http: an error occured during post processing response:',
}; };
+3 -12
View File
@@ -1,13 +1,4 @@
module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConfigs) { module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConfigs, errorCodes) {
var ErrorCode = {
Generic: -1,
SslException: -2,
ServerNotFound: -3,
Timeout: -4,
UnsupportedUrl: -5,
NotConnected: -6,
};
var publicInterface = { var publicInterface = {
getBasicAuthHeader: getBasicAuthHeader, getBasicAuthHeader: getBasicAuthHeader,
useBasicAuth: useBasicAuth, useBasicAuth: useBasicAuth,
@@ -38,7 +29,7 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
head: head, head: head,
uploadFile: uploadFile, uploadFile: uploadFile,
downloadFile: downloadFile, downloadFile: downloadFile,
ErrorCode: ErrorCode ErrorCode: errorCodes
}; };
function getBasicAuthHeader(username, password) { function getBasicAuthHeader(username, password) {
@@ -155,7 +146,7 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
var headers = helpers.getMergedHeaders(url, options.headers, globalConfigs.headers); var headers = helpers.getMergedHeaders(url, options.headers, globalConfigs.headers);
var onFail = helpers.injectCookieHandler(url, failure); var onFail = helpers.injectCookieHandler(url, failure);
var onSuccess = helpers.injectCookieHandler(url, helpers.injectRawResponseHandler(options.responseType, success)); var onSuccess = helpers.injectCookieHandler(url, helpers.injectRawResponseHandler(options.responseType, success, failure));
switch (options.method) { switch (options.method) {
case 'post': case 'post':