When i tried to access star wars API using $http method . am getting 403 response with message "Invalid basic header. No credentials provided" what am missing here?
$http({
method : 'GET',
url : 'https://swapi.co/api/people/'
}).then(function(success) {
var data = JSON.parse(body);
var result = data.result.filter(function each(r) {
return username == r.name && password == r.birth_year;
});
}, function(error) {
alert('not logged::' + eror)
});
Could you please someone help me to find the issue?
You are using wrongly the data returned by the get call.
You don't need to parse it to JSON, it's already a JSON.
Here's a plunker with a call to the API working. Hope it helps you
https://plnkr.co/edit/WKQfqc7wxmBJIjYUyZKe
angular.module('myApp', []).controller('myAppController', function($http, $scope) {
$scope.callApi = function() {
$http.get('https://swapi.co/api/people/').then(function(result) {
$scope.characters = result.data.results;
}, function(error) {
alert('not logged::' + error)
});
}
});
Related
I'm a new developer and I'm having some issues. I'm using AngularJS and I use a service to return the users from a database.
I have an factory in my Service.js to specify the http service:
dashboard.factory('User', ['$resource', 'urlPrefix',
function ($resource, urlPrefix) {
return $resource(urlPrefix + '/user/json/getUsersByName', {
id: '#id'
}, {
getUsersByName: {
globalError: false,
method: 'GET',
isArray: true
}
});
}
]);
The user controller receives two entries(userName and maxResults):
#ControllerSupport
public List< User > getUsersByName() {
String userName = getParameter( "userName", String.class );
Integer maxResults = getParameter( "maxResults", Integer.class );
return userService.findByName( userName, maxResults );
}
I'm calling the service as you can see above:
$scope.queryDashboardUsers = function () {
User.getUsersByName({
'userName': $scope.username.search,
'maxResults': 100
}).$promise.then(
function (response) {
console.log('users', response);
});
};
And receiving the following error:
Error: **[$resource:badcfg] ** object http://errors.angularjs.org/1.2.20/$resource/badcfg?p0=array
As I was reading in the forum, query returns an array and get returns an object.
So I've tried to call:
return $resource(urlPrefix + '/user/json/getUsersByName', ...).query();
and
return $resource(urlPrefix + '/user/json/getUsersByName', ...).get();
And neither them worked.
If I look at "Network" in Chrome, I can see the request response and that's right. So I imagine that I'm having a problem of conversion between Object and Array but I have no idea where.
Could someone help me?
I solved the problem changing the service to:
dashboard.factory('User', ['$resource', 'urlPrefix',
function ($resource, urlPrefix) {
return $resource(urlPrefix + '/user/json/getUsersByName', {}, {});
}
]);
But I really don't understand why the service before didn't work. Does someone know?
Inside my controller I have a call to fetch a document from my back end that looks like this:
orderFactory.query({_id: $stateParams.obj}).$promise.then(
function (response) {
console.log(response);
$scope.invoice = response[0].invoice;
$scope.client = response[0].client;
$scope.orderdetails = response[0].orderdetails;
},
function (response) {
console.log(response);
$scope.message = "Error: " + response.status + " " + response.statusText;
});
But the problem is that this code sends a GET request to /orders&_id=5926bef0f5344c1ff8a9b295 but the REST end point it should access is /orders/5926bef0f5344c1ff8a9b295
The URL in the browser is /trackdetails and I cant use $stateParams to access the end point desired
So my question is there any way to access that end point from the controller? Or perhaps I have to rework my architecture?
In resource:
$resource('your_url/:_id',
{
_id: '#_id'
}
)
In component:
orderFactory.get({_id: $stateParams.obj}, function(response) {
// success
}, function(reject) {
// error
})
Im working with angularjs and Im trying to handle errors with interceptors.
I have run into the issue of how handling the different error session expires with login failed when server replies both with 401.
It seems that interceptors defined in the config will execute before any other interceptors (order definition matters):
var configInterceptor = function($httpProvider)
{
$httpProvider.interceptors.push('unauthorizedInterceptor');
};
angular.module('app', [])
.config(configInterceptor)
.controller....
The interceptors defined in the $resource will be considered only after they have gone through the configInterceptor.
var res = $resource(serviceUrl + '/users/login',{},{
post:{
method:'POST',
params: {},
withCredentials: true,
interceptor: {
responseError: function(){
console.log('login interceptor');
}
}
}
});
I would like to have a single point for controlling when the session has expired (pushing the user to the login page and sending an appropriate message) without the need to add the unauthorizedInterceptor to all $resources, one by one.
If the error is due to users trying to log in and failed, then the interceptor should treat it differently (message will be different).
Any way to resolve this properly? I tried also defining interceptors to only be applied to a specific module but they are triggered.
I would do something like that:
angular.module('app', []).factory('unauthorizedInterceptor', unauthorizedInterceptor);
function unauthorizedInterceptor($q, ngUserAuthService) {
return {
'responseError': function (response) {
if (response.status === 401) {
// find out if the session has expired or the user login has failed
if (sessionExpired()) {
doRedirectToSomewhere();
} else if (loginHasFailed()) {
response.loginFailed = true; // use this later
}
}
return $q.reject(response);
}
};
}
And then only add an interceptor to the $resource when you want to check for failed login:
var res = $resource(serviceUrl + '/users/login',{},{
post:{
method:'POST',
params: {},
withCredentials: true,
interceptor: {
responseError: function(response) {
console.log('login interceptor');
console.log('The login has failed: ' + response.loginFailed);
}
}
}
});
I am using the Django REST token authentication for my API.
I posted my credentials to obtain token endpoint. However when I try to set the header in a correct way it keeps responding with a http 401 error. I tried it using curl -X GET http://127.0.0.1:8000/events/ -H 'Authorization: Token 4d92d36768ca5d555b59cf68899eceab39c23704 ' and that does work! This is my code:
app.controller('HomeController', ['$scope','$http', function($scope,$http) {
$scope.username = '';
$scope.password = '';
$scope.submitLogin = function () {
var credentials = {
username : $scope.username,
password : $scope.password,
};
var req = $http.post('http://127.0.0.1:8000/api-token-auth/', credentials);
req.success(function(data, status, headers, config) {
$scope.token = data.token;
var str1 = 'Token ';
$scope.tokenheader = str1.concat($scope.token);
$http.defaults.headers.common.Authorization = $scope.tokenheader;
});
req.error(function(data, status, headers, config) {
alert( "failure message: " + JSON.stringify({data: data}));
});
};
$scope.getEvents = function () {
var req = {
method: 'GET',
url: 'http://127.0.0.1:8000/events/',
}
$http(req).then(
function() {
console.log('succes')
},
function(){
console.log('fail')
});
};
}]);
And the error message in chrome dev tools:
XMLHttpRequest cannot load http://127.0.0.1:8000/events/.
Response for preflight has invalid HTTP status code 401
How do I get rid of this 401 error?
Edit: I just found out the fault lies in the fact that I did not have CORS installed on my API. I was using a CORS plugin in chrome that worked for the authentication part of my api but not for my events url!
Did you check that the token is actually added to your request?
You can do this for example using the Chrome developers tools.
Personally I prefer to use the $httpprovider.interceptor as described in:
angularjs $httpProvider interceptor documentation
This ensures that the tokens are always present on any call.
If you are accessing more than one API, you should consider adding something like:
$httpProvider.interceptors.push(['$q', '$location', '$log', 'loginService', 'restHelperService',
function ($q, $location, $log, loginService, restHelperService) {
return {
request: function (config) {
// check if the request comes with an url
if (config.url) {
// check that the call is to the REST api, if yes add token
if (restHelperService.isRestCall(config.url)) {
// add auth header or revert to login
if (loginService.userIsLoggedIn()) {
config.headers = config.headers || {};
config.headers.Authorization = 'Token ' + loginService.getToken().token;
} else {
$location.path('/login');
}
}
}
return config;
},
responseError: function (response) {
if (response.status === 401 || response.status === 403) {
// clear auth token if the REST call failed with the current token
if (response.config && response.config.url && restHelperService.isRestCall(response.config.url)) {
$log.debug(" restCall failed due to bad credentials, resetting credentials");
loginService.resetCredentials();
$location.path('/login');
}
}
return $q.reject(response);
}
};
}]);
}])
This avoid issues that will arise when you start adding the token to API calls that don't expect them. Also the code ensures that a user will be automatically redirected to the login page if the credentials are not valid.
The example, I'm using two additional services. A loginService that manages the tokens and a restHelperService that manages the urls of the REST framework.
I would recommend doing the same as else it will be hard to access the credentials from outside your controller.
You need to add Token to the headers:
get($http, "/some_url", {headers: {"Authorization": "Token " + $your_token}}
....
....
);
Response code 401 means Unauthorized. If you are using Token based authentication then in case of fail it would be 403, Forbidden.
So my guess would be that it's username/password who is messing with it. In your curl example you are not using them.
I'm hitting an API which requires all authenticated actions to include an auth token in the request, however, I do not have the auth token until I login.
I've only seen examples of setting default request parameters in Restangular in app.config.
Is it possible to set this until after the user has logged in and User.auth_token is set?
So basically instead of:
app.config(function(RestangularProvider) {
RestangularProvider.setDefaultRequestParams({
auth_token: 'thisistheauthenticationtoken'
});
});
I need:
app.config(function(RestangularProvider) {
RestangularProvider.setDefaultRequestParams({
auth_token: User.auth_token
});
});
Why would you set token as part of the response versus in the header? Like so.
Restangular.setDefaultHeaders({ authentication: 'bearer ' + token.authentication });
I know this is an old thread but this SO question kept appearing when I was Googling (yes, I just used Google as a verb... deal with it :P) for a resolution, so I thought I should provide my solution. Hopefully it will help the OP or anyone else that may come across this page.
angular.module("app").factory("UserService", [
"$rootScope",
"$state",
"$q",
"Restangular",
function ($rootScope, $state, $q, Restangular) {
var UserSvc = {};
var Identity;
/*
This creates a scoped copy of Restangular
Normally this is where you would use setDefaultRequestParams,
but it would only affect this scope and not ALL API requests in your app
*/
var UsersAPI = Restangular.withConfig(function (RestangularConfigurer) {
RestangularConfigurer.setBaseUrl("api/1.0/users");
});
UserSvc.login = function (credentials) {
var $defer = $q.defer();
UsersAPI.all("start-session").post(credentials).then(function(respData){
if (respData.apikey) {
Identity = respData.plain();
/*
User is authenticated and API key is obtained from server response
Note how I do NOT use the setDefaultRequestParams function:
If we do the withConfig/setDefaultRequestParams, it only affects local scope, not global
This method modifies the ROOT Restangular object and
will then propegate through all future use of Restangular in your app
*/
Restangular.configuration.defaultRequestParams.common.apikey = Identity.apikey;
if ($rootScope.toState && $rootScope.toState.name != "login") {
$state.go($rootScope.toState.name, $rootScope.toStateParams || {});
} else {
$state.go("app.dashboard");
}
$defer.resolve(Identity);
}
else {
Identity = undefined;
$defer.reject(Identity);
}
},function (respData) {
$defer.reject(respData);
});
return $defer.promise;
};
return UserSvc;
}
]);
In my case, I use
Restangular.setDefaultRequestParams({token: localstorage.get('token')});
This works with me. Please have a look my snippet here.
https://github.com/fugokidi/ng-snippets/blob/master/rest.js
If you want to do something like this, you need to remove your code from app.cofig and move to when you find user is logged in.
You can set defaultRestParams for restangular at any point of application using Restangular service.
For more info refer https://github.com/mgonto/restangular#setdefaultrequestparams.
A more Angular-ish example from a project that I've been working on:
angular.module('app', [ 'restangular' ])
.factory('API', function(Restangular){
return Restangular.withConfig(function(config){
config
.setBaseUrl('https://api.example.com')
// etc etc etc
; // END config
});
})
.factory('Auth', function(API){
return {
login: function(credentials){
// Assuming I just POST /session/new to get an OAuth token,
// which is totally not a thing that OAuth should do.
API.one('session').post('new', credentials)
.then(function(auth){ // Assuming `auth = { access_token: '...' }`
API.setDefaultHeaders({
Authorization: 'bearer ' + auth.access_token
// Assuming OAuth Bearer Token
});
})
},
logout: function(){ /* . . . */ }
};
})
.controller('MainController', function(API, Auth){
var self = this;
self.user = { };
this.login = function(credentials){
Auth.login(credentials).then(function(){
self.user = API.one('user').$object;
});
});
})
; // END module(app)
The following code will read the token from storage for every request.
app.config(function(RestangularProvider) {
//Injext $cookies manually (there might be better ways to do this)
var $cookies;
angular.injector(['ngCookies']).invoke(['$cookies', function(_$cookies_) {
$cookies = _$cookies_;
}]);
RestangularProvider.setDefaultHeaders({
Authorization: function() {
return $cookies.get('token');
}
});
});
I too struggled with this.
Instead of using
RestangularProvider.setDefaultRequestParams({
auth_token: 'thisistheauthenticationtoken'
});
try using
Restangular.setDefaultRequestParams({auth_token:'thisistheauthenticationtoken'});