A Generic HTTP Service Approach for Angular Applications

Krishna Chaitanya Acondy
Better Programming
Published in
5 min readFeb 13, 2018

--

Photo by Jantine Doornbos on Unsplash

Part of the project I’m currently working on is building an Angular 4-based web application, which pulls and visualizes data from a number of RESTful back end services.

One of the cornerstones of REST is the identification and manipulation of resources through HTTP requests.

For example, if we had a RESTful pizza service that exposed a pizzas endpoint, then doing an HTTP GET on this endpoint would return a collection of resources, each of which is the representation of a pizza.

Each pizza would be uniquely identifiable with an attribute such as an id. This id can then be used to fetch and manipulate a specific pizza resource.

Making a GET request to the pizzas/:id endpoint would return the pizza with the requested id.

Making a PUT request to the pizzas/:id endpoint with a pizza resource in the request body would update the specified resource with the supplied values.

Making a DELETE request to the endpoint would delete that resource.

Here’s the overall picture:

In an Angular application, we would use the HttpClient module to make HTTP requests, so if we implemented a matching PizzaService in an Angular app, it would look something like this:

The HttpClient's generic methods ensure that strongly typed Pizza objects are returned to components that use the service.

However, if slightly more complex transformations are required between the representations of the object on the back end, and what’s required to be displayed on the front end, we will need to build our own transformation mechanism.

Let us, for our example, make pizzas have a cookedOn property, which is returned as a string by the API. We would like to parse it into a moment object, which gives us more control on how it can be displayed in the application.

Also, while posting a pizza back to the API, the cookedOn field will be ignored and doesn’t need to be posted.

For transformations such as these, I use a mechanism that I call a Serializer, which converts the raw JSON returned by the API into a strongly typed object with the required properties.

Here is an example PizzaSerializer:

And the PizzaService, now enhanced to use the serializer.

Now, what is important to note here, is that, if we had another back end service that returned burgers instead of pizzas, the matching front end service would do much the same as the PizzaService, only now it performs the same operations on Burger objects instead of Pizza objects.

The only differences in implementation would be in the serializer, due to possible differences in the model.

In the process of building out our Angular application, we implemented a large number of services to fetch and manipulate the data from the back end.

So we ended up with a bunch of classes that essentially did the same thing — fetching specific resources from the back end, transforming them into the front end’s representations of them, and updating, creating or deleting them from the back end as required.

This eventually got to the point where there was a lot of code duplication which needed to be addressed in some way.

The solution was to take a generic approach that would work for any resource fetched from a RESTful API, as long as the resource conformed to some basic constraints.

If we assume that everything that comes back from the API is uniquely identifiable, it means that every object we receive has an id field, for example.

We can formalize this by creating a Resource model:

export class Resource {
id: number
}

Now, every model that we create for a resource fetched from the back end, such as Burger or Pizza, can inherit from Resource, thereby giving it an id property.

export class Pizza extends Resource {
//id is inherited from Resource
name: string;
cookedOn: Moment;
}

Another component we will need to genericize is the Serializer. We will do this by specifying an interface that all serializers will implement.

Now, we use this generic model and interface (and some cool TypeScript generics) to implement a generic service that works for any resource.

A PizzaService that extends this generic service now won’t need the writing of any CRUD code!

Implementing a new service for burgers is now just a matter of creating the class and getting it to inherit from the generic ResourceService as above.

There we have it, a generic implementation for fetching and transforming data from a RESTful API!

However, there is yet another scenario we haven’t accounted for.

REST allows resources to have children — i.e. sub-resources which have an association with the main resource object.

To support such sub-resources, we will need to extend our resource model as follows:

export class Resource {
id: number;
parentId?: number;
}

Adding the parentId field allows us to recognize a sub-resource.

We will, however, need to implement another generic service, a SubResourceService, which takes an additional parameter to identify the parent endpoint, and will need to be passed in the parentId to operate on the resource.

Conclusion

Now we have a full-featured, generic implementation for CRUD on any resource or sub-resource provided by a RESTful API.

This ensures that the code that does all the heavy lifting in terms of fetching, transforming and dispatching data is encapsulated in two classes, and can be unit tested in isolation.

The Serializers expose pure functions that can also be thoroughly unit tested to ensure high quality, working software.

--

--