\$\begingroup\$
\$\endgroup\$
Could you please review the below AngularJS service. What it does is centralize all (relevant) HTTP action calls.
Do you see any chances for improvement?:
"use strict";
angular.module("services.api")
.factory("apiService", [
"$http",
"$q",
"coreUtilityService",
"constantsServiceNames",
"constantsApiRequestFor",
function (
$http,
$q,
coreUtilityService,
constantsServiceNames,
constantsApiRequestFor
) {
// === START SERVICE === //
var self = {};
self.Name = constantsServiceNames.ApiService;
self.ExecuteRequest = function(verb, fullUri, data) {
var defer = $q.defer();
verb = verb.toLowerCase();
//start with the uri
var httpArgs = [fullUri];
if (verb.match(/post|put/)) {
httpArgs.push(data);
}
$http[verb].apply(null, httpArgs)
.success(function (response) {
defer.resolve(response);
})
.error(function (response, status) {
defer.reject("HTTP Error: " + status);
});
return defer.promise;
}
/*
Do a request to any RESTful receiver. Meant for external use only, use DoViewRequest
for internal requests.
*/
self.DoRequest = function (verb, uri, data) {
var fullUrl = coreUtilityService.GetBaseUrl(constantsApiRequestFor.WebAPI, uri);
return self.ExecuteRequest(verb, fullUrl, data);
};
/*
This will target an MVC View of the client application. The url will be different.
*/
self.DoViewRequest = function (verb, uri) {
var fullUrl = coreUtilityService.GetBaseUrl(constantsApiRequestFor.View, uri);
return self.ExecuteRequest(verb, fullUrl, null);
};
// === PUBLIC === //
return {
Get: function (uri) {
return self.DoRequest("get", uri);
},
Post: function (uri, data) {
return self.DoRequest("post", uri, data);
},
Put: function (uri, data) {
return self.DoRequest("put", uri, data);
},
Delete: function (uri) {
return self.DoRequest("delete", uri);
},
View: function (uri) {
return self.DoViewRequest("get", uri);
}
}
// === END SERVICE === //
}]);
Roamer-1888
1,3176 silver badges9 bronze badges
1 Answer 1
\$\begingroup\$
\$\endgroup\$
4
A few ideas - nothing major :
- Encapsulating the methods in
self
doesn't really add anything. A set of function statements or function expressions would do the job andself.
could be purged all through. - The explicit promise construction antipattern should be purged.
- "method" would be better understood than "verb".
- Does
DoRequest()
not throw whendata
is not passed? Do range checking indoRequest()
instead ofExecuteRequest()
. - Possibly allow for omitted
uri
, defaulting to empty string (browser will use current page's url). Could be useful in some use cases. - By convention Initial-caps are reserved for constructors. Change to lower-case all through.
- Possibly use Function.prototype.bind() in the exposer. (Check that browser compatibility is acceptable).
angular.module("services.api").factory("apiService", [
"$http",
"$q",
"coreUtilityService",
"constantsServiceNames",
"constantsApiRequestFor",
function (
$http,
$q,
coreUtilityService,
constantsServiceNames,
constantsApiRequestFor
) {
// === START SERVICE === //
// var name = constantsServiceNames.ApiService; // necessary?
var executeRequest = function(method, fullUri, data) {
method = method.toLowerCase();
var httpArgs = [fullUri];
if (data) {
httpArgs.push(data);
}
return $http[method].apply(null, httpArgs).then(null, function (response) {
throw new Error("HTTP Error: " + response.status);
});
};
/*
Do a request to any RESTful receiver. Meant for external use only, use DoViewRequest
for internal requests.
*/
var doRequest = function (method, uri, data) {
uri = uri || '';
data = (!data || !method.match(/post|put/)) ? null : data; // or similar
return ExecuteRequest(method, coreUtilityService.GetBaseUrl(constantsApiRequestFor.WebAPI, uri), data);
};
/*
This will target an MVC View of the client application. The url will be different.
*/
var doViewRequest = function (method, uri) {
uri = uri || '';
var fullUrl = coreUtilityService.GetBaseUrl(constantsApiRequestFor.View, uri);
return ExecuteRequest(method, fullUrl, null);
};
// === PUBLIC === //
return {
'get': doRequest.bind(null, 'get'),
'post': doRequest.bind(null, 'post'),
'put': doRequest.bind(null, 'put'),
'delete': doRequest.bind(null, 'delete'),
'view': doViewRequest.bind(null, 'get')
};
// === END SERVICE === //
}]);
answered Nov 29, 2015 at 18:31
-
\$\begingroup\$ All very good points, thanks! A question with point 7, shouldn't there be a data parameter in the
bind()
for post/put? \$\endgroup\$kbd– kbd2015年11月30日 07:08:50 +00:00Commented Nov 30, 2015 at 7:08 -
\$\begingroup\$ Bind statements often look wrong. I've used them quite a bit and still have to concentrate. The thing to remember is that
.bind()
is not a call but something that returns a function. Here, anull
context is provided (doRequest() and doViewRequest() don't usethis
therefore don't need a context), and "get" etc are "bound-into" the returned function as its first param. Further param(s) are passed when the returned function is eventually called for real, and don't need to appear in these.bind()
statements. \$\endgroup\$Roamer-1888– Roamer-18882015年11月30日 12:07:58 +00:00Commented Nov 30, 2015 at 12:07 -
\$\begingroup\$ I'll look into it when able, thanks for the information! \$\endgroup\$kbd– kbd2015年11月30日 12:26:19 +00:00Commented Nov 30, 2015 at 12:26
-
\$\begingroup\$ Minor side note regarding 6: I'm not a fan of lowerCamelCase for functions/methods, because that makes callbacks confusing. Hard to see if you're passing a variable or function. I prefer the .net naming rules. \$\endgroup\$kbd– kbd2015年11月30日 12:51:04 +00:00Commented Nov 30, 2015 at 12:51
Explore related questions
See similar questions with these tags.
default