Before getting into how to access external APIs with angular.js, let's cover some background material.
Same Origin Policy
A policy implemented by browsers that prevents access to scripts outside the current domain. XHR is subject to this policy, <script> tags are not. This policy means that scripts on mysite.com can not make XHR requests for data from yoursite.com-- there are workarounds to this (JSONP, CORS, cross domain messaging, modifying document.domain property)
CORS (Cross Origin Resource Sharing)
CORS supports all HTTP methods unlike JSONP which only supports GET.
A mechanism utilized in CORS whereby an initial "pre-flight" request is made to the server to determine if the appropriate permissions are available before making the real request. A preflight request is an 'OPTIONS' HTTP request that the server can respond to by specifying the allowed methods and origin. If the server responds appropriately, the browser sends the real request
The plunker code snippets below attempt to retrieve some data from various external APIs and display the data through the $scope's data property. Hit the play icon in the top right of each plunker to see the result.
$http.get on an API that does not support CORS
This first plunker below shows a naive get of the OpenWeatherMap API using $http.get
Clearly, this did not work. Looking at the console, you can see the following error messages.
You can run the curl cmd below to reveal the headers for this request
>> curl -X OPTIONS -i 'http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139' -H "Origin: http://example.com"
Notice that there is no "Access-Control-Allow-Origin" header.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Thu, 01 Aug 2013 19:22:36 GMT
This means that the OpenWeatherMap API does support CORS. We can try to access the API via JSONP.
$http.jsonp on an API that does not support CORS, but supports JSONP
The plunker below shows the retrieval of OpenWeatherMap data using $http.jsonp
Success! We are able to retrieve OpenWeatherMap API data using JSONP.
$http.get of an API that supports CORS
The plunker below shows the retrieval of github api data using http.get
Success! Running curl on the github API will show the CORS related headers.
>> curl -X OPTIONS -i https://api.github.com -H "Origin: http://example.com"
HTTP/1.1 204 No Content
Date: Thu, 01 Aug 2013 19:29:16 GMT
Status: 204 No Content
Access-Control-Expose-Headers: ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes
Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With
Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE
Access-Control-Allow-Origin: *Vary: Accept-Encoding
APIs that do not support preflight requests
Finally, lets look at the Spotify API which does not respond appropriately to the preflight OPTIONS request.
The plunker below shows the retrieval of spotify api data using http.get in angular 1.0
This does not work as the preflight request is rejected by the server.
curl -X OPTIONS -i 'http://ws.spotify.com/search/1/artist.json?q=bah' -H "Origin: http://example.com"
HTTP/1.1 400 Bad Request
Date: Thu, 01 Aug 2013 19:39:34 GMT
$http requests in Angular 1.0.x include the 'X-Requested-With' header which triggers the preflight request in CORS. The plunker below removes this header.
Success! We are now able to retrieve data from the Spotify API.
The 'X-Requested-With' header has been removed in Angular 1.1.x
The plunker below shows the retrieval of Spotify API data using $http.get in angular 1.1
Use curl -X OPTIONS -i $api_endpoint -H "http://example.com" to see if $api_endpoint supports preflight requests. If not and you are using angular 1.0.x, remove the 'X-Requested-With' header from the $httpProvider
Use curl -i $api_endpoint?callback=callBackFn -H "http://example.com" to see if $api_endpoint supports JSONP
Not covered here, but angular also provides $resource which can be used to interact with RESTful API services.