"Subclass" http and httProvider in AngularJS - angularjs

I want to make a separate $http module that does exactly the same thing as the original $http module, but appends a baseURL to every request.
I know that this can be done with an interceptor, but I don't want this behavior for every instantiation of $http, only for my "subclass" (not really possible in JS) called something like $httpAPI or something.
I've seen similar solutions that do a lot of work by hand. Can I just clone $http and put an interceptor on the cloned version?

Create a service that has $http and an injectable parameter. Implemented the common function you use (get, post, put,... etc). In this new service the baseUrl can be either injected or hard coded.
function myHttp($http, baseUrl){
var internalBaseUrl = baseUrl || 'http://www.baseUrl.com/';
return {
get: function(url){
return $http.get(baseUrl + url);
},
post: function(url, data){
return $http.get(baseUrl + url, data);
}
}
}

Related

Store domain in one place in angular js service

I have the following example method in angular service:
function send(data) {
return $http({
method: 'POST',
url: 'https://test.domain/test/send',
data: $httpParamSerializerJQLike(data)
});
}
The domain that is https://test.domain/test is the same for all the services in my app. I do not want to write it every time in every services. I can abstract it in a constant and inject it in every service but I wonder if there is more clever solution. Is it possible to store the domain part in an interceptor or any other suggestions are welcome. Please provide code examples as I am quite new to angular. Thanks
I'd say rather than abstracting the values out into a constant, you should abstract the $http call into a service. Then you can just inject that service into all of your other services in place of $http. For example:
angular.module('myApp').factory("myHttp", ["$http", function ($http) {
return function (config) {
config.url = "https://test.domain/test" + config.url;
return $http(config);
};
}]);
So effectively what this service is doing is proxying calls to $http, but prepending your common URL to the beginning - this would allow you to change your example code to:
function send(data) {
return myHttp({
method: 'POST',
url: '/send',
data: $httpParamSerializerJQLike(data)
});
}
Of course, this is just one example of how you could do an abstraction like this - the myHttp service could take any form you like, depending on what would be most convenient for you. I think this is a better solution than using an interceptor in this case, as it allows you to pick and choose when you use it, rather than it being applied to every single HTTP request.
create an interceptor and on requests change the url.
angular.module('app').factory('domainInterceptorService', [
function () {
var request = function (config) {
config.url = 'https://test.domain/' + config.url;
}
return config;
}
return {request: request};
});

Access to header information by $resource in AngularJS

