api_bloc 1.5.0 api_bloc: ^1.5.0 copied to clipboard
A Flutter library for managing API calls using the BLoC pattern. This library provides a set of classes and utilities to simplify API calls and manage state changes.
Api BLoC #
A Flutter library for managing API calls using the BLoC pattern. This library provides a set of classes and utilities to simplify API calls and manage state changes.
Features #
- Easily manage API calls and state changes using the BLoC pattern.
- Generic classes for handling various API states such as loading, success, and error.
- Customizable builder and listener functions to respond to state changes.
- Automatic disposal of the controller to prevent memory leaks.
Getting Started #
To use this library, add api_bloc
as a dependency in your pubspec.yaml
file.
dependencies:
api_bloc: ^1.5.0
Usage #
- Create a subclass of [BlocController] with [BlocStates].
This library already provide you with FetchStates [
loading
,success
,error
] and SubmitStates [idle
,loading
,success
,failed
,error
], But you can create custom state by extending [BlocStates].
Fetching Scenario #
import 'package:api_bloc/api_bloc.dart';
class GetUserController extends FetchController {
@override
Future<void> request({List<Object> args = const []}) async {
await Future.delayed(const Duration(seconds: 1));
final response = await Dio().get('https://reqres.in/api/users/2');
final model = GetUserModel.fromJson(response.data);
emit(FetchSuccessState<GetUserModel>(data: model));
}
}
- Put the controller inside [ApiBloc] widget.
import 'package:api_bloc/api_bloc.dart';
final controller = GetUserController();
ApiBloc.builder(
controller: controller,
builder: (context, state, child) {
if (state is FetchSuccessState<UserModel>) {
return Text('Username: ${state.data!.username}');
} else if (state is FetchErrorState){
return Text('Error occurred: ${state.message}');
} else {
return CircularProgressIndicator();
}
},
);
When the first time it initiate the controller, on fetching controller it's auto running the request function. But if you want to re run it, you can do it by calling
controller.run();
Submitting Scenario #
import 'package:api_bloc/api_bloc.dart';
class CreateUserController extends SubmitController {
@override
// We're going to dispose it manually if we set it as false.
bool get autoDispose => false;
@override
Future<void> request({List<Object> args = const []}) async {
await Future.delayed(const Duration(seconds: 1));
final response = await Dio().post('https://reqres.in/api/users/2',
data: FormData.fromMap({"name": args[0], "job": args[1]}));
if (response.statusCode == 201) {
final model = CreateUserModel.fromJson(response.data);
emit(SubmitSuccessState<CreateUserModel>(data: model));
} else {
emit(SubmitFailedState<Map<String, dynamic>>(
data: response.data,
message: "Expected response code output is 201"));
}
}
}
- Put the controller inside [ApiBloc] widget.
import 'package:api_bloc/api_bloc.dart';
final controller = CreateUserController();
ApiBloc(
controller: controller,
listener: (context, state) {
if (state is SubmitSuccessState<CreateUserModel>) {
snackbar(context, message: "Succesfully creating new user with id #${state.data!.id}");
} else if (state is SubmitFailedState) {
snackbar(context, message: "Failed because ${state.message}", color: Colors.grey);
} else if (state is SubmitErrorState) {
snackbar(context, message: state.message, color: Colors.red);
}
},
builder: (context, state, child) {
if (state is SubmitLoadingState) {
return TextButton(text: "Loading ...");
} else {
return TextButton(text: "Create", onPressed: () => controller.run());
}
},
);
Unlike the fetch controller, initial state of submit controller is idle
state, so to run the request you need to trigger the controller.run()
manually.
Using Extension #
Now you can easily customize how your ApiBloc
handles different state scenarios using these new extensions:
onIdle
: HandleSubmitIdleState
and only work withSubmitController
.onLoading
: HandleFetchLoadingState
and only work withFetchController
orSubmitLoadingState
that only work withSubmitController
.onSuccess
: HandleFetchSuccessState
and only work withFetchController
orSubmitSuccessState
that only work withSubmitController
.onFailed
: HandleSubmitFailedState
and only work withSubmitController
.onError
: HandleFetchErrorState
and only work withFetchController
orSubmitErrorState
that only work withSubmitController
.
import 'package:api_bloc/api_bloc.dart';
final controller = CreateUserController();
ApiBloc(
controller: controller,
child: TextButton(text: "Create", onPressed: () => controller.run()))
.onLoading(
builder: (context, state, child) {
return TextButton(text: "Loading ...");
})
.onFailed(
listener: (context, state, child) {
snackbar(context, message: "Failed because ${state.message}", color: Colors.grey);
})
.onSuccess<CreateUserModel>(
listener: (context, state, child) {
snackbar(context, message: "Succesfully creating new user with id #${state.data!.id}");
})
.onError(
listener: (context, state, child) {
snackbar(context, message: state.message, color: Colors.red);
})
.onState<BlocStates<Object>>(
listener; (context, state) {
snackbar(context, message: "You're in this custom state of ${state.runtimeType}");
},
builder: (context, state, child) {
return Text("You're in this custom state of ${state.runtimeType}");
}
);