The infrastructure layer implements the domain contracts, handling HTTP requests to TheMovieDB API, JSON deserialization, and mapping to domain entities.
The infrastructure layer is where external concerns live: HTTP clients, JSON models, and data transformation. It implements every abstract class defined in the domain.
MoviedbDataSource implements MoviesDatasource using Dio as the HTTP client. It is configured once at construction time with the base URL, API key, and language.
class MoviedbDataSource extends MoviesDatasource { final Dio dio = Dio( BaseOptions( baseUrl: 'https://api.themoviedb.org/3', queryParameters: { 'api_key': Environment.theMovieDbKey, 'language': 'es-MX', }, ), ); @override Future<List<Movie>> getNowPlaying({int page = 1}) async { final response = await dio.get( '/movie/now_playing', queryParameters: {'page': page}, ); final movieDBResponse = MovieDbResponse.fromJson(response.data); final List<Movie> movies = movieDBResponse.results .where((moviedb) => moviedb.posterPath != 'no-poster') .map((moviedb) => MovieMapper.movieDBToEntity(moviedb)) .toList(); return movies; } // ... getPopular, getUpcoming, getTopRated follow the same pattern}
Every method follows the same three-step pattern:
Make a GET request with the page number
Deserialize the response into MovieDbResponse
Filter out movies with no poster, then map each to a domain Movie
Represents the top-level JSON envelope returned by TheMovieDB list endpoints.
class MovieDbResponse { final Dates? dates; final int page; final List<MovieMovieDB> results; final int totalPages; final int totalResults; factory MovieDbResponse.fromJson(Map<String, dynamic> json) => MovieDbResponse( dates: json["dates"] != null ? Dates.fromJson(json["dates"]) : null, page: json["page"], results: List<MovieMovieDB>.from( json["results"].map((x) => MovieMovieDB.fromJson(x)), ), totalPages: json["total_pages"], totalResults: json["total_results"], );}
MovieRepositoryImpl implements MoviesRepository by delegating every call directly to the injected datasource. It decouples the presentation layer from any specific datasource.
Because MovieRepositoryImpl accepts any MoviesDatasource, swapping MoviedbDataSource for a local cache or a mock in tests requires changing only the constructor call at the provider level.