Saltar al contenido principal

Repositorios

Clases

Nombrado de repositorios

El nombre de la clase repositorio debe representar el módulo o el conjunto de datos que gestiona y debe terminar con el sufijo Repository.

class UserRepository

class ReportRepository

class PortfolioRepository

Extensión de la interfaz del repositorio (capa de dominio)

La clase repositorio de la capa de datos debe extender de la interfaz repositorio de la capa dominio.

class UserRepository extends IUserRepository {}

class ReportRepository IReportRepository {}

class PortfolioRepository IPortfolioRepository {}

Constructores

Inyección de dependencias

El repositorio debe recibir las variables y dependencias como parámetros delegados y asignarlos a los atributos privados respectivos de la clase en el constructor.

class UserRepository extends IUserRepository {
// Se pide por parametros y se instancia a la variable api en el archivo
UserRepository(UserApi api) : _api = api;

final UserApi _api;
}

Atributos

Declarar variables públicas y privadas

A. Atributos privados

Los atributos de uso interno de la clase, como dependencias y variables auxiliares, deben ser atributos privados.

B. Atributos públicos

Los atributos públicos que sean parte de la firma de la interfaz del repositorio deben declararse como getters de atributos privados.

abstract class IUserRepository {
List<Country> countries; // Atributo parte de la firma de la interfaz
}

class UserRepository extends IUserRepository {
List<Country> _countries = <Country>[];

List<Country> get countries => _countries; // Implementación del atributo de la interfaz por medio de un getter.
}

Streams

Los Streams deben crearse a partir de un StreamController que controle el flujo de información del Stream desde y hacia el repositorio.

Declaración

A. StreamController de tipo BehaviorSubject

El StreamController debe declararse como una variable privada. El valor asignado debe ser de tipo BehaviorSubject del paquete package:rxdart.

B. Atributo de tipo Stream<T>

El atributo de tipo Stream<T> debe ser un getter del stream de la variable StreamController de la clase.

class UserRepository extends IUserRepository {
UserRepository(UserApi api) : _api = api;

final UserApi _api;

final _currentUserController = BehaviorSubject<User>();


/// Stream que emite el estado actual y
/// los suscriptores pueden escuchar este stream para recibir actualizaciones.
Stream<User> get currentUserStream => _currentUserController.stream;
}

Logger

Las funciones en los repositorios deben realizar un control de ejecución de las llamadas con la función log de la librería dart:developer.

Rastreo de llamadas

A. Eventos de ejecución

Al momento de iniciar una llamada deben registrarse al menos tres eventos de la ejecución: Al iniciar, al finalizar con éxito o al finalizar con un error.

B. Emojis para identificar los eventos de ejecución

Cada evento de ejecución debe incluir un emoji en el log de la llamada. Los emojis deben ser los siguientes:

  • 📡 Inicio de la llamada
  • ✅ Llamada exitosa
  • ❌ Error en la llamada

C. Variable _source

Los repositorios deben declarar la variable privada _source de tipo estática y constante con el nombre de la clase para identificar el origen de la llamada de la función log.

D. Declaración de parámetros error y stackTrace en el log de bloque catch

Se deben declarar los parámetros error y stackTrace del método log en el bloque catch de la función.

class PostRepository extends IPostRepository {
PostRepository({required PostApi api}) : _api = api;

final PostApi _api;

static const String _source = 'PostRepository';


Future<void> deleteComment({
required String userId,
required String commentId,
}) async {
try {
log(
'📡 Delete comment $commentId',
name: '$_source.deleteComment',
);
await _api.deleteCommentPost(
itemId: commentId,
ownerId: userId,
);
log(
'✅ Success delete comment $commentId',
name: '$_source.deleteComment',
);
} catch (e, s) {
log(
'❌ Delete comment $commentId',
name: '$_source.deleteComment',
error: e,
stackTrace: s,
);
rethrow;
}
}
}

Métodos

Flujo de ejecución (try/catch)

Las funciones de los repositorios deben incluir un control de flujo implementado bajo un try/catch y del retorno de excepciones segun sea el caso. Como el siguiente ejemplo:

class ReportsRepository extends IReportsRepository {
ReportsRepository(ReportsApi api) : api = api;

final _source = 'ReportsRepository';
final ReportsApi api;


Future<void> createReport({
required Report report,
required String locale,
}) async {
try {
log(
'📡 Creating report',
name: '$_source.createReport',
);

await api.createReport(
report: ReportModel.fromEntity(report),
locale: locale,
);

log(
'✅ Report created',
name: '$_source.createReport',
);
} on ResponseException catch (e) {
log(
'❌ Error creating the report: ${e.message}',
name: '$_source.followProfile()',
error: e,
);
throw ReportProfileException(
message: e.message,
);
} catch (e) {
log(
'❌ Error creating the report',
name: '$_source.createReport',
error: e,
);
rethrow;
}
}
}