Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global dependency on flutter_bloc

I have a problem implementing an app on Flutter using flutter_bloc. I understood the core concepts but I found an "edge case" where there is not examples or guides (at least that I could find):

(I will simplify the problem) I have a bloc called AuthBloc that manages the App. If the state is NotAuthenticated then the App should show the LoginScreen but if is Authenticated the App should show the HomeScreen. Inside the HomeScreen I have 4 blocs, where each bloc has its states and events, but all of them has dependencies on different Repositories to get some data from an API.

All the Repositories need a token to make the API requests. The first problem came here. How can I get the token from all the repositories? If I use a UserRepository to store the token, I will need to pass it as dependency to each Repository (probably works but I don't think its the right way to do it). So, what can be the right way to manage this?

The second problem is:

If somehow I can get the token on all the repositories queries, what happens when the token is revoked? The app should return to the LoginScreen and for that I would need to notify the AuthBloc through an event (for example InvalidTokenEvent). And the AuthBloc should change its state to NotAuthenticated and that will rebuild the LoginScreen. But the question is: How can I notify the AuthBloc from other blocs or repositories? The first idea I had is through dependency injection: I can pass the AuthBloc to every other bloc in the constructor, so when the repository request returns a token expired, the XBloc can call AuthBloc.add(InvalidTokenEvent). But again, if I have a lot of blocs I would need to do that in each bloc. So, what's the right way to do this?

Thank you for any help!

like image 906
Ademir Villena Zevallos Avatar asked Nov 16 '22 13:11

Ademir Villena Zevallos


1 Answers

To answer your first problem:

Your repositories should not be handling the API authentication. That should be the job of the data layer under the repository layer.

What I recommend is having one instance of a http client and then provide this instance to all the repositories. This way your client can have an interceptor that handles adding the saved token to all your requests. So your repositories could look something like this:

class OrderRepository {
  const OrderRepository(this.httpClient);

  final HttpClient httpClient;
}

Then the rest would be as simple as initializing your httpclient then pass it to your repositories which you can provide to your app and blocs by using RepositoryProvider or MultiRepositoryProvider. Then do the same thing with your repositories and blocs passing your repositories to your blocs inside of your blocproviders.

To answer your second problem:

If authenticating and passing your token to all requests can be handled at the http client layer so should unauthenticating and revoking the token. Therefore to reflect this in your authentication state your AuthRepository should listen to your http client and similarly your AuthBloc should listen to your AuthRepository. You can do this by exposing a stream of your authentication status in both your http client and your AuthRepository that gets listened to in your auth bloc.

So it would look like this: http client gets a 401 error so it removes the token from storage and then adds the unauthenticated status to the stream. This stream is then exposed in auth repository and then in auth bloc have a stream subscription which listens to the authentication status to emit an unauthenticated state.

like image 177
Hadi Hassan Avatar answered Dec 21 '22 17:12

Hadi Hassan