Implementación de la Capa de Datos con Clean Architecture
Clase 4 de 19 • Curso de Android: Modo Offline con Room y Realm
Resumen
La Clean Architecture es un enfoque de diseño que permite estructurar proyectos de manera organizada y mantenible. Al dividir tu aplicación en capas bien definidas, logras una separación de responsabilidades que facilita el desarrollo, las pruebas y el mantenimiento a largo plazo. En este artículo, exploraremos cómo implementar la capa de datos dentro de una arquitectura limpia, enfocándonos en la configuración de servicios API con Retrofit y la inyección de dependencias con Hilt.
¿Qué es Clean Architecture y cómo se estructura?
Clean Architecture es un patrón de diseño que divide una aplicación en capas con responsabilidades específicas. Esta estructura facilita el mantenimiento del código y permite realizar cambios sin afectar otras partes del sistema. La organización en capas es fundamental para crear aplicaciones escalables y fáciles de probar.
Las tres capas principales en Clean Architecture son:
-
Capa de presentación: Contiene todos los elementos relacionados con la interfaz de usuario como textos, botones y composables. Esta capa interactúa directamente con el usuario y maneja exclusivamente la lógica de presentación.
-
Capa de dominio: Define las entidades del dominio y las interfaces de los repositorios. Representa el núcleo de la aplicación y sus reglas de negocio.
-
Capa de datos: Implementa los repositorios y los data sources. Es responsable de la persistencia de datos y la comunicación con fuentes externas como APIs.
¿Cómo implementar la capa de datos en Clean Architecture?
La capa de datos es crucial para manejar la comunicación con fuentes externas. Esta capa actúa como un puente entre la aplicación y los servicios externos, permitiendo que el resto de la aplicación no necesite conocer los detalles de implementación de cómo se obtienen o almacenan los datos.
Para implementar esta capa, necesitamos:
- Crear modelos DTO (Data Transfer Objects)
- Definir interfaces para servicios API
- Configurar la inyección de dependencias
Veamos cada uno de estos pasos en detalle:
¿Cómo crear modelos DTO para mapear respuestas JSON?
Los DTOs son objetos que representan la estructura de los datos que recibimos de fuentes externas. En Kotlin, podemos usar data classes para crear estos modelos de manera concisa:
@JsonClass(generateAdapter = true)
data class OrderDTO(
val id: String,
val item: String,
@Json(name = "customer_name")
val customerName: String,
@Json(name = "total")
val price: Double,
@Json(name = "image_url")
val imageUrl: String
)
En este ejemplo, utilizamos anotaciones de Moshi (@JsonClass
y @Json
) para indicar cómo debe realizarse la deserialización del JSON. Las anotaciones son especialmente útiles cuando los nombres de las propiedades en el JSON no coinciden con los nombres que queremos usar en nuestro código.
¿Cómo definir interfaces para servicios API con Retrofit?
Retrofit es una biblioteca que facilita la comunicación con APIs REST. Para utilizarla, definimos una interfaz que describe los endpoints disponibles:
interface OrderAPI {
@GET("get_orders")
suspend fun getOrders(): Response<List<OrderDTO>>
@POST("preorders")
suspend fun savePreorders(): Response<Unit>
}
En este ejemplo:
- Usamos anotaciones de Retrofit (
@GET
y@POST
) para definir el tipo de petición HTTP y la ruta del endpoint. - Utilizamos funciones suspendidas (
suspend
) de Kotlin Coroutines para manejar operaciones asíncronas. - El tipo de retorno
Response<T>
nos permite acceder a información sobre la respuesta HTTP, como códigos de estado y encabezados.
Las funciones suspendidas son una característica de Kotlin que permite escribir código asíncrono de manera secuencial, lo que hace que sea más fácil de leer y mantener.
¿Cómo configurar la inyección de dependencias con Hilt?
Hilt es una biblioteca de inyección de dependencias para Android que facilita la gestión de dependencias en toda la aplicación. Para configurar Retrofit y nuestros servicios API con Hilt, necesitamos crear módulos que provean estas dependencias:
Módulo para proveer servicios API
@Module
@InstallIn(SingletonComponent::class)
class ApiModule {
@Provides
@Singleton
fun provideOrderAPI(retrofit: Retrofit): OrderAPI {
return retrofit.create(OrderAPI::class.java)
}
}
Módulo para configurar Retrofit
@Module
@InstallIn(SingletonComponent::class)
class RetrofitModule {
@Provides
@Singleton
fun provideRetrofit(httpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl("https://tu-url-base-de-mockapi.io/")
.client(httpClient)
.addConverterFactory(MoshiConverterFactory.create())
.build()
}
@Provides
@Singleton
fun provideHttpClient(): OkHttpClient {
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
}
}
En estos módulos:
- Usamos
@Module
y@InstallIn
para definir módulos de Hilt y especificar su alcance. - La anotación
@Singleton
asegura que solo se cree una instancia de cada dependencia. - Configuramos un interceptor de registro para ver las respuestas de la API en la consola, lo que es muy útil durante el desarrollo.
La inyección de dependencias nos permite desacoplar la creación de objetos de su uso, lo que facilita las pruebas y hace que nuestro código sea más modular.
¿Por qué es importante el logging en las peticiones API?
El logging de las peticiones y respuestas HTTP es crucial durante el desarrollo para:
- Depurar problemas de comunicación con la API
- Verificar que los datos enviados y recibidos tienen el formato esperado
- Entender mejor el comportamiento de la API
En nuestro ejemplo, configuramos el nivel de logging como BODY
, lo que nos permite ver el cuerpo completo de las respuestas. Esta información es invaluable cuando estamos integrando una nueva API o solucionando problemas.
La implementación de Clean Architecture, específicamente la capa de datos, es fundamental para crear aplicaciones robustas y mantenibles. Al separar claramente las responsabilidades y utilizar patrones como la inyección de dependencias, creamos un código más limpio y fácil de evolucionar. ¿Has implementado Clean Architecture en tus proyectos? Comparte tu experiencia en los comentarios.