I send a request server-side by $resource which is inside my factory.
In the return object there many information, but I'd like to have access to the authorization in the headers.
I tried to print the returning object by console.log() but I dont see any headers and authorization in console. What should I do?
controllers.controller('ProfileSettingCtrl', function ($scope,User) {
User.get({id: 'me'}, function(res) {
console.log(res);
$scope.profile = res;
})
Documentation for $resource
Success callback is called with (value, responseHeaders) arguments.
Seems like you can just get the headers with function (res, headers) { console.log(headers); }
According to the $resource docs, the header is passed as second argument to your success callback.
It's worth noting that the success callback for get, query and other methods gets passed in the response that came from the server as well as $http header getter function, so one could rewrite the above example and get access to http headers as:
var User = $resource('/user/:userId', {userId:'#id'});
User.get({userId:123}, function(u, getResponseHeaders){
u.abc = true;
u.$save(function(u, putResponseHeaders) {
//u => saved user object
//putResponseHeaders => $http header getter
});
});
If you want to use the header information, you have to use the success callback. Otherwise I always advice to use promises, which you can chain and pass around:
User.get().$promise.then(successCallback).catch(errorCallback);

angular-http-auth with $http transformResponse

I'm using angular-http-auth to show a login dialog whenever a 401 "unauthorized" response is returned from the server.
Since I'm cool, I also try to deserialize response objects in my services. For example, if a service requests a car and the response is {make: Honda, model: Civic}, I try to deserialize that into a Car object using transformResponse.
For example:
getCar: function() {
return $http.get('/api/car', {
method: 'GET',
transformResponse: function(data, headers) {
var c = angular.fromJson(data);
return new Car(c);
}
});
}
This doesn't work with angular-http-auth. If the response was a 401 Unauthorized, you'll get a javascript error. It's because angular will try to run that transformResponse code even if the response was a 401.
It turns out that $http interceptors (which is what angular-http-auth uses) are run AFTER the transformResponse code. That's a huge problem, because none of that code in transformResponse will work if the server response was a 401 (there wouldn't be any data)
Is this a problem for anyone else? How did you get around it? Am I not to use transformResponse if I use $http interceptors?
Late to the party, I know, but to anyone coming here from Google like I did (I also posted this as a comment on a related issue filed with the Angular repo):
I also found it to be confusing that response interceptors run after the transformResponse method. I added a method to $http.defaults.transformResponse. Here is an example from the documentation on how to do that.
So, if you need to basically have a response interceptor that runs before the transformResponse method, this should do it:
'use strict';
angular.module('app')
.run(function ($http) {
$http.defaults.transformResponse.push(function (data, headers) {
// do stuff here before the response transformation
// Be sure to return `data` so that the next function in the queue can use it.
// Your services won't load otherwise!
return data;
});
});
If your services or http calls don't have their own response transformer, you're good now.
If your services do have their own transformResponse method, they will actually override all default transformers (I found this out after a long read of the documentation), and the above code will not run.
To circumvent this, you can follow this example in the docs.
To get around this problem I don't use transformResponse anymore. I just can't see the point of transformResponse if it runs before $http interceptors.
In order to use angular-http-auth and also deserialize responses in your services, you can write your services so that they execute the HTTP request first and then deserialize the response in a callback function.
As an example, here is how I would have restructured the example in the OP:
Plunker
services.factory('HttpCarService', function($resource, $q) {
var resource = $resource('/api/car');
return {
getCar: function() {
var deferred = $q.defer();
var car = null;
var successCallback = function(data, status, headers, config) {
var c = angular.fromJson(data);
car = new Car(c);
deferred.resolve(car);
};
var errorCallback = function(data, status, headers, config) {
deferred.reject("something wrong");
};
var result = resource.get(successCallback, errorCallback);
return deferred.promise;
}
};
});
This pattern will also work if data is an array.
$http interceptors will run before either of the callback methods are executed. If your $resource needs url params, you can make the getCar() function accept a config object as a parameter, and pass the necessary information on when you make the $resource.get() call.

AngularJS remote client Properties share to controllers/services

I want to develop an AngularJS web client for which the REST backend may be located on a different server.
So basically I am thinking of having a property input field on the frontend where for each session I will enter the base REST url (e.g., http://localhost:8080/backend/rest/)
Is there some sort of best practice to be able to share the base url amongst all controller/factories/services in order to include it for all $http requests?
I would configure an HTTP request interceptor service that would simply prepend the value to the URL passed to the $http service. Something like the following (not tested):
// register the interceptor as a service
$provide.factory('pathPrependerInterceptor', function() {
var _path = 'http://localhost:8080/backend/rest'; // default value
return {
request: function(config) {
config.url = _path + config.url
return config;
},
setPath: function(path) {
_path = path;
}
}
});
$httpProvider.interceptors.push('pathPrependerInterceptor');
I think the bast way would be to acomplish this with the use of interceptors. You can read more about this topic in the AngularJs documentation.
The idea is to set up an interceptor that will preappend the base url to each request something like this:
var app = angular.module('MyApp',[]);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function($q) {
return {
'request': function(config) {
config.url = "http://api.openweathermap.org/data/2.5/" + config.url
return config;
}
};
});
}]);
I hope you got an idea.
There is JSFiddle that incorporates this idea.
The other answers are from a more experienced bunch, so take this with a pinch of salt, but they seem like overkill to me. You're configuring an application-wide variable which needs injection. Using
module.value("baseRestUrl", ...)
lets you inject baseRestUrl wherever it's required.

Define Service or factory using ngResource to retrieve data from server side?

I'm developing angular web app. And I have this controller which needs to call restful api to do some operations on Users.
Earlier I'm thinking define a service which has some methods: getAllUser( ), getUser(id), saveUser( ), deleteUser( ). these methods will use a ngResource to call rest apis.
But when I look at these methods, it seems to me that I'm just wrapping the ngResource and expose some of his lower level methods: query( ), get( ), save( ), delete( ).
Could someone share some experience about how will you design common services or factories or providers which use ngResource to fetch data from server?
I've been working on an angular project myself. And I'd built a Factory manually, and then ended up using JBoss Forge for my second attempt and that build stuff for me in a pretty nice way, here's what it looked like:
angular.module('myApp').factory('myResource', function($resource){
var urlBase = '/rest/resources';
var resource = $resource(urlBase + '/:RsvpId',{RsvpId:'#id'},{'queryAll':{method:'GET',isArray:true},'query':{method:'GET',isArray:false},'update':{method:'PUT'}});
return resource;
});
That's all there is to it, then when you want to call it, you do something like the following:
$scope.save = function() {
var successCallback = function(data,responseHeaders){
var id = locationParser(responseHeaders);
$location.path('/Resources/edit/' + id);
$scope.status = 'success';
};
var errorCallback = function(data, status, headers, config) {
$scope.status = 'failure';
$scope.statusMessage = 'Saving your resource failed: ' + $scope.errorMessage;
};
myResource.save($scope.resource, successCallback, errorCallback);
};
or to do a get, you'd have this line inside a method:
myResource.get({ResourceId:$routeParams.ResourceId}, successCallback, errorCallback);
or
resource.$remove(successCallback, errorCallback);
Hope that helps.
Let me explain about ngResource...
ngResource is a service from AngularJs and it use at lower lever the $http service, so its very simple to use it when you want to use the RESTFul Resources. Here is my example:
myAppModule.factory('User', ['$resource', function($resource) {
return $resource('/user/:userId'}
]);
So what this code above are doing? This is creating a service that return a resource, the url was mapped, so when you inject and call this service you receive a object with some methods: "GET", "POST", "PUT", "DELETE"... Example:
var users = User.query();
The variable "users", receive all users(and plus it receive some resource features like save, because "users" variable still being a resource object), it's like you make this request (.../user/), ok? All you have to do is call resource, it's very simple.

Resources