Angularjs - $resource causing a 404 - method: OPTIONS - angularjs

I am trying to get a basic $resource request via angularjs. I am running this on my local computer.
However, I get a 404. A simple get request on the browser loads the json.
Here is the request shown by chrome devtools. (Question: why is the request mode: OPTIONS? Could that be the problem?)
Request URL:http://example.com/api/rentable_properties.json
Request Method:OPTIONS
Status Code:404 Not Found
Here is my controller that is attempting to make the request:
'use strict';
angular.module('adminApp')
.factory('Property', function($resource)
{
return $resource('http://example.com/api/rentable_properties.json/:propertyId');
});
angular.module('adminApp')
.controller('PropertiesCtrl', function ($scope, Property, $location) {
$scope.properties = Property.query()

The answer here is that your browser is running into a cross domain issue
See http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/ for an explanation and Why am I getting an OPTIONS request instead of a GET request? for a question basically the same as yours.

As mentioned by #JSager, the problem was a cross domain issue.
Since I had control over the server side (running a Rails server), I had to change the server to it to receive cross-site requests.
In my case, I had to install a gem and follow it's instructions.
https://github.com/cyu/rack-cors
This fixed the issue for me. No changes made on the Angularjs based app.

Related

AngularJs + Django RESTful: session based authentication

I'm developing an angular web application that will replace the current website that we have. The current website uses session based authentication. At the moment, I can't access the hosted API with get or post requests.
I'm developing the angular application on my local computer using a python simple server, whereas the api is hosted online.
I would prefer to find a fix that's completely in angular since I can't change the API without help (it was written by my boss a while ago, and is now used in the production version). I don't have a login page so I'm just trying to provide the authentication information in my headers and requests.
My angular application was written independent of django. I just want to access the django backend
So far I'm trying the following to set the headers:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.headers.common = {'username': btoa('myUsername'), 'password': btoa('myPassword')
};
}]);
And in my service:
app.factory('Test', ['$resource', function($resource) {
return $resource('https://www.phonywebsite.org/en/api/test/')
};
I consistently get 301, 400 and 403 errors. Lately it's been mostly 301 errors and I get no response from the api. I'm using the Allow CORS chrome extension as a temporary fix to try to get to the api without getting a CORS policy error.
My questions
How can I fix the CORS errors without using the chrome extension?
How do I provide my authentication to my django backend that uses session based authentication making sure the csrf cookie its looking for is in the header?
To answer your first question, using the cors extension is a temporary solution and should mostly never be used cause your clients might not use it. To handle CORS, you need to understand how cross site API calls work. In short CORS is a mechanism that allows AJAX requests to circumvent their same origin limits. To handle such situations you need to update your backend and add
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
. Once you add this your settings.py should stop getting CORS issues.
To answer your second question, angular already provides you with support for CSRF so half of your battle is already won. What you need to do is add a patch on your module to start accepting csrf tokens (The name is a bit different in angular). You have already done this and done a good job of it as well:
var app = angular.module('app', ['...']);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
What this would do is make sure that whenever you make a $http call your csrf token is set as well.
As a learning oppurtunity, you could also try using ng-cookies as well. To go further to explain this, whenever you make a call in angular , your request in bundled with cookies as well so you can easily access them in request.COOKIES.
You need to change how you are calling your API as well, something like:
app.factory('APIService', function ($http) {
return $http({url: 'https://www.phonywebsite.org/en/api/test/',
method: 'GET'})
}
You can obviously make modifications to this but I think this shows the $http usage to make you understand the general gist.
You can try to add some more authentication around your application here as well (or replace django auth with your own custom auth), but that is on your use case.
Hope this helps.

How to make https request in service

I am invoking a service with $http protocol, but the url that I need to invoke is of https protocol.
As a result I am getting error with code : 403.
Snippet:
return $http({
method: 'POST',
url: 'https://test.com', /* sample url */
headers: some_header,
data: some_data
});
I have tried the same using HTML - form, and it worked there, so I don't think, it's an issue with the url.
I guess, this error is mainly because of $http.
How can one make https call in AngularJS using service or factory?
The 403 Forbidden error is an HTTP status code which means that
accessing the page or resource you were trying to reach is absolutely
forbidden for some reason. This article contains basic troubleshooting
instructions for 403 Forbidden errors.
source
Using Angular's $http service works with https. Here's a basic plunker doing exactly that. It retrieves a resource over https and updates $scope.results with the result.
$http.get('https://run.plnkr.co/plunks/77OOwJ/')
.then(function(data){
$scope.results = data;
})

angular ngresource can't send headers

I'm new to the angularjs/ionic mobile app development. I'm using Parse REST api to store data and already hosted Parse server in Heroku. Tested with postman chrome extension and everything working fine. The problem that i'm facing right now is my angular-resource seem look like not sending any headers used to authenticate with parse to the server.
angular.module('starter.services', ['ngResource']).factory('Session', function ($resource) {
return $resource('/restapiurl', {}, {
get: {
method:'GET',
headers:{'X-Parse-Application-Id':'XXX', 'X-Parse-REST-API-Key':'XXX'}
}
});
});
Need an advice/guide to make my code work perfectly. Any help would be appreciate. Thanks in advance
UPDATE: I'm managed to send custom headers to the server. The workaround is to use $httpProvider.defaults.headers.common with the key and value inside module.config

Call external API by Angular JS

I'm calling my API on PHP server by Angular JS:
$http({method: 'POST', url: 'my api...',
And my call is always canceled and generated the error:
XMLHttpRequest cannot load http://kni.prz.edu.pl/querye/api/querye. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
How to enable Cross Requests in Angular JS?
The canceled is not from server.
It's likely that the issue is in fact on the server side. You need to add a response header to allow cross domain requests:
Access-Control-Allow-Origin: *
Be aware that adding this will allow any domain to send requests to your host.
If you don't have control of the server, you'll need to try JSONP, see: $http.jsonp
To enable cross site requests
angularjs $http docs
Most probably you won't get this error when running a deployed instance as you won't be on the localhost.
For testing purposes, you can do:
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);

AngularJS: $http.post throws error

I am using Request Bin to post some data. In my controller, I have the following code:
$http.post('http://requestb.in/redacted', fooBar).
success(function(data) {
$scope.fooBarPostedSuccess = true;
}).
error(function(err) {
console.log("Error while posting to Request Bin");
console.log("Error Info : " + err);
});
This is triggered by means on a button on the UI. Now when this gets triggered, the data is not posted to Request Bin and I get this error:
XMLHttpRequest cannot load http://requestb.in/redacted.
Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin.
How do I post data to request bin through an AngularJS controller? Also, what does the above error mean?
EDIT : I wish to add here that I am using Node.js with AngularJS. Is this something to do with Node perhaps?
Ah yes... you are dealing with cross-domain scripting issues. This is not an AngularJS problem, but a browser security limitation and a VERY common friction point.
You cannot POST/PUT/DELETE to another domain (different from the one which is hosting -- localhost in your case) without doing some Cross-Origin Resource Sharing (CORS). You are limited to GET for a cross-domain HTTP request.
You have two options:
See if your API supports any cross-domain capabilities. This might be via CORS or it might be via an overloaded GET API or JSONP.
Proxy requests through your server. Since you are using Node.js, proxying REST through your server is extremely simple... you just need to set up a route handler (like /api/redacted) in your Node.js server and then make a new request to your actual API server with something like Restler (NPM package) and return the result back to your client.
Hope this helps!
EDIT:
Your API supports JSONP (Your API Docs). You should be able to use Angular's JSONP function to access your API's JSONP capabilities. (Angular.js JSONP docs).
Since you want to be able to POST to the service, you will need to use the second approach.
CORS allows both GET and POST
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
http://www.w3.org/TR/cors/
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
Now, that that's out of the way...
I too have found that angular's $http won't let me POST cross domain. I was suspicious about that though because I have jquery ajax calls in other projects that can post cross domain just fine. So, I swapped my $http POST with $.ajax POST and that worked.
// $http({
// url: url,
// method: "POST",
// data: data
// })
// .success(successCallback)
// .error(errorCallback)
// ole reliable
$.ajax({
type : "POST",
url : url,
data : data,
success : successCallback,
error : errorCallback,
cache : false,
dataType : 'json',
})
You can use PutsReq instead of RequestBin. PutsReq supports CORS.

Resources