angular-http-case-converter
Version:
A module providing simple way to convert request params and response body of backend requests
236 lines (209 loc) • 9.23 kB
JavaScript
/**
* @author Jarek Rencz <jarek.rencz@laboratorium.ee> - current implementation
* @author Michał Gołębiowski <michal.golebiowski@laboratorium.ee> - original idea
* @author Mikołaj Dądela <mikolaj.dadela@laboratorium.ee> - object converter code
*
* (c) Laboratorium EE 2014
*/
(function () {
'use strict';
angular
.module('ee.$http.CaseConverter', [
'ee.$http.CaseConverter.request.camelToSnake',
'ee.$http.CaseConverter.response.snakeToCamel',
]);
})();
/**
* @author Jarek Rencz <jarek.rencz@laboratorium.ee> - package maintainer
* @author Mikołaj Dądela <mikolaj.dadela@laboratorium.ee> - filters code
*
* (c) Laboratorium EE 2014
*/
(function () {
'use strict';
angular
.module('ee.$http.CaseConverter.filter', [])
.constant('eeHttpSnakeToCamelFilterFn', function (input) {
return input.replace(/_([a-zA-Z0-9])/g, function (all, letter) {
return letter.toUpperCase();
});
})
.constant('eeHttpCamelToSnakeFilterFn', function (input) {
return input.replace(/[A-Z]/g, function (letter) {
return '_' + letter.toLowerCase();
});
})
.filter('snakeToCamel', ["eeHttpSnakeToCamelFilterFn", function (eeHttpSnakeToCamelFilterFn) {
return eeHttpSnakeToCamelFilterFn;
}])
.filter('camelToSnake', ["eeHttpCamelToSnakeFilterFn", function (eeHttpCamelToSnakeFilterFn) {
return eeHttpCamelToSnakeFilterFn;
}]);
})();
/**
* @author Jarek Rencz <jarek.rencz@laboratorium.ee> - package maintainer
* @author Michał Gołębiowski <michal.golebiowski@laboratorium.ee> - original idea
*
* (c) Laboratorium EE 2014
*/
(function () {
'use strict';
angular
.module('ee.$http.CaseConverter.request.camelToSnake', [
'ee.$http.CaseConverter.utils',
'ee.$http.CaseConverter.settings',
])
.config(["$provide", "$httpProvider", function ($provide, $httpProvider) {
$provide.factory('httpCaseConverterCamelToSnakeRequestInterceptor',
["eeHttpCaseConverterUtils", "eeHttpCaseConverter", function (eeHttpCaseConverterUtils, eeHttpCaseConverter) {
return {
request: function (requestConfig) {
if (eeHttpCaseConverter.condition.request.camelToSnake.data(requestConfig)) {
requestConfig.data =
eeHttpCaseConverterUtils.convertKeyCase.camelToSnake(requestConfig.data);
}
if (eeHttpCaseConverter.condition.request.camelToSnake.params(requestConfig)) {
requestConfig.params =
eeHttpCaseConverterUtils.convertKeyCase.camelToSnake(requestConfig.params);
}
return requestConfig;
},
};
}]);
$httpProvider.interceptors.push('httpCaseConverterCamelToSnakeRequestInterceptor');
}]);
})();
/**
* @author Jarek Rencz <jarek.rencz@laboratorium.ee> - package maintainer
* @author Michał Gołębiowski <michal.golebiowski@laboratorium.ee> - original idea
*
* (c) Laboratorium EE 2014
*/
(function () {
'use strict';
angular
.module('ee.$http.CaseConverter.response.snakeToCamel', [
'ee.$http.CaseConverter.utils',
'ee.$http.CaseConverter.settings',
])
.config(["$provide", "$httpProvider", function ($provide, $httpProvider) {
$provide.factory('httpCaseConverterSnakeToCamelResponseInterceptor',
["$q", "eeHttpCaseConverterUtils", "eeHttpCaseConverter", function ($q, eeHttpCaseConverterUtils, eeHttpCaseConverter) {
var convert = function (response) {
if (eeHttpCaseConverter.condition.response.snakeToCamel(response)) {
response.data = eeHttpCaseConverterUtils.convertKeyCase.snakeToCamel(response.data);
}
return response;
};
return {
response: function (response) {
return convert(response);
},
responseError: function (response) {
return $q.reject(convert(response));
},
};
}]);
$httpProvider.interceptors.push('httpCaseConverterSnakeToCamelResponseInterceptor');
}]);
})();
/**
* @author Jarek Rencz <jarek.rencz@laboratorium.ee>
*
* (c) Laboratorium EE 2014
*/
(function () {
'use strict';
angular
.module('ee.$http.CaseConverter.settings', [])
.provider('eeHttpCaseConverter', function () {
var caseConverterProvider = this;
// This may be replaced with any custom logic callable to provide more precise yet still standard condition.
caseConverterProvider.requestUrlFilter = function () {
return true;
};
// This may be replaced with any custom logic callable to provide more precise yet still standard condition.
caseConverterProvider.responseUrlFilter = function () {
return true;
};
caseConverterProvider.requestConfig = {
camelToSnake: {
data: function (config) {
// Only PATCH, POST, PUT methods can have data
return ['PATCH', 'POST', 'PUT'].indexOf(config.method) > -1 &&
!!config.data &&
caseConverterProvider.requestUrlFilter(config.url);
},
params: function (config) {
return !!config.params && caseConverterProvider.requestUrlFilter(config.url);
},
},
};
caseConverterProvider.responseConfig = {
snakeToCamel: function (response) {
var contentTypeHeader = response.headers('content-type');
var isValid = caseConverterProvider.responseUrlFilter(response.config.url);
return !!contentTypeHeader && isValid && contentTypeHeader
.split(';')
.map(function (header) {
return header.trim();
})
.indexOf('application/json') > -1;
},
};
caseConverterProvider.$get = function () {
return {
condition: {
request: caseConverterProvider.requestConfig,
response: caseConverterProvider.responseConfig,
},
};
};
});
})();
/**
* @author Jarek Rencz <jarek.rencz@laboratorium.ee> - package maintainer
* @author Mikołaj Dądela <mikolaj.dadela@laboratorium.ee> - object converter code
* @author Patryk Hes <patryk.hes@laboratorium.ee> - object converter code
*
* (c) Laboratorium EE 2014
*/
(function () {
'use strict';
angular
.module('ee.$http.CaseConverter.utils', [
'ee.$http.CaseConverter.filter',
])
.service('eeHttpCaseConverterUtils', ["$filter", function ($filter) {
function getClass(obj) {
// Workaround for detecting native classes.
// Examples:
// getClass({}) === 'Object'
// getClass([]) === 'Array'
// getClass(function () {}) === 'Function'
// getClass(new Date) === 'Date'
// getClass(null) === 'Null'
// Here we get a string like '[object XYZ]'
var typeWithBrackets = Object.prototype.toString.call(obj);
// and we extract 'XYZ' from it
return typeWithBrackets.match(/\[object (.+)\]/)[1];
}
function createConverterFunction(keyConversionFun) {
return function convertObjectKeys(obj) {
// Creates a new object mimicking the old one with keys changed using the keyConversionFun.
// Does a deep conversion.
if (getClass(obj) !== 'Object' && getClass(obj) !== 'Array') {
return obj; // Primitives are returned unchanged.
}
return Object.keys(obj).reduce(function (newObj, key) {
newObj[keyConversionFun(key)] = convertObjectKeys(obj[key]);
return newObj;
}, Array.isArray(obj) ? [] : {}); // preserve "arrayness"
};
}
this.convertKeyCase = {
snakeToCamel: createConverterFunction($filter('snakeToCamel')),
camelToSnake: createConverterFunction($filter('camelToSnake')),
};
}]);
})();