Add authorization header with transformRequest - javascript

this should be quite easy, but in the end is not working :(.
We use Angular 1.4.3, and we try to add an Authorization header value before some API calls.
Long story short, there is a factory:
angular.module('xxx').factory('factory', function ($resource, addBasicAuth) {
return $resource(baseUrl, {}, {
query: {method: 'GET', isArray: true, transformRequest: addBasicAuth},
...
});
});
And the addBasicAuth goes as follows:
angular.module('xxx').factory('addBasicAuth', function ($rootScope) {
return function (data, headersGetter) {
var user = ($rootScope.user);
headersGetter().Authorization = 'Basic ' + Base64.encode(user.username + ':' + user.password);
return angular.toJson(data);
};
});
And in theory all should work fine, but for the reason I do not understand, the requestHeader is untouched (checked in Developers Tools/Network - Chrome).
What am I doing wrong? Thanks!

my colleague helped me out with a following solution;
instead of transformRequest we use headers and it goes like this:
angular.module('xxx').factory('factory', function ($resource, addBasicAuth) {
return $resource(baseUrl, {}, {
query: {
method: 'GET',
isArray: true,
headers: addBasicAuth()
},
...
});
});
and the addBasicAuth is now a factory function:
angular.module('xxx').factory('addBasicAuth', function ($rootScope) {
return function () {
var user = ($rootScope.user);
return {'Authorization': 'Basic ' + Base64.encode(user.username + ':' + user.password)};
};
});
Works like a charm.

Related

AngularJS + API call

Trying to understand how AngularJS works, doing my first API calls, when I got stuck.
I want to do 2 API calls, but I can't seem to make it work.
After the first $http.get I want to do an another call (using the information from the previous call) but that doesn't work for some reason. (I get no alert)
The city and country are working perfectly after the first .get
JS:
var app = angular.module('weather', []);
app.controller("weatherCtrl", function($scope, $http) {
$http.get("http://ipinfo.io/json").then(function(response) {
$scope.city = response.data.city;
$scope.country = response.data.country;
var apiKey = "";
var apiCall = "api.openweathermap.org/data/2.5/weather?q=" + response.data.city + "&APPID=" + apiKey;
$http.get(apiCall).then(function(responsew) {
// $scope.temperature would get a value here
alert("1")
});
});
})
HTML:
<body ng-app="weather" ng-controller="weatherCtrl">
<h1 class="text-center">Weather</h1>
<h2 class="text-center">{{city}}, {{country}}</h2>
<h2 class="text-center">{{temperature}} °C</h2>
</body>
You can use promise to call the request after another which is the recommended way to do,
Another thing is you are missing the http part in the second request
Code:
app.controller("weatherCtrl", function ($scope, $http) {
function infoReq() {
return $http({
method: 'Get',
url: 'http://ipinfo.io/json'
})
}
function weatherReq() {
var apiKey = "";
var apiCall = "http://api.openweathermap.org/data/2.5/weather?q=" + $scope.city + "&APPID=" + apiKey;
return $http({
method: 'Get',
url: apiCall,
})
}
$scope.makeRequest = function () {
infoReq()
.then(function (response) {
$scope.city = response.data.city;
$scope.country = response.data.country;
return weatherReq();
})
.then(function (response) {
console.log(response.data);
})
}
})
var req = {
method: 'POST',
url: "http://api.openweathermap.org/data/2.5/weather?q=" + $scope.city + "&APPID=" + apiKey;
headers: {
'Content-Type': undefined
},
data: { test: 'test' }
}
$http(req).then(function(){...}, function(){...});
You can use the above http service to make the request inside your angularjs controller.

weird javascript behavior - logging in chrome

I have something really weird going on in my code. An object is sent by the server in a correct way, and it even arrives in my angular factory and i log the object the following shows:
notice how course_id is an integer and 20 when the object is not expanded, when i expand it becomes a string and 19. I am going insane. Has anyone ever had this before? I'm sure there's a reason to this madness!
my angular service:
/*********************************
* get one batch
*********************************/
get: function(batch_id) {
var deferred = $q.defer();
var request = $http({
method: 'GET',
url: ENV.api + 'batch/get/' + batch_id,
headers: {
'Content-Type': 'application/json'
}
});
request
.success(function(result) {
console.log(result);
deferred.resolve(result);
})
.error(function(error) {
console.error(error);
deferred.reject(error);
});
return deferred.promise;
},
i have figured out a way around it, and a possible answer:
https://docs.angularjs.org/api/ng/function/angular.copy
and
Why do I need to use angular.copy in my factory?
/*********************************
* get one batch
*********************************/
get: function(batch_id) {
var deferred = $q.defer();
var request = $http({
method: 'GET',
url: ENV.api + 'batch/get/' + batch_id,
headers: {
'Content-Type': 'application/json'
}
});
request
.success(function(result) {
console.log(angular.copy(result));
deferred.resolve(angular.copy(result));
})
.error(function(error) {
console.error(error);
deferred.reject(error);
});
return deferred.promise;
},

How to send a custom header on every request with an angular resource?

I like to send a custom header on every request with an angularjs resource. Before every request the header has to be created again. The following doesn't work. The header is calculated only once and because of this only one request works. A second request on the same resource fails. Its a lot of copy n paste of "headers: authhandler.createHeader()" also ...
myApp.service('Rest', ['$resource', 'authhandler',
function($resource, 'authhandler',{
return {
User: $resource( api_domain + "/api/users/:userid", {}, {
get: {method: 'GET', headers: authhandler.createHeader()},
remove: {method: 'DELETE', headers: authhandler.createHeader()},
edit: {method: 'PUT', headers: authhandler.createHeader()},
add: {method: 'POST', headers: authhandler.createHeader()},
patch: {method: 'PATCH', headers: authhandler.createHeader()}
}),
};
}]);
Has someone an idea how to solve this ?
I had a working solution but I don't like it because of huge amount of copy and paste source code:
myApp.controller('MyController', function(RestResource, authhandler, $routeParams) {
$http.defaults.headers.common = authhandler.createHeader();
RestResource.get({userid: $routeParams.id}, function(result) {
//...
});
});
I Would be very happy about hints how to solve this ! Thanks in advance!
You can use a request transformer:
function($resource, 'authhandler',{
return {
User: $resource( api_domain + "/api/users/:userid", {}, {
get: {
method: 'GET',
transformRequest: function(data, headersGetter) {
var currentHeaders = headersGetter();
angular.extend(currentHeaders, authhandler.createHeader());
return data;
}
},
You could also add the transformer to all requests:
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.transformRequest.push(function(data, headersGetter) {
var currentHeaders = headersGetter();
angular.extend(currentHeaders, authhandler.createHeader());
return data;
});
That way you don't have to configure anything or your resources.

Angularjs: Singleton service using $http [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
is it possible in angular to create service using $http which will take method, url, success and failure callback as parameters when called from controller.
I want to achieve following kind of functionality using angular.
var ajax = {
URL: "webservice url",
loggedIn: false,
importedId: "",
token: '',
userdetails: new Backbone.Collection.extend({}),
serverCall: function(method, data, successCallBack, failureCallBack) {
var that = this;
//console.log(method);
//console.log(successCallBack);
that.showLoading();
$.ajax({
url: that.URL + method,
method: 'post',
data: data,
// contentType:"application/json; charset=utf-8",
success: function(data) {
that.hideLoading();
if (that.checkForError(data))
{
successCallBack(data);
}
},
fail: function(data) {
that.hideLoading();
failureCallBack(data);
}
});
}
i am using https://github.com/StarterSquad/startersquad.github.com/tree/master/examples/angularjs-requirejs-2 folder structure for app and inside services i have following code
define(['./module'], function(services) {
'use strict';
services.factory('user_resources', ['$resource', '$location', function($resource, $location) {
return $resource("", {},
{
'getAll': {method: "GET", url:'JSON/myList.JSON',isArray:true}
});
}]);
});
and in controller i have following code
define(['./module'], function (controllers) {
'use strict';
controllers.controller('myListCtrl',['Phone','Phone1','loginForm','$scope','$http','user_resources','CreditCard',function(Phone,Phone1,loginForm,$scope,$http,user_resources,CreditCard){
console.log(user_resources.getAll())
}]);
});
which returns [$promise: Object, $resolved: false] how to get data from that?
A service in AngularJS is always a singleton, so you wouldn't have to do anything to achieve that. However, it seems like you do not actually want a singleton as you want to pass in different values. Thus, you might want to add your own service factory function. Something like:
function MyHTTPService($rootScope, url, method) {
this.$rootScope = $rootScope;
this.url = URL;
this.method = method;
}
MyHTTPService.prototype.serverCall = function () {
// do server call, using $http and your URL and Method
};
App.factory('MyHTTPService', function ($injector) {
return function(url, method) {
return $injector.instantiate(MyHTTPService,{ url: url, method: method });
};
});
This can be called using
new MyHTTPService("http://my.url.com", "GET");
you could also use $resource for this type of usage.
angular.module('MyApp.services').
factory('User_Resource',["$resource","$location", function ($resource,$location){
var baseUrl = $location.protocol() + "://" + $location.host() + ($location.port() && ":" + $location.port()) + "/";
return $resource(baseUrl+'rest/users/beforebar/:id',{}, {
query: { method: 'GET', isArray: true },
get: { method: 'GET' },
login: { method: 'POST', url:baseUrl+'rest/users/login'},
loginAnonymous: { method: 'POST', url:baseUrl+'rest/users/loginAnonymous'},
logout: { method: 'POST', url:baseUrl+'rest/users/logout/:id'},
register: { method: 'POST', url:baseUrl+'rest/users/register'}
});
}]);
Example of usage :
userSrv.logout = function(user,successFunction,errorFunction)
{
var userSrv = new User_Resource();
userSrv.$logout({user.id}, //params
function (data) { //success
console.log("User.logout - received");
console.log(data);
if (successFunction !=undefined)
successFunction(data);
},
function (data) { //failure
//error handling goes here
console.log("User.logout - error received");
console.log(data);
var errorMessage = "Connexion error";
if (errorFunction !=undefined)
errorFunction(errorMessage);
});
}

How to "rebuild" a $resource from a factory in angularjs?

I'm implementing my own API-Token system into my AngularJS-Laravel project, so the API-Token is sent over $http using headers. The thing is, when a user logs in, it sets the API token in the API factory, but the $resource doesn't get updated.
myApp.factory('Api', ['$resource', '$http', '$cookies',function($resource, $http, $cookies) {
var baseURL = 'an api url';
var APIToken = $cookies.token;
return {
SetToken: function(token) {
APIToken = token;
console.log(APIToken);
},
Authenticator: function(data,callback) {
$http({
url: baseURL + 'auth',
method: "GET",
params: data
}).success(callback);
},
Authors: $resource(baseURL + "journalists/:id", {id: '#id'}, {
update: {
method:'PUT',
headers: { 'API-Token': APIToken }
},
query: {
method:'GET',
isArray: true,
headers: { 'API-Token': APIToken }
}
}),
};
}]);
The most interesting part is the headers: { 'API-Token': APIToken } part. The problem is that when SetToken is called, the headers won't get updated. Is there any way around this? Am I using the wrong function for this?
Your $resource object is created and setup only once when it is called. It doesn't access the APIToken variable every time you make a call to one of its functions. In order to make the code above work, you would have to call SetToken() before you call Authors() because once you call Authors(), the $resource object is created and will use the value of APIToken at that moment. I don't know of any way to do what you want and still use the $resource service. You might have to just use the $http service directly, like you're doing for your Authenticator function.
Authors: {
update: function(obj){
$http({
url: baseURL + 'journalists/' + obj.id,
method: "PUT",
params: obj
});
},
query: function(obj){
$http({
url: baseURL + 'journalists/' + obj.id,
method: "GET",
params: obj
});
},
})
Or something like that. Hope that helps.

Categories

Resources