Accessing External APIs Using AngularJS’s Services
Aside from ability to extend HTML easily AngularJS also offers a simple way to interact with external APIs. In this tutorial, I will show you how to use Services to access GitHub’s API and create a simple repository browser.
Step 1: Preparation
Let’s start with this basic HTML template:
<!DOCTYPE html> <html> <head> <title>GitHub Search</title> </head> <body> </body> </html>
Now add the AngularJS script in the of the document:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
After that you can add this CSS style inline or in separate a file:
* { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; font-family: sans-serif; } body, html { margin: 0; } p { margin: 0; } input { width: 100%; } pre { white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; } div.repo { border-bottom: 1px solid; cursor: pointer; } #search, #repo, #user { float: left; } #search { width: 20%; } #repo { width: 60%; } #user { width: 20%; }
It’s nothing fancy as you can see, only a basic layout that puts the search box on the right, repository information in the middle, and user’s repositories on the right. We also have to wrap the lines in the
tag that we will use to display the README file contents, since they are usually in GitHub Flavored Markdown and some lines would overlap with the user's repository list.
Of course, you can add more style to make it more pleasing to the eye, just keep in mind that the screenshots in this tutorial will show the basic look.
You can put the JavaScript code that we will write later either inline in the of the document, or in a separate file, but it has to be under the AngularJS script.
Step 2: The Module
Now we can create a module for our app:
var app = angular.module('githubsearch', []);
Let’s add it to the tag using the
ngApp
directive:
<body ng-app="githubsearch">
Step 3: The Controller
We will also need a controller for our app. To keep it simple, it will be only one for the entire app, so we don’t need to deal with passing information between controllers:
app.controller('SearchController', function SearchController($scope) { });
Step 4: Basic Service
Let’s define our GitHub
service:
app.factory('GitHub', function GitHub($http) { return { }; });
We are using the app.factory()
method so we can just return the object with some methods to use later. We will be using the $http
service to get data from GitHub’s API.
Step 5: Searching for Repositories
The first method in our service will search for repositories using GitHub’s API. The usage of the $http
service is pretty simple (this function goes into the object returned by our factory function):
searchRepos: function searchRepos(query, callback) { $http.get('https://api.github.com/search/repositories', { params: { q: query } }) .success(function (data) { callback(null, data); }) .error(function (e) { callback(e); }); }
The $http.get()
method is a shorthand for doing GET
requests. The first parameter is the URL that we want to access. The second one is a object with options. We only need the params
object here – it’s a hash of query parameters that will be added to the request (the q
parameter is a search string, as described here).
$http.get()
returns a promise. We can attach success()
and error()
listeners to it and call the callback function accordingly.
Step 6: The Search Box
To make use of the function that we defined in the previous step we will have to add a search box to our HTML. The code is pretty simple:
<div id="search"> <input ng-model="query" placeholder="search" ng-keyup="$event.keyCode == 13 && executeSearch()"> <div class="repo" ng-repeat="repo in repos" ng-click="openRepo(repo.full_name)"> <strong>{{ repo.full_name }}</strong> <p>{{ repo.description }}</p> </div> </div>
We use ngModel
directive to bind the value of this input field to the query
variable in the scope and ngKeyup
to call the executeSearch()
function when user presses the enter key (hence the $event.keyCode == 13
comparison). We can’t use conditional statements in AngularJS expressions, but a simple logic operation (AND) will do fine.
Under the input field, we use ngRepeat
to display the search results. We will display the repository’s full name and description (you can see all of the fields available in this example in the GitHub’s API documentation if you want to display something different).
We also use ngClick
to call the openRepo()
function with the repository’s full name so we can display information about it. We will define this function later.
Step 7: Using the Search Function
Now we can finally make use of the service we created. First, add the GitHub
parameter to the controller function (so the service can be injected by AngularJS):
app.controller('SearchController', function SearchController($scope) {
Now define the executeSearch()
function:
$scope.executeSearch = function executeSearch() { GitHub.searchRepos($scope.query, function (error, data) { if (!error) { $scope.repos = data.items; } }); }
As you can see, we call the GitHub.searchRepos()
method with the search string from $scope.query
and in the callback we put the search results (from data.items
) in the $scope.repos
variable.
That is all you need to do to display the search results. Open the HTML file in your browser and try searching:
Step 8: Getting Repository’s Data
Now that we have the search functionality we can display some information about the repository the user selected. Let’s create a function to get the repository’s data in our service:
getRepo: function getRepo(name, callback) { $http.get('https://api.github.com/repos/'+ name) .success(function (data) { callback(null, data); }) .error(function (e) { callback(e); }); }
The name passed to this function must be a full name (author’s name, slash, repository’s name – like angular/angular.js
) since we have to pass it to the GitHub API (like shown here).
Step 9: Getting Repository’s README File
The contents of the README file are not inside the data we retrieved from the previous function. Instead, there is another API call to get it, so we have to create another function:
getReadme: function getReadme(name, callback) { $http.get('https://api.github.com/repos/'+ name +'/readme') .success(function (data) { callback(null, atob(data.content)); }) .error(function (e) { callback(e); }); }
This one is pretty much the same as the two previous ones, only the url changes. We are also using the atob()
function to decode contents of the README file, since it’s base64 encoded. Getting contents of the README file is described here in the GitHub’s API documentation.
The reason that we did not chain the two requests in one function is that some repositories don’t have any README file. If we were to continue like that, the application would fail.
Step 10: Displaying the Repository Information
We will display repository’s full name, number of people watching it and the README file in another
element:
<div id="repo" ng-show="activeRepo"> <strong>{{ activeRepo.full_name }}</strong> <em>Watched by {{ activeRepo.watchers_count }} people.</em> <pre>{{ activeRepo.readme }}</pre> </div>
We will store that information in the activeRepo
variable in the scope of the controller. There is also the ngShow
which will show the element only if there is any data to be displayed (otherwise you would see a “Watched by people” text there with no repository selected).
Step 11: Updating the Controller
We also have to update our controller so it gets the repository data and puts it in the scope. Create the openRepo()
function that we attached to the ngClick
directive earlier:
$scope.openRepo = function openRepo(name) { GitHub.getRepo(name, function (error, data) { if (!error) { $scope.activeRepo = data; GitHub.getReadme(name, function (error, data) { if (!error) { $scope.activeRepo.readme = data; } else { $scope.activeRepo.readme = 'No README found!'; } }); } }); }
As you can see we first use the GitHub.getRepo()
method, check for errors and then place the data in the activeRepo
variable. After that we get the README file and in case it does not exist we inform the user about that fact.
Now you can run your app again and see how it
Step 12: Getting User’s Repositories
To add some functionality to our app we will display all repositories of the selected repository’s owner on the right side of the screen. This will require another method in our service:
getUserRepos: function getUser(name, callback) { $http.get('https://api.github.com/users/'+ name +'/repos') .success(function (data) { callback(null, data); }) .error(function (e) { callback(e); }); }
Which looks pretty much the same like the other ones (and you can read more about this API request here).
Step 13: Displaying Them
This is basically a copy of the HTML for the search box, but we display user’s name instead of the input field and the repository list is in the user
object instead of the scope itself:
<div id="user"> <strong>{{ user.login }}</strong> <div class="repo" ng-repeat="repo in user.repos" ng-click="openRepo(repo.full_name)"> <strong>{{ repo.name }}</strong> <p>{{ repo.description }}</p> </div> </div>
At this point, you should have a working AngularJS application that retrieves GitHub repositories based on a search string. You can continue to iterate on this by adding more features, or giving it a different presentation through styles.
Whatever the case, all questions, comments, and feedback is welcome!
Source: Nettuts+
Leave a Reply
Want to join the discussion?Feel free to contribute!