I used BloC pattern to create an application.
There is a data provider layer that is responsible to request a session code from the remote server.
abstract class AppApi{
/// Logins a user to server and return a [Session].
///
/// Throw [HttpException] if response status code is not 200.Throw
/// [FetchSessionException] if response message is not "OK" or response data is null.
Future<Session> fetchSession(String username, String password);
}
There is a repository layer that is responsible to expose the session with a Stream<Session> get session
to the application layer.
abstract class LoginRepository {
factory LoginRepository(AppApi appApi) =>
LoginRepositoryImpl(appApi);
Stream<Session> get session;
Future<void> getSession(String username, String password);
}
There is a cubit in the application layer that subscribes to the repository session stream and with hybricCubit
it saves the session.
class SessionCubit extends HydratedCubit<PersistenceSession> {
final LoginRepository _loginRepository;
late StreamSubscription<Session> _loginStreamSubscription;
static final defaultSessionState = PersistenceSession.empty;
SessionCubit(this._loginRepository) : super(defaultSessionState) {
_loginStreamSubscription =
_loginRepository.session.asBroadcastStream().listen((session) {
if (session == Session.empty) {
emit(defaultSessionState);
} else {
emit(
state.copyWith(session: session.sessionCode),
);
}
});
}
}
Each time other cubits want to request to the server they request the session with context.read<PersisSessionCubit>.state.session.code
and pass the code as an argument to the repository and data layer.
But I want to persist the session in the repository layer or data layer and then other cubits in the application layer use this saved session with a StreamSubscription
.
At which layer can I save the session to prevent tight coupling?
3
Answers
I managed the architecture base on BLoC architecture guide to separate data layer and domain layer and application layer.
Then in the repository layer create an algorithm to check if the session in persist data layer does not exist or has expired then call the logout method (since API doesn't support the refresh token endpoint I called the logout method which clears the storage and redirects the user to the login screen) Then when a user request login and we get a 200 response status code with a session, we store the session in persist layer.
The key to solving this problem is on the repository layer and persist policy to manage calls to the remote server or use the session in persist data layer.
You could just keep the
StreamSubscription<Session>
in theLoginRepository
class. That instance ofLoginRepository
would get passed into the constructor of any Bloc/Cubit that needs it, and they all would listen to the same stream.That being said, I see nothing wrong with how you have it setup now where you just grab session code from the
SessionCubit
when you need it. You already have loose coupling setup because you don’t have the other cubits directly depending on theSessionCubit
. That keeps testing easier without having to stub other Cubits in eachblocTest
instance.Either of these approaches are in line with the Bloc pattern, and maintain loose coupling between Bloc classes.
Step 1: Define the SessionState class
Step 2: Define the S## Heading ##essionEvent class
Step 3: Define the SessionBloc class
Step 4: Load the initial session state from persistent storage
Step 5: Handle the LogoutEvent by updating the session state and saving it to persistent storage
Step 6: Use the SessionBloc in your app