Generic Approach to Consume REST API in Angular
Tags: angular, webdev, typescript
Published: 2021-03-16 18:51:32

In this article, I will show you how to create a generic solution to Consume REST API in Angular. I will utilize Typescript Generics in combination with Angular HTTPClient service to eliminate any code redundant, be as [DRY](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle) as possible, and follow the [Open–closed principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle).

<hr/>


##Communicating with backend services using HTTPClient


Most applications need to communicate with a remote server over the HTTP protocol, in order to perform the basic <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> operations. With Angular, you can use <code>HTTPClient</code> service to achieve this communication easily. As an example, if you need to manage the Posts of your blog, you may have the following service to handle all the operations on the Post resource:

{% gist https://gist.github.com/NicholaAlkhouri/f1c84bb54f559ad524d94e15c367b1fe.js %}

This solution is simple and clean, and it even follows the best practices according to the official [Angular Documentation](https://angular.io/guide/http). However, applications usually have many resources to manage, for our example, we may have users, comments, reviews, etc. Ideally, each of these resources should have a separate service to handle CRUD operations and communicate with the server, at the end we will have UserService, CommentService, ReviewService. Let's take a look at how the CommentService would look like:

{% gist https://gist.github.com/NicholaAlkhouri/ca51b5cd6fbece67837598dd8c3bc03e.js %}

<hr/>


## The Problem

Although the above implementation is very common and widely acceptable, it suffers from two cons:

* Code redundant (breaking of the DRY principle): If you compare the <code>PostService</code> and the <code>CommentService</code> you will notice how redundant the code is.
* Changes in the server-side, or changes in the way to communicate to the server, require changes in many files (in our case we need to change both <code>PostService</code> and <code>CommentService</code> files)

<hr/>

## Typescript Generics To The Rescue

To solve the above issues let's go ahead and build the following abstract class which will be the base of all the other services:
{% gist https://gist.github.com/NicholaAlkhouri/9042bce5df619727bbc4288c38c7acd8.js %}

<!-- wp:list -->
* The new service class is <code>abstract</code>, which means it can't be instantiated and used directly, but it needs to be extended by other classes.
* We provide one abstract method <code>getResourceUrl</code>, The class which extends this abstract class must implement this method, and return the URL of the resource as we will see in the following section.
* This is a Generic Class, it is not tied to a specific type, rather the class which extends this abstract class will define the exact type used.
* It has all the needed CRUD operations which we need and used before in the previous service.

Now after we have our abstract generic class, whenever we need a new service we can simply extend this class and implement the only one abstract method <code>getResourceUrl</code>. so the PostService and CommentService will be as the following:

{% gist https://gist.github.com/NicholaAlkhouri/35c5d5f44fa72e6ce0387b6e590155d1.js %}

<hr/>

## Server vs Front-end Model

In most applications, the front-end model doesn't match %100 the server-side model. In other words, the REST API will respond with json object that doesn't match exactly the interface or the class defined in the front-end application. In this case, you need a mapping function to convert between server and front-side mode. This sometimes referred to as serializing/deserializing. 

So, let us extend our base class to provide this mapping functionality. To do so I updated the <code>ResourceService</code> to look as the following:

{% gist https://gist.github.com/NicholaAlkhouri/e014d2efab0a6b3062157ebc9d47c48d.js %}


<ul><li>I added two new methods:<ul><li><code>toServerModel</code>: to convert from the Front-end model to the Server Model, It accepts the resource generic type <code>T</code> and return <code>any</code> (json)</li><li><code>fromServerModel</code>: to convert from the Server model to the Front-end Model, it accepts a parameter of the type <code>any</code> which represent the server response, and return the generic type <code>T</code></li></ul></li><li>I provided a default implementation for both of the two methods <code>toServerModel</code>, <code>fromServerModel</code>, so in case no mapping needed, the same object returned by the server will be used as a front-end model. Also since I added a  default implementation, the consumer of this service doesn't have to override or even implement these two methods at all.</li><li>In both <code>getList</code> and <code>get</code> methods, I am using the new method <code>fromServerModel</code>, to map the server response to the front-end Model.</li><li>In both <code>add</code> and <code>update</code> methods, I am using <code>toServerModel</code> to map the front-model to the server model before posting the data to the server.</li></ul>

<p>Now to consume the new changes we have two cases:</p>


<ol><li>There is no mapping needed between the server and the front-end model, in this case, we don't have to change anything in the class that extends the <code>resourceService</code>.</li><li>There is some kind of mapping needed between the server and the front-end model, all we need to do is to override <code>toServerModel</code> and <code>fromServerModel</code> models in the derived class to address our requirement mappings. For example let's assume, that the <code>PostsService</code> implemented previously needs to map from timestamp to a js Date object, the PostsService implementation would look like the following:</li></ol>

{% gist https://gist.github.com/NicholaAlkhouri/45f0939966b8f0058706120d0ee73fd2.js %}

<hr/>

## Conclusion:


To communicate with a server using the HTTP protocol, you need to use the Angular HTTPClient service. In this article, we implemented a generic extendable solution to allow us to achieve this communication. Our solution is clean, <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>, and follows the <a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle">Open–closed principle</a>. We utilized Typescrip Generics, Generic Classes, and we even took into consideration a required mapping between server and front-end model.