The HTTP Client

Angular's HttpClient is how components and services talk to a backend API — every method returns an Observable rather than a value or a Promise directly.

Making a GET request

TS user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

interface User {
  id: number;
  name: string;
}

@Injectable({ providedIn: 'root' })
export class UserService {
  constructor(private http: HttpClient) {}

  getUser(id: number) {
    return this.http.get<User>(`/api/users/${id}`);
  }
}

this.http.get<User>(...) doesn't make the request yet — it returns an Observable<User> describing a request that will run once something subscribes to it.

Subscribing to actually fire the request

TS profile.component.ts
export class ProfileComponent {
  user: User | null = null;

  constructor(private userService: UserService) {}

  ngOnInit() {
    this.userService.getUser(42).subscribe(user => {
      this.user = user;
    });
  }
}
Behavior
The HTTP GET request only fires once .subscribe() is called.
When the response arrives, the callback runs and this.user
is set, which triggers the template to re-render with the data.

ngOnInit is a lifecycle hook that runs once, right after Angular finishes setting up the component — a natural place to kick off an initial data load.

Handling errors

TS profile.component.ts — with error handling
this.userService.getUser(42).subscribe({
  next: user => { this.user = user; },
  error: err => { console.log('Failed to load user:', err.message); }
});

The object form of .subscribe() lets you handle a failed request explicitly — without an error handler, a failed HTTP call fails silently as far as the rest of your component is concerned.

Note: because HttpClient methods return Observables rather than Promises, calling .get() and never subscribing means the request is never sent at all — this trips up people coming from fetch(), where the request fires the moment you call it. It's also why forgetting to unsubscribe from a long-lived subscription (rather than a one-shot HTTP call, which completes on its own) can leak memory in a component that gets destroyed and recreated repeatedly, like inside a router-outlet.