UPDATE 2017/07/26 : Some breaking change were pushed since I wrote this article. I updated it, but I didn't test it, feel free to comment if you find any issue. Thanks to Facundo Donato for noticing the library update.
Today I wanted to make a REST client interface for my project. I looked first on the Internet but surprisingly I didn't find anything good enough. I'll explain what I made, but first, what is the goal of this "interface".
To sum up the goal in one sentence it would be : having a layer for http requests. With that said, the point is to have something that adds headers, manage request methods, gets the response and parses it without writing it again and again through angular services.
First, I use a library that follows CRUD rules (which is not needed for this solution) and is up to date, toyanskiy/ngx-resource
Angular version 2.4.0 and later
I assume you have an angular2 project already setup, I'll only details how to make the REST interface, and how to use it.
Let's get started
Let's create a file, I named it rest-client.ts and I put it in a folder called app/shared (it depends on your design choice, but rest-client must be global). Here is the code in rest-client.ts
This class will be our REST interface. It extends Resource which is the ngx-resource class that has access to request properties such as headers and URL.
Now let's take a look at an angular service which uses our RestClient, for this example we will make an angular service to manage books, the file name would look something like book.service.ts
ResourceMethod is an interface from ngx-resource. The method generics are respectively request body and response body. Note that the service extends RestClient, it is mandatory.
Here is an example about how to consume the service above
Here, I mostly copied the documentation from ngx-resource github page.
Notice that I didn't put the full URL in the comments, it's because right now the service BookService don't have the URL, I just put '/books'. I could have put the entire URL in the decorator ResourceParams, but it would have mean that I had to put the URL for each service I create. To avoid this, let's come back to RestClient, we will override one method from Resource
That's it. getUrl is a method from Resource and it is used by the decorator ResourceAction. The method now get the URL we put, it is '/books' and concatenates this with the full URL. Now it does that for every service that extends RestClient.
The second thing I wanted to have is a global header for every service, for JWT authentication for example. Here is how I did this
I added two things. First getHeaders, it's exactly the same behavior than getUrl we saw earlier. For every service it will get the token from localStorage and put it in the Authorization header.
To make the auth works, you should specify the param auth when a resource requires an authentication. Let's say a user have to be authenticated when he wants a list of books, the resource method should look like the following
The second new method is responseInterceptor which overrides the method from Resource (remember, RestClient extends Resource). responseInterceptor allows us to catch the request response before sending it to the service which made the request. By doing this, we can parse the body, checks values, find a header entry, and so on. In the example above, I used this method to get the header in order to automatically refresh the JWToken.
Last thing but no least, or nothing will work. Import the resource module in your app module such as
I hope this solution is simple enough and easy to use. Bear in mind this solution is only about communication between client and server. You should consider routing within the app which is independent from services.
By the way, if you come up with something better, let me know.