Angular Services to Access an API - MEAN Machine - A beginner's practical guide to the JavaScript stack (2015)

MEAN Machine - A beginner's practical guide to the JavaScript stack (2015)

Angular Services to Access an API

Separating server-side and client-side applications means that there has to be something that links the two together. When creating Angular applications, services are the glue between frontend and backend.

Services are the way we contact an API, get data back, and pass it to our Angular controllers. The controller then passes that information to our views and we have a complete separation of duties like the MVC model states we should.

We will be using Angular services and Angular’s built-in $http service to make HTTP requests to our API. You can also use this to make requests to any API.

The beauty of Angular services is that they just make API calls. This means we are able to hook up Angular to any backend API. It doesn’t matter if we have a Node API, PHP API, or any other language. Angular can talk to them all as long as we have a backend that allows calls for information and returns valid JSON data.

Types of Angular Services

There are 3 types of Angular services: service, factory, and provider. Each has its own specific use cases.

Service: The simplest type. Services are instantiated with the new keyword. You have the ability to add properties to a service and call those properties from within your controllers.

Factory: The most popular type. In a Factory, you create an object, add properties to that object, and then return it. Your properties and functions will be available in your controllers.

Provider: Providers are the most complex of the services. They are the only service that can be passed into the config() function to declare application-wide settings.

For our purposes, we will be using factories. They provide a good middle ground of functionality between services and providers.

The $http Module

The $http module gives us a way to communicate with remote HTTP servers. If you are familiar with jQuery API calls, then you will see that the syntax is very similar.

Here’s an example call to get all users from our Node API we created earlier:

1 angular.module('myApp', [])

2

3 // inject $http into our controller

4 .controller('mainController', function($http) {

5

6 var vm = this;

7

8 // make an API call

9 $http.get('/api/users')

10 .then(function(data) {

11

12 // bind the users we receive to vm.users

13 vm.users = data.users;

14

15 });

16

17 });

The $http module can be injected into an Angular module, whether it be a controller or service. In the above example, it was injected into a controller. However, we do not want to call the $http module directly in a controller. That logic should be moved into a service so that we have a clear separation of duties. Services get the data while the controller receives it and sends to our views.

Let’s look at how we can use the $http module in a factory.

A Sample Angular Service

We’re going to build out a sample factory and see how we can use it inside of an Angular controller.

Angular Factory

Here’s a quick file called userService.js that will access an API that delivers user data.

1 angular.module('stuffService', [])

2

3 .factory('Stuff', function($http) {

4

5 // create the object

6 var myFactory = {};

7

8 // a function to get all the stuff

9 myFactory.all = function() {

10 return $http.get('/api/stuff');

11 };

12

13 return myFactory;

14

15 });

We have just created our first Angular service! The syntax is fairly straightforward. We have a factory called Stuff and a function called all. This function will create an HTTP GET call using the $http module and return a promise object. We can then act on the promise object by accessingsuccess(), error(), or then(). For our purposes, success() will do just fine.


Tip

Tip

Promises

Promises are a hard concept to grasp if you are new to JavaScript development. Promises help us deal with the asynchronous nature of JavaScript by acting as sort of a placeholder. We make a request for some kind of data and the promise will wait for the response so the rest of our program can continue with whatever else its doing. Once our promise receives the result, it will notify us and we can carry out our next action based on that result whether it be a success or error.

Here are some good resources for understanding promises:

· promisejs.org - A good vanilla JS explanation

· Promises in AngularJS, Explained as a Cartoon

We will be using promises to handle grabbing data from our API. This ensures that we get the data back as we want it and it is not lost. The $http module will return a promise object that we can use.


Now that we have created our stuffService Angular module and Stuff factory, let’s look at how we can use this factory within an Angular controller.

Using a Service in a Controller

1 // inject the stuff service into our main Angular module

2 angular.module('myApp', ['stuffService'])

3

4 // create a controller and inject the Stuff factory

5 .controller('userController', function(Stuff) {

6

7 var vm = this;

8

9 // get all the stuff

10 Stuff.all()

11

12 // promise object

13 .success(function(data) {

14

15 // bind the data to a controller variable

16 // this comes from the stuffService

17 vm.stuff = data;

18 });

19

20 });

Just like that, we have created an Angular service, injected it into a controller, and grabbed all our user data. It is important to understand the separation of concerns here.

The service is responsible for grabbing data from an external resource (our API) while the controller is responsible for facilitating that data to our views.

We have a separation of concerns between our controllers and services. Services get the data and controllers facilitate that data to the view.

User Service

Let’s create a service that we will use in our final application. We’ll call this our userService. The benefit of creating a standalone service like this is that it will be reusable across other projects.

Just like we created API endpoints on the backend, we will use the $http module to create functions in our service to go and grab from each of the endpoints. We will need to handle the following:

· get a single user

· get a list of all users

· create a user

· update a user

· delete a user

All of these tasks together combine to make your normal CRUD operations. For reference, let’s see how we can match up the frontend needs with the backend API. Our matching table will also show the HTTP verb that needs to be used since we want to stick to the REST pattern we created.

Task

Node API

Angular Service Function

single user

GET /api/users/:user_id

get(id)

list users

GET /api/users

all()

create user

POST /api/users

create(userData)

update a user

PUT /api/users/:user_id

update(id, userData)

delete user

DELETE /api/users/:user_id

delete(id)

Our frontend functions can be named anything. If you wanted to, you could even get these to match the backend functions. For example, instead of create(userData), you could use postUser(userData) to keep with the HTTP verb trend.

Remember that when calling these functions within an Angular controller, you will have to prefix the function name with the factory name, so it’s nice to keep them simply named. For example, to get all of the users, we will call User.all() and to get a single user we will call User.get(id). Having a clean set of function names makes development easier across an entire team.

Whatever you choose, the most important thing is that there is a set standard on the backend and frontend and that all developers involved with the project know the exact naming schemes across the entire stack.

Let’s create an Angular module for our userService. We will define our Angular module and create a factory called User to go along with it.

1 angular.module('userService', [])

2

3 .factory('User', function($http) {

4

5 // create a new object

6 var userFactory = {};

7

8 // get a single user

9 userFactory.get = function(id) {

10 return $http.get('/api/users/' + id);

11 };

12

13 // get all users

14 userFactory.all = function() {

15 return $http.get('/api/users/');

16 };

17

18 // create a user

19 userFactory.create = function(userData) {

20 return $http.post('/api/users/', userData);

21 };

22

23 // update a user

24 userFactory.update = function(id, userData) {

25 return $http.put('/api/users/' + id, userData);

26 };

27

28 // delete a user

29 userFactory.delete = function(id) {

30 return $http.delete('/api/users/' + id);

31 };

32

33 // return our entire userFactory object

34 return userFactory;

35

36 });

Notice how we are using the $http module to create requests to our various API endpoints. We have $http.get(), $http.post(), $http.put(), and $http.delete() all accounted for here.

There is nothing too fancy happening here. Our service will return the data from our calls to the API. With our user service done, we’ll be able to integrate this into our full MEAN stack application in a couple chapters.

This drop in functionality is what is so great about Angular. We are creating a set of modules and then injecting them into one another. We will inject this into our User CRM application that we create in Chapter 17.

Note: If your API is hosted on a separate server, then you will need to prefix all these /api/ URLs with your server URL like so: $http.get('http://example.com/api/users, ...).

Next up, we’ll create another service that we will use to handle authentication. Services can be used for more than just grabbing data. They can act as data objects and handle all the functions and properties necessary for a certain operation, in this case, authentication.