Add TmdbClient

This commit is contained in:
2026-08-12 21:05:22 +02:00
parent 9683d65a1f
commit 4e483557d7
4 changed files with 169 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
import { ApiClient } from '../../../core/http/ApiClient';
import type { TMDbMovie } from '../../models';
import { SearchMovieEndpoint } from './endpoints/SearchMovieEndpoint';
import { RecommendedMoviesEndpoint, SimilarMoviesEndpoint } from './endpoints/MovieListEndpoint';
const TMDB_BASE_URL = 'https://api.themoviedb.org';
export class TmdbClient extends ApiClient {
private readonly searchEndpoint = new SearchMovieEndpoint();
private readonly similarEndpoint = new SimilarMoviesEndpoint();
private readonly recommendedEndpoint = new RecommendedMoviesEndpoint();
constructor(
private readonly apiKey: string,
baseUrl: string = TMDB_BASE_URL
) {
super(baseUrl);
}
async searchMovie(title: string, year?: number): Promise<TMDbMovie | undefined> {
const results = await this.request(this.searchEndpoint, { apiKey: this.apiKey, title, year });
return results[0];
}
getSimilar(tmdbId: number): Promise<TMDbMovie[]> {
return this.request(this.similarEndpoint, { apiKey: this.apiKey, tmdbId });
}
getRecommendations(tmdbId: number): Promise<TMDbMovie[]> {
return this.request(this.recommendedEndpoint, { apiKey: this.apiKey, tmdbId });
}
}

View File

@@ -0,0 +1,44 @@
import { Endpoint, type HttpMethod } from '../../../../core/http/Endpoint';
import type { TMDbMovie } from '../../../models';
import { toTMDbMovie } from './SearchMovieEndpoint';
interface TMDbResult {
id: number;
title: string;
release_date: string;
}
interface TMDbListResponse {
results: TMDbResult[];
}
export interface MovieListParams {
apiKey: string;
tmdbId: number;
}
export class SimilarMoviesEndpoint extends Endpoint<TMDbMovie[], MovieListParams> {
readonly method: HttpMethod = 'GET';
path(params: MovieListParams): string {
return `/3/movie/${params.tmdbId}/similar`;
}
query(params: MovieListParams): Record<string, string> {
return { api_key: params.apiKey };
}
parseResponse(json: unknown): TMDbMovie[] {
return (json as TMDbListResponse).results.map(toTMDbMovie);
}
}
export class RecommendedMoviesEndpoint extends Endpoint<TMDbMovie[], MovieListParams> {
readonly method: HttpMethod = 'GET';
path(params: MovieListParams): string {
return `/3/movie/${params.tmdbId}/recommendations`;
}
query(params: MovieListParams): Record<string, string> {
return { api_key: params.apiKey };
}
parseResponse(json: unknown): TMDbMovie[] {
return (json as TMDbListResponse).results.map(toTMDbMovie);
}
}

View File

@@ -0,0 +1,41 @@
import { Endpoint, type HttpMethod } from '../../../../core/http/Endpoint';
import type { TMDbMovie } from '../../../models';
interface TMDbResult {
id: number;
title: string;
release_date: string;
}
interface TMDbSearchResponse {
results: TMDbResult[];
}
export interface SearchMovieParams {
apiKey: string;
title: string;
year?: number;
}
export function toTMDbMovie(result: TMDbResult): TMDbMovie {
const year = result.release_date && result.release_date.length >= 4 ? Number(result.release_date.slice(0, 4)) : 0;
return { id: result.id, title: result.title, year };
}
export class SearchMovieEndpoint extends Endpoint<TMDbMovie[], SearchMovieParams> {
readonly method: HttpMethod = 'GET';
path(): string {
return '/3/search/movie';
}
query(params: SearchMovieParams): Record<string, string> {
const query: Record<string, string> = { api_key: params.apiKey, query: params.title };
if (params.year) query.year = String(params.year);
return query;
}
parseResponse(json: unknown): TMDbMovie[] {
return (json as TMDbSearchResponse).results.map(toTMDbMovie);
}
}