remote_tmdb_kit 1.0.0
remote_tmdb_kit: ^1.0.0 copied to clipboard
Cliente desacoplado para la API de TMDB con manejo de errores tipado, patrón Result y cliente HTTP intercambiable.
remote_tmdb_kit #
Idioma: Español
Un paquete Dart/Flutter altamente cohesivo, desacoplado y listo para producción que encapsula la integración con la API de películas de The Movie Database (TMDB).
Está diseñado bajo principios de arquitectura limpia: aísla por completo al cliente de
los detalles HTTP (cabeceras, códigos de estado, deserialización) y expone un control de
flujo funcional basado en el patrón Result.
El cliente HTTP por defecto es
dio, pero la interfazHttpServiceestá abierta para inyectar cualquier otro cliente (por ejemplohttp).
Tabla de contenido
Empezando #
Instalación #
Agrega la dependencia en el pubspec.yaml de tu aplicación:
dependencies:
remote_tmdb_kit:
git:
url: https://github.com/vmgarciahurtado/remote_tmdb_kit.git
# O usando una ruta local:
# path: ../remote_tmdb_kit
Luego descarga las dependencias:
flutter pub get
Uso simple #
Crea el repositorio con MovieRepository.create suministrando tu apiKey de TMDB:
import 'package:remote_tmdb_kit/remote_tmdb_kit.dart';
final repository = MovieRepository.create(
apiKey: 'TU_API_KEY_DE_TMDB',
language: 'es-ES', // Idioma de los datos devueltos (por defecto)
enableLogging: false, // Logs en consola (por defecto false)
);
final result = await repository.getPopular(page: 1);
Ejemplos #
Películas populares #
void fetchPopularMovies() async {
final Result<List<Movie>> result = await repository.getPopular(page: 1);
switch (result) {
case Success(data: final movies):
for (final movie in movies) {
print('- ${movie.title} (${movie.releaseDate})');
}
case FailureResult(failure: final failure):
// El mensaje ya viene traducido y listo para pintar en pantalla.
print('Error: ${failure.userMessage}');
}
}
Películas en cartelera #
final Result<List<Movie>> result = await repository.getNowPlaying(page: 1);
Búsqueda con filtros avanzados #
Usa MovieSearchFilter para acotar la búsqueda:
void searchMovies() async {
final filter = MovieSearchFilter(
includeAdult: false,
primaryReleaseYear: 2024,
language: 'es-ES',
);
final Result<List<Movie>> result = await repository.searchMovies(
'Batman',
page: 1,
filter: filter,
);
if (result is Success<List<Movie>>) {
final movies = result.data;
// ... mostrar listado filtrado
}
}
Reparto de una película #
final Result<List<Actor>> result = await repository.getMovieCast(550); // Fight Club
if (result is Success<List<Actor>>) {
for (final actor in result.data) {
print('${actor.name} como ${actor.character}');
}
}
API del repositorio #
MovieRepository expone cuatro métodos. Todos retornan un Result:
Future<Result<List<Movie>>> getNowPlaying({int page = 1});
Future<Result<List<Movie>>> getPopular({int page = 1});
Future<Result<List<Movie>>> searchMovies(String query, {int page = 1, MovieSearchFilter? filter});
Future<Result<List<Actor>>> getMovieCast(int movieId);
El constructor de factoría MovieRepository.create acepta:
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
apiKey |
String |
— (requerido) | Clave de acceso a la API de TMDB. |
enableLogging |
bool |
false |
Activa los logs HTTP en consola. |
baseUrl |
String |
https://api.themoviedb.org/3/ |
URL base de la API. |
imageBaseUrl |
String |
https://image.tmdb.org/t/p/w500 |
URL base para imágenes de películas. |
actorImageBaseUrl |
String |
https://image.tmdb.org/t/p/w185 |
URL base para fotos de actores. |
noImageUrl |
String |
URL de fallback | Imagen usada cuando no hay póster. |
language |
String |
es-ES |
Idioma de los datos devueltos. |
Manejo de errores #
Result<T> es una clase sellada (sealed) con dos variantes: Success<T> y
FailureResult<T>. Esto obliga a manejar ambos casos en tiempo de compilación.
switch (result) {
case Success(data: final value):
// usar value
case FailureResult(failure: final error):
print(error.userMessage);
}
¿Prefieres propagar el error con try/catch? Usa la extensión getOrThrow:
try {
final movies = result.getOrThrow(); // retorna la lista o lanza el Failure
} on Failure catch (e) {
print(e.userMessage);
}
Cambiar el cliente HTTP #
Si prefieres el paquete nativo http (u otro cliente), implementa la interfaz
HttpService e inyéctala en RemoteMovieRepositoryImpl, sin tocar el código del paquete:
import 'package:http/http.dart' as http;
import 'package:remote_tmdb_kit/remote_tmdb_kit.dart';
// 1. Implementa la interfaz con la librería que desees.
class HttpPackageClient implements HttpService {
final http.Client client = http.Client();
@override
Future<T> request<T>(
String path, {
required HttpMethod method,
dynamic data,
Map<String, dynamic>? queryParameters,
Map<String, dynamic>? headers,
}) async {
// ... conversión HTTP y mapeo de errores a Failure
}
}
// 2. Inyéctalo manualmente al instanciar el repositorio.
final resolver = ImageUrlResolver(
imageBaseUrl: 'https://image.tmdb.org/t/p/w500',
actorImageBaseUrl: 'https://image.tmdb.org/t/p/w185',
noImageUrl: 'https://sd.keepcalms.com/i-w600/keep-calm-poster-not-found.jpg',
);
final repository = RemoteMovieRepositoryImpl(HttpPackageClient(), resolver);
Características #
- Aislamiento de errores: mapea automáticamente excepciones de red y códigos HTTP
crudos a fallos tipados (
ConnectionFailure,ServerFailure,NotFoundFailure,UnauthorizedFailure,UnexpectedFailure) con mensajes en español listos para mostrar. - Flujo funcional con
Result: cada petición retornaSuccess<T>oFailureResult<T>, dando seguridad de tipos al manejar estados en la UI. - Filtros de búsqueda avanzados: modelo inmutable
MovieSearchFilterpara refinar búsquedas (idioma, año, región, contenido para adultos). - Logger HTTP opcional: registro detallado de peticiones, respuestas y errores en
consola, desactivado por defecto (
enableLogging = false). - Documentación en hover: toda la API pública está documentada con Dartdoc e incluye ejemplos visibles desde el editor.
- Cliente HTTP desacoplable: viene con
diopor defecto, peroHttpServicepermite inyectar cualquier cliente. - Resolución automática de imágenes:
ImageUrlResolverconvierte rutas parciales de TMDB en URLs absolutas, con fallback para imágenes no disponibles. - Sin acoplamiento a gestores de estado: úsalo con Riverpod, BLoC, Provider o
setStatepuro. - Sin dependencias de mocking en tests: cobertura construida con fakes escritos a mano.
Estructura del paquete #
La estructura interna (lib/src/) está dividida de forma modular por responsabilidad:
| Carpeta | Responsabilidad |
|---|---|
errors/ |
Jerarquía de fallas de negocio (failures.dart). |
result/ |
Tipo Result (Success / FailureResult). |
network/ |
Abstracciones de red (HttpService, HttpMethod) + impl. con dio. |
models/ |
Entidades de dominio (Movie, Actor, MovieSearchFilter). |
dtos/ |
Modelos de deserialización JSON de TMDB (internos). |
mappers/ |
Conversores de DTO a entidad. |
services/ |
Resolución de URLs de imágenes (ImageUrlResolver). |
helpers/ |
Utilidades internas (executeRepositoryCall). |
repositories/ |
Interfaz MovieRepository e implementación concreta. |
Pruebas #
El paquete incluye una suite de pruebas unitarias construida con fakes (sin mockito
ni mocktail):
flutter test
Versionamiento (SemVer) #
Este paquete sigue Semantic Versioning:
- Parche (
x.y.Z): correcciones internas que no afectan la API pública (bugfixes, optimizaciones, documentación). - Menor (
x.Y.z): nuevas funcionalidades retrocompatibles (un nuevo parámetro opcional o un nuevo método del repositorio). - Mayor (
X.y.z): cambios que rompen compatibilidad (renombrar propiedades deMovieo cambiar firmas de retorno).
Consulta el historial completo de cambios en CHANGELOG.md.
Licencia #
Distribuido bajo la licencia MIT. Consulta LICENSE para más detalles.