Reader Stacks

Calling a REST API From Angular With HttpClient

Setting up HttpClient, subscribing to the returned Observable, and the two most common mistakes: forgetting to unsubscribe, and expecting a synchronous return value.

Calling a REST API From Angular With HttpClient

Angular's HttpClient is the standard way to call a REST API — every method returns an RxJS Observable, not a Promise or a direct value, which is the single most important thing to understand before writing your first API call.

1. Provide HttpClient

In a standalone-component Angular app (17+), add it in app.config.ts:

import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [provideHttpClient()],
};

Older, module-based apps import HttpClientModule into the relevant NgModule instead — same effect, different registration mechanism.

2. Making a request

import { HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';

export class ProductService {
  private http = inject(HttpClient);

  getProducts() {
    return this.http.get<Product[]>('/api/products');
  }
}

3. Subscribing to get the actual data

this.productService.getProducts().subscribe({
  next: (products) => this.products = products,
  error: (err) => console.error('Failed to load products', err),
});

Nothing happens until .subscribe() is called — an Observable from HttpClient is "cold," meaning the actual HTTP request doesn't fire until something subscribes to it. Calling getProducts() alone, without subscribing, never sends the request at all.

Mistake 1: treating it like a synchronous value

// Wrong — products is still undefined here, the request hasn't resolved yet
const products = this.productService.getProducts();
console.log(products.length); // error or wrong result

The response only exists inside the subscribe() callback (or via the async pipe in a template) — code written as if getProducts() returns the array directly will run before the network request has actually completed.

Mistake 2: not unsubscribing where it matters

For a single one-off HTTP call, HttpClient's Observable completes automatically after emitting once, so manual unsubscription usually isn't necessary. It matters more for long-lived subscriptions (a WebSocket stream, a repeating timer) — those genuinely need to be unsubscribed in ngOnDestroy to avoid a memory leak, which is a different situation from a simple one-time API call.

Using the async pipe instead of manual subscription

products$ = this.productService.getProducts();
<li *ngFor="let product of products$ | async">{{ product.name }}</li>

The async pipe subscribes automatically when the template renders and unsubscribes automatically when the component is destroyed — often the cleaner choice over manual subscribe() calls specifically because it removes the cleanup concern entirely.

Topics: APIs & Integrations