Skip to content

HttpClient and Observables

HttpClient is Angular’s built-in service for making HTTP requests. It returns Observables — lazy streams that produce a value when subscribed to. Every API call in CinemaVault goes through HttpClient.

In app.config.ts, add provideHttpClient() to the providers array:

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient()
]
};

Services that inject HttpClient will now have access to it.

import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class MovieService {
private http = inject(HttpClient);
}

http.get<T>(url) returns an Observable<T>. The type parameter T tells TypeScript the shape of the response:

interface MoviesResponse {
results: Movie[];
total_pages: number;
total_results: number;
}
getPopular(): Observable<MoviesResponse> {
return this.http.get<MoviesResponse>(
'https://api.themoviedb.org/3/movie/popular',
{ params: { api_key: this.apiKey } }
);
}

The Observable does nothing until something subscribes to it.

Subscribe in ngOnInit to trigger the request:

ngOnInit(): void {
this.movieService.getPopular().subscribe({
next: (response) => {
this.movies = response.results;
this.loading = false;
},
error: (err) => {
console.error(err);
this.loading = false;
}
});
}

The subscribe method accepts an observer object with next, error, and optional complete callbacks. next fires when data arrives; error fires on failure.

Often you want to extract just the results array from the response. Use map from RxJS:

import { Observable, map } from 'rxjs';
getPopular(): Observable<Movie[]> {
return this.http.get<MoviesResponse>(
'https://api.themoviedb.org/3/movie/popular',
{ params: { api_key: this.apiKey } }
).pipe(
map(response => response.results)
);
}

Now components receive Movie[] directly instead of the raw API response object.

Pass query parameters via the params option:

discover(genreId: string, year: string, sortBy: string): Observable<Movie[]> {
return this.http.get<MoviesResponse>(
'https://api.themoviedb.org/3/discover/movie',
{
params: {
api_key: this.apiKey,
with_genres: genreId,
primary_release_year: year,
sort_by: sortBy
}
}
).pipe(map(res => res.results));
}

Angular’s HttpClient automatically URL-encodes the params object.

An Observable from http.get() does not fire a network request until you call .subscribe(). This means:

  • You can create an Observable, store it, and subscribe later
  • If you never subscribe, no request is made
  • Each subscription creates a new request (unlike Promises, which are eager)

In CinemaVault, services return Observables. Components subscribe in ngOnInit. The async pipe in templates subscribes automatically.

  1. Set up a practice project with provideHttpClient() in app.config.ts.
  2. Create a JsonService that injects HttpClient and has a getTodos(): Observable<any[]> method that fetches https://jsonplaceholder.typicode.com/todos?_limit=5.
  3. Inject JsonService into a component and subscribe in ngOnInit.
  4. Display the results in the template with @for.
  5. Add a loading = true flag and set it to false in the next callback.
  • Register HttpClient with provideHttpClient() in app.config.ts.
  • Inject HttpClient in services with private http = inject(HttpClient).
  • http.get<T>(url, options) returns an Observable<T> — lazy, typed.
  • Subscribe in ngOnInit with { next: fn, error: fn } to trigger the request.
  • Use .pipe(map(res => res.results)) to transform the response before subscribing.
  • Pass query params as { params: { key: value } } — Angular URL-encodes them automatically.