Two Ways of Using Angular Services With the HttpClient
Tags: angular, rxjs, typescript, webdev
Published: 2020-07-02 16:39:35

### Angular Level:

![level](https://raw.githubusercontent.com/Nas3nmann/articles/b09b6860c561037e223a104a6e824c371b7444ec/Angular/shared/angular-levels/ng_3_of_5.svg)

---

#The Old Fashioned Way: The 'Pull' Approach
When starting to build an Angular app you most likely come to the point where you need some kind of HTTP communication.
I guess every intermediate Angular user has used the http client before. 
Most likely it was wrapped in an Angular service. 
E.g. a service for a shopping list app could look like this:

```typescript
@Injectable({
  providedIn: 'root'
})
export class ShoppingListPullService {

  ITEMS_URL = 'assets/items.json';

  constructor(private httpClient: HttpClient) {
  }

  getItems(): Observable<ShoppingItem[]> {
    return this.httpClient.get<ShoppingItem[]>(this.ITEMS_URL);
  }
}
```

A component then gets the shopping items via a simple method call, stores them and can display them like this:
```typescript
@Component({
  selector: 'app-pull',
  template: `
      <div *ngFor="let user of items">
          - {{user.quantity}} {{user.name}}
      </div>
  `
})
export class PullComponent implements OnInit {

  items: ShoppingItem[];

  constructor(private readonly shoppingListService: ShoppingListPullService) {
  }

  ngOnInit(): void {
    this.shoppingListService.getItems()
      .subscribe(items => this.items = items);
  }
}
```
Note that we don't need to ``unsubscribe`` here, as the angular ``HttpClient`` handles this for us.
If we had another kind of Observable here, we would also need to ``unsubscribe``.

Let's call this approach the "Pull Approach", because it pulls the data from the service and the component is responsible for holding the state (in this case the array of shopping items).
After any possible change of the items a refetch must be done including the corresponding subscribe block.

This approach is nice and simple, but may not be suitable if multiple components use the service and all of them should share one consistent state.
E.g. imagine you have a component for listing the items and one component for adding new items.
Both components need control of the list.

# Observable Data Service: The 'Push' Approach
 Here an "Observable Data Service" or "Service With a Subject" is much more convenient.
 It may look like this:
 
 ```typescript
@Injectable({
  providedIn: 'root'
})
export class ShoppingListPushService {

  ITEMS_URL = '/assets/items.json';

  private readonly items$: BehaviorSubject<ShoppingItem[]> = new BehaviorSubject<ShoppingItem[]>([]);

  constructor(private httpClient: HttpClient) {
  }

  fetchList() {
    this.httpClient.get<ShoppingItem[]>(this.ITEMS_URL)
      .subscribe(receivedItems => this.items$.next(receivedItems));
  }

  get items(): Observable<ShoppingItem[]> {
    return this.items$.asObservable();
  }
}
```
Let's have a look on how this works:

The ``fetchList`` method executes an HTTP request.
After it returned the items successfully they are _published_ to the [BehaviourSubject](https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject) ``items$``, which means that anyone subscribed to this subject will get that new array of items.
This Subject is made public in the form of an [Observable](https://rxjs-dev.firebaseapp.com/guide/observable) by the ``get`` method below so nothing can be published from outside of the service.

This kind of service can easily be used with the Angular ``async`` pipe. 
No need to ``subscribe`` to or ``unsubscribe`` from anything.

```typescript
@Component({
  selector: 'app-push',
  template: `
      <div *ngFor="let item of shoppingListService.items | async">
          - {{item.quantity}} {{item.name}}
      </div>
  `
})
export class PushComponent implements OnInit {

  constructor(readonly shoppingListService: ShoppingListPushService) {
  }

  ngOnInit(): void {
    this.shoppingListService.fetchList();
  }
}
```

Only thing left to do programmatically in the list component is to trigger the data fetch.
 
So let's again imagine a second component using this service to add items to the shopping list. 
After adding an item the component may easily trigger the ``fetchList()`` method and cause an update of the item list in the other component.

Pretty easy, huh?