Generic Approach to Consume REST API in Angular

nicholaalkhouri

Nichola Alkhouri

Posted on March 16, 2021

Generic Approach to Consume REST API in Angular

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 as possible, and follow the Open–closed principle.


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 CRUD operations. With Angular, you can use HTTPClient 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:

This solution is simple and clean, and it even follows the best practices according to the official Angular Documentation. 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:


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 PostService and the CommentService 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 PostService and CommentService files)

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:

  • The new service class is abstract, which means it can't be instantiated and used directly, but it needs to be extended by other classes.
  • We provide one abstract method getResourceUrl, 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 getResourceUrl. so the PostService and CommentService will be as the following:


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 ResourceService to look as the following:

  • I added two new methods:
    • toServerModel: to convert from the Front-end model to the Server Model, It accepts the resource generic type T and return any (json)
    • fromServerModel: to convert from the Server model to the Front-end Model, it accepts a parameter of the type any which represent the server response, and return the generic type T
  • I provided a default implementation for both of the two methods toServerModel, fromServerModel, 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.
  • In both getList and get methods, I am using the new method fromServerModel, to map the server response to the front-end Model.
  • In both add and update methods, I am using toServerModel to map the front-model to the server model before posting the data to the server.

Now to consume the new changes we have two cases:

  1. 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 resourceService.
  2. There is some kind of mapping needed between the server and the front-end model, all we need to do is to override toServerModel and fromServerModel models in the derived class to address our requirement mappings. For example let's assume, that the PostsService implemented previously needs to map from timestamp to a js Date object, the PostsService implementation would look like the following:

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, DRY, and follows the Open–closed principle. We utilized Typescrip Generics, Generic Classes, and we even took into consideration a required mapping between server and front-end model.

💖 💪 🙅 🚩
nicholaalkhouri
Nichola Alkhouri

Posted on March 16, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related