Making API Calls in AngularJS using Angular’s $http service

Share this article

Note: This article was updated on 2016.01.17 by Siyuan Hua.

  • Replaced unnecessary setTimeout and clearTimeout calls with ng-model-option debounce feature and $watch service.
  • .success()/.error() have been deprecated, updated to use .then(success_callback, error_callback) instead.
  • Fix the broken poster image.

Nowadays, it is commonplace for web apps to communicate with each other via APIs. For example, when you buy movie tickets online, the movie ticket web site uses a remote API to verify your credit card information is correct. In this tutorial I will examine how AngularJS can be used to make HTTP requests to a remote API and how to handle the API’s JSON response so that the view is updated.

Staying with the movie theme, I will demonstrate this by building a movie browser called Fastr, which will fetch a variety of different information about any movie you care to enter. In addition to AngularJS, Fastr will be built using Bootstrap for styling and Animate.css for some snazzy effects.

This is what we’ll end up with:

A screen shot of the FASTR app

The code for this project is available from our GitHub repo, or you can view a working demo on CodePen.

The Project Structure

We will be keeping the code in a modular structure as follows:

css/
  animate.min.css
  bootstrap.min.css
  style.css

js/
  angular.min.js
  app.js

partials/
  main-info.html
  related-results.html

index.html

The file index.html will contain the main view for our app. The majority of it is boilerplate, but let’s examine where the action takes place:

<div class="input-group search-bar">
  <input type="text" 
         ng-model="search" 
         ng-model-options="{ debounce: 800 }"
         placeholder="Enter full movie name" />
  ...
</div>

<div id="main-info" 
     ng-include="'partials/main-info.html'">
</div>

<div id="related-results" 
     ng-include="'partials/related-results.html'">
</div>

As you can see, we have used ng-model to bind the input field (where the users will enter the movie name) to the search model (which we will declare in our controller). We have also used the ng-model-options directive with a debounce value of 800 to ensure that the model is updated with a delay of at least 800ms. We are also monitoring search model for changes using the $watch service and we register a callback to fetch data every time a change is detected. You will see this in the below section.

The main-info and related-results divs will be used to display information about the current movie and a list of related movies respectively. The information will be displayed in partials which are fetched, compiled and included by the ng-include directive.

Calling the API for Data

Let’s look at app.js which is the heart of the application. We start by passing $scope and $http as parameters to our controller’s constructor function. This means we are declaring dependencies on both the scope object and the http service.

.controller('MovieController', function($scope, $http){

Now, when the page loads for the first time, the search model is undefined. So, we set it to “Sherlock Holmes” and call the fetch function, which will contact the remote API and ensure that the view is initialized.

Now in the MovieController, we set up monitoring of the search model and load the results when the string in the search box changes. What we want, is that the results should only be fetched after the user has stopped typing for 800 milliseconds (remember we used the ngModelOptions directive with a debounce value of 800). This prevents the application from making unnecessary calls to the API. We also wish to see the results instantly as we are typing (we don’t want to press enter or click on any search button).

$scope.$watch('search', function() {
  fetch();
});

Now we define the change function. It loads results when the string in the search box changes. What we want, is that the results should be fetched only after the user has stopped typing for 800 milliseconds. This prevents the application from sending unnecessary calls to the API. We also wish to see the results instantly as we are typing (we don’t want to press enter or click on any search button).

Then we initialize the search model to “Sherlock Holmes” in the controller, which in turn invokes the fetch() callback registered with the $watch service, which contacts the remote API and ensures that the view is initialized.
$scope.search = "Sherlock Holmes";

Next comes the fetch function. This function makes calls to the API and processes the JSON data that is sent in response. The API we will be using for our movie browser is the OMDb API—a free web service to obtain movie information. If you are curious as to how the API works, I encourage you to check out the comprehensive documentation at the link above.

To make the requests we use Angular’s $http.get function, passing it the API URL and a concatenated query string as parameter. Two requests to different URLs are made—the first to retrieve the main information about the movie, the second to retrieve related results.

On success we store the responses in a model called details and a model called related respectively.

function fetch(){
  $http.get("http://www.omdbapi.com/?t=" + $scope.search + "&tomatoes=true&plot=full")
  .then(function(response){ $scope.details = response.data; });

  $http.get("http://www.omdbapi.com/?s=" + $scope.search)
  .then(function(response){ $scope.related = response.data; });
}

Next comes the update function. This will be called when a user clicks on one of the related titles in the view. It accepts an object (containing information about the related movie) and sets our Search model to the value of that movie’s title. The $watch service still performs the magic to pull in the information about that movie when search model changes.

$scope.update = function(movie){
  $scope.search = movie.Title;
};

Finally we have a convenience function select which ensures that the entire text is selected when the user clicks in the text input.

$scope.select = function(){
  this.setSelectionRange(0, this.value.length);
}

Handling the Response

Let us now analyse the partials/main-info.html file.

We start off using the ng-if directive to show the message “Loading Results…” if the list has not yet been loaded, followed by checking details.Response==='True' to see if the API has found a match when the request returns.

In the case that results were returned, we use the ng-src directive to examine the contents of details.Poster and either load the image it contains a reference to, or load a placeholder image if no image was available.

<img ng-src="{{ details.Poster=='N/A' ?  
                'http://placehold.it/150x220&text=N/A' : 
                details.Poster }}">

After that we use Angular’s data bindings to display the remaining movie details, before including four further links at the bottom of the page to external sites where the user can obtain more information about the movie. We render these links using the ng-href directive, as we are using Angular expressions in the href attribute and if the user clicks a link before Angular has a chance to replace the expression with its value, then things will break.

Finally, let us examine partials/related-results.html

<div ng-if="related.Response!=='False'">
  Related Results:<hr>

  <ul class="rel-results">
    <li ng-repeat="movie in related.Search">
      <a href="#" id="{{ $index + 1 }}" 
         ng-click="update(movie)">{{ movie.Title }}
      </a>, {{ movie.Year }}
    </li>
  </ul>
</div>

Again, we use ng-if to check the response before rendering anything. We then use the ng-repeat directive to iterate through the related model’s Search property, which contains (amongst other things) a list of movie titles related to the movie we were searching for.

We also use the ng-click to call our controller’s update function whenever a title is clicked. As explained above, the update function will ensure that information for this new movie is fetched and displayed.

Some Final Touches

We can add some noscript tags to index.html, so that it displays an error message if JavaScript is either disabled or not supported in the user’s browser. We can also include animate.css to add in some cool animations such as flipping the poster image, zooming in the content and bouncing of the related results. Using animate.css is as simple as specifying the name of the animation in the class of the element preceded by the string animation. E.g.:

<div class="animated zoomInRight">

And here’s the result!

Please note that I’ve hidden the related results in the embedded demo due to space constraints. To see them, simply view the demo on CodePen (which is a good idea anyway, as the demo is faster there).

See the Pen YXXQxj by SitePoint (@SitePoint) on CodePen.

Conclusion

In this tutorial I have demonstrated how to use AngularJS to make a request to a remote API and how to use Angular’s data binding mechanisms to immediately update the view with the results. Building a project like this can be a great way of learning a particular language or framework feature, so I encourage you to clone the repo and further improve the app.

Frequently Asked Questions (FAQs) about API Calls with AngularJS HTTP Service

What is the role of AngularJS HTTP service in API calls?

AngularJS HTTP service is a core AngularJS service that facilitates communication with the remote HTTP servers via the browser’s XMLHttpRequest object or via JSONP. It provides a simple and concise method to make API calls. It allows you to send HTTP GET, POST, PUT, DELETE, and other types of requests. It also provides the ability to handle responses from the server, including error handling.

How can I handle errors in AngularJS HTTP service?

Error handling is an essential part of making API calls. In AngularJS HTTP service, you can handle errors using the .error() method. This method is executed when the request fails. It takes a function as a parameter, which will be called when the request fails. The function will receive the error response object, which contains information about the error.

Can I cancel a request in AngularJS HTTP service?

Yes, you can cancel a request in AngularJS HTTP service. You can do this by using the timeout property of the config object. You can create a timeout promise and pass it to the config object. If you resolve this promise before the HTTP request completes, the request will be aborted.

How can I send data in a POST request using AngularJS HTTP service?

To send data in a POST request using AngularJS HTTP service, you can use the data property of the config object. The data property contains the request body. This should be an object, a string, or a Blob object.

How can I set headers in AngularJS HTTP service?

You can set headers in AngularJS HTTP service using the headers property of the config object. The headers property is an object where each property is a header name and the corresponding value is the header value.

Can I use AngularJS HTTP service with JSONP?

Yes, you can use AngularJS HTTP service with JSONP. AngularJS provides the $http.jsonp() method for making JSONP requests. This method works similarly to the $http.get() method, but it sends a JSONP request instead of a GET request.

How can I transform the request or response in AngularJS HTTP service?

You can transform the request or response in AngularJS HTTP service using the transformRequest and transformResponse properties of the config object. These properties are functions or arrays of functions that transform the request or response.

How can I cache responses in AngularJS HTTP service?

You can cache responses in AngularJS HTTP service using the cache property of the config object. If you set this property to true, the response will be cached. If the same request is made again, the response will be returned from the cache instead of making a new request.

Can I make a synchronous request in AngularJS HTTP service?

No, you cannot make a synchronous request in AngularJS HTTP service. All requests made with the $http service are asynchronous. This means that the function will return immediately and the response will be handled in a callback function.

How can I handle global HTTP errors in AngularJS?

You can handle global HTTP errors in AngularJS using the $httpProvider.interceptors property. You can add an interceptor to this array that will be called for every HTTP request. The interceptor can handle errors, transform requests or responses, or even cancel requests.

Tanay PantTanay Pant
View Author

Tanay Pant is an Indian author, hacker, developer and tech enthusiast. He is known for his work on Learning Firefox OS Application Development, which was published by Packt. He is also an official representative of Mozilla, and has been listed in the about:credits of the Firefox web browser. His personal website is tanaypant.com.

angular servicesAngular TutorialsAPIsgitCSjameshjson
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week