4

In Typescript/Angular 6 (2+), is it considered a good practice to have a base abstract http service from which derives all the application services? for example:

//import the angular Http ...etc

export abstract class MyBaseService{
  ...
  protected get<T>(url: string): Observable<T> {
      return this.http.get(...)
        .pipe(map(result => result.json() as T));
  }

  protected post<T>....
  ...
}

We basically define all the rest methods (GET, POST, PUT, .. etc)

And then we have every service extend the base one:

export class MyFirstService extends MyBaseService{
  ...
  public doWork(data: MyModel): Observable<string> {
    this.post<string>(`my url`, data);
  }
  ...
}
Uentee
  • 391
  • 2
  • 4
  • 9

3 Answers3

4

I would rather use Dependency Injection instead of inheritance. And here is why:

  1. Everytime you update your MyBaseService constructor (at some point in the future you might want to inject another service in it, like HttpLogger or AlertService to handle errors etc) you need to update all the classes that inherit from it (you need to update super() call and also inject these new dependencies into them as well, and these dependencies might be irrelevant to the child class).

  2. What if you want to extend some of your services from something else in the future, you can't, cause you've already extended it from MyBaseService.

  3. During debugging - it is easier to reason about a single class, as you can see all the methods in it, you can grasp the class easily, while if you have inheritance, you need to keep in mind the parent class behaviour/methods/props as well. So if inheritance does not provide something really beneficial, then DI seems like a better choice.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Pavel
  • 111
  • 1
4

I think inheritance would be the best approach when it's services. In Angular you are unable to inject an instance of a service via 'provider' into another service. Instead, all the services would share the same instance. This is usually fine; however, if you want your BaseService to do more, such as handle errors, check if the call was successful, then store the result so your service can grab, then inheritance is the only real option you have.

If for example you used dependency injection and had your base service store values and give them out and your services are bound to these results. Then what would happen is all services that bind to it will be updated.

So at this point if you had EventService and Messages Service both would update with the same values.

Glorfindel
  • 3,137
  • 6
  • 25
  • 33
L1ghtk3ira
  • 141
  • 4
1

This is one case where I think Service inheritance may not be such a bad thing. Inheriting boilerplate service code can be as clean or cleaner than using composition if the inheritance structure is kept simple.

To address some of the points made by other answers:

  • Anyone familiar with OOP should be capable of managing what code goes in a base class
  • Defining a Specific Service is a Base Service fits with the inheritance "is a" paradigm (as opposed to "has a")
  • Managing differences between child/parent dependencies (constructor arguments) can be handled using InjectionToken or a Service Locator design pattern

For the InjectionToken approach, see Doing Inversion of Controler (IoC) in Angular

The Service Locator can be implemented by creating an Injector Singleton and pass that as the only argument to the constructor BaseService constructor. Then pull all the dependencies you need from there and assign to protected fields. This is described in Angular: Inheritance Without Effort. Note: this is technically an anti-pattern, since you can lose track of dependencies and hit runtime errors.

DV82XL
  • 119
  • 4