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
- Feature #239: add enumeration style object for error codes
- Feature #253: add support for response type "json"
## 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)
* `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:
* `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)
* `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
+101 -3
View File
@@ -4,6 +4,7 @@ const should = chai.should();
describe('Advanced HTTP public interface', function () {
const messages = require('../www/messages');
let http = {};
const noop = () => { /* intentionally doing nothing */ };
@@ -13,16 +14,17 @@ describe('Advanced HTTP public interface', function () {
const jsUtil = require('../www/js-util');
const ToughCookie = require('../www/umd-tough-cookie');
const lodash = require('../www/lodash');
const errorCodes = require('../www/error-codes');
const WebStorageCookieStore = require('../www/local-storage-store')(ToughCookie, lodash);
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);
return { exec: noop, cookieHandler, urlUtil: urlUtil, helpers, globalConfigs };
return { exec: noop, cookieHandler, urlUtil: urlUtil, helpers, globalConfigs, errorCodes };
};
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(() => {
@@ -377,4 +379,100 @@ describe('Common helpers', function () {
.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 base64 = require('cordova/base64');
var messages = require(pluginId + '.messages');
var errorCodes = require(pluginId + '.error-codes');
var globalConfigs = require(pluginId + '.global-configs');
var jsUtil = require(pluginId + '.js-util');
var ToughCookie = require(pluginId + '.tough-cookie');
var lodash = require(pluginId + '.lodash');
var WebStorageCookieStore = require(pluginId + '.local-storage-store')(ToughCookie, lodash);
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 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;
+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 validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
var validClientAuthModes = ['none', 'systemstore', 'buffer'];
var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download'];
var validResponseTypes = ['text','arraybuffer', 'blob'];
var validResponseTypes = ['text', 'json', 'arraybuffer', 'blob'];
var interface = {
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) {
var dataType = jsUtil.getTypeOf(response.data);
// don't need post-processing if it's already binary type (on browser platform)
if (dataType === 'ArrayBuffer' || dataType === 'Blob') {
return cb(response);
return success(response);
}
// arraybuffer
if (responseType === validResponseTypes[1]) {
var buffer = base64.toArrayBuffer(response.data);
response.data = buffer;
}
try {
// json
if (responseType === validResponseTypes[1]) {
response.data = JSON.parse(response.data);
}
// blob
if (responseType === validResponseTypes[2]) {
var buffer = base64.toArrayBuffer(response.data);
var type = response.headers['content-type'] || '';
var blob = new Blob([ buffer ], { type: type });
response.data = blob;
}
// arraybuffer
else if (responseType === validResponseTypes[2]) {
response.data = base64.toArrayBuffer(response.data);
}
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',
MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" 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) {
var ErrorCode = {
Generic: -1,
SslException: -2,
ServerNotFound: -3,
Timeout: -4,
UnsupportedUrl: -5,
NotConnected: -6,
};
module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConfigs, errorCodes) {
var publicInterface = {
getBasicAuthHeader: getBasicAuthHeader,
useBasicAuth: useBasicAuth,
@@ -38,7 +29,7 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
head: head,
uploadFile: uploadFile,
downloadFile: downloadFile,
ErrorCode: ErrorCode
ErrorCode: errorCodes
};
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 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) {
case 'post':