The Movie Service and HTTP Integration
Before writing any component, create the data layer: interfaces that describe TMDb’s response shapes, and a service with methods for every API call the app needs.
The models
Section titled “The models”Create src/app/models/movie.model.ts:
export interface Movie { id: number; title: string; overview: string; poster_path: string | null; backdrop_path: string | null; release_date: string; vote_average: number; vote_count: number; genre_ids: number[];}
export interface Genre { id: number; name: string;}
export interface CastMember { id: number; name: string; character: string; profile_path: string | null;}
export interface MovieDetail extends Movie { genres: Genre[]; runtime: number | null; tagline: string; credits?: { cast: CastMember[]; };}
export interface MoviesResponse { results: Movie[]; total_pages: number; total_results: number;}Note credits?: is optional — TMDb only includes it when you pass append_to_response=credits.
The TMDb config
Section titled “The TMDb config”Create src/app/core/tmdb.config.ts:
import { environment } from '../../environments/environment';
export const TMDB_API_KEY = environment.tmdbApiKey;export const TMDB_BASE = 'https://api.themoviedb.org/3';
export function posterUrl(path: string | null, size = 'w500'): string { return path ? `https://image.tmdb.org/t/p/${size}${path}` : '/no-poster.svg';}
export function backdropUrl(path: string | null): string { return path ? `https://image.tmdb.org/t/p/w1280${path}` : '';}The MovieService
Section titled “The MovieService”Create src/app/services/movie.ts:
import { Injectable, inject } from '@angular/core';import { HttpClient } from '@angular/common/http';import { Observable, map } from 'rxjs';import { Movie, MovieDetail, MoviesResponse, Genre} from '../models/movie.model';import { TMDB_API_KEY, TMDB_BASE } from '../core/tmdb.config';
@Injectable({ providedIn: 'root' })export class MovieService { private http = inject(HttpClient); private readonly params = { api_key: TMDB_API_KEY };
getPopular(): Observable<Movie[]> { return this.http.get<MoviesResponse>( `${TMDB_BASE}/movie/popular`, { params: this.params } ).pipe(map(r => r.results)); }
getTrending(): Observable<Movie[]> { return this.http.get<MoviesResponse>( `${TMDB_BASE}/trending/movie/week`, { params: this.params } ).pipe(map(r => r.results)); }
getTopRated(): Observable<Movie[]> { return this.http.get<MoviesResponse>( `${TMDB_BASE}/movie/top_rated`, { params: this.params } ).pipe(map(r => r.results)); }
getDetail(id: number): Observable<MovieDetail> { return this.http.get<MovieDetail>( `${TMDB_BASE}/movie/${id}`, { params: { ...this.params, append_to_response: 'credits' } } ); }
search(query: string): Observable<MoviesResponse> { return this.http.get<MoviesResponse>( `${TMDB_BASE}/search/movie`, { params: { ...this.params, query } } ); }
discover(genre: string, year: string, sortBy: string): Observable<Movie[]> { const params: Record<string, string> = { ...this.params, sort_by: sortBy }; if (genre) params['with_genres'] = genre; if (year) params['primary_release_year'] = year;
return this.http.get<MoviesResponse>( `${TMDB_BASE}/discover/movie`, { params } ).pipe(map(r => r.results)); }
getGenres(): Observable<Genre[]> { return this.http.get<{ genres: Genre[] }>( `${TMDB_BASE}/genre/movie/list`, { params: this.params } ).pipe(map(r => r.genres)); }}Wire up HttpClient
Section titled “Wire up HttpClient”Update src/app/app.config.ts:
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() ]};Exercise
Section titled “Exercise”- Create
movie.model.tswith all the interfaces above. - Create
tmdb.config.tswith the API key, base URL, and helper functions. - Create
movie.ts(the service) with all seven methods. - Update
app.config.tsto includeprovideHttpClient(). - Inject
MovieServiceintoAppComponenttemporarily and callgetTrending()inngOnInit. Subscribe and log the results to confirm the API call works. - Remove the test code from
AppComponent.
- Define interfaces for
Movie,MovieDetail,Genre,CastMember, andMoviesResponseinmodels/movie.model.ts. - Put TMDb constants and URL helpers in
core/tmdb.config.ts, reading the API key from the environment file. MovieServicehas methods for all API calls:getPopular,getTrending,getTopRated,getDetail,search,discover,getGenres.- Register
HttpClientwithprovideHttpClient()inapp.config.ts.