0 purchases
api bloc
Api BLoC #
Flutter widgets designed to simplify the implementation of the BLoC pattern for REST APIs within an MVC architecture. Significantly reduces boilerplate code by automating BLoC pattern and test generation for handling REST API interactions.
Features #
Significantly reducing boilerplate code of bloc pattern to interact with REST API.
Generic classes for handling various API states such as loading, success, & error for READ states and idle, loading, success, failed & error for WRITE states.
Customizable builder and listener functions to respond to state changes.
Generate api bloc pattern & bloc test on command.
Getting Started #
To use this library, add api_bloc as a dependency in your pubspec.yaml file.
dependencies:
api_bloc: ^3.0.1
copied to clipboard
and to use api_bloc_cli run this command in terminal.
dart pub global activate api_bloc
copied to clipboard
Fetching Scenario #
import 'package:api_bloc/api_bloc.dart';
class GetUserController extends ReadController {
@override
Future<void> onRequest(Map<String, dynamic> args) async {
// Mock Delay
await Future.delayed(const Duration(seconds: 1));
Response response = await Dio().get(
'https://reqres.in/api/users/2',
onReceiveProgress: (received, total) {
emit(ReadLoadingState<double>(data: received / total));
},
);
emit(ReadSuccessState<GetUserModel>(
data: GetUserModel.fromJSON(response.data)));
}
}
copied to clipboard
Put the controller inside the [ApiBloc] widget.
import 'package:api_bloc/api_bloc.dart';
ApiBloc(
controller: UserDetailController(),
child: BlocBuilder<UserDetailController, ReadStates>(
builder: (context, state, child) {
if (state is ReadSuccessState<UserDetailModel>) {
} else if (state is ReadErrorState) {}
return Text(state.message);
},
),
);
copied to clipboard
When the controller is first initiated, on ReadController it automatically runs the request function. If you want to rerun it, you can do it by calling:
controller.run();
copied to clipboard
Submitting Scenario #
import 'package:api_bloc/api_bloc.dart';
class UserUpdateController extends WriteController {
@override
Future<void> onRequest(Map<String, dynamic> args) async {
// Delay to make the loading state more noticable.
await Future.delayed(const Duration(milliseconds: 300));
// Emit your success and failed state here ↓↓
if (isSuccess) {
emit(const WriteSuccessState<UserUpdateSuccessModel>(
data: UserUpdateSuccessModel.test()));
} else {
emit(const WriteFailedState<UserUpdateFailedModel>(
data: UserUpdateFailedModel.test()));
}
}
}
copied to clipboard
Put the controller inside the [ApiBloc] widget.
import 'package:api_bloc/api_bloc.dart';
ApiBloc(
controller: UserUpdateController(),
child: BlocConsumer<UserUpdateController, WriteStates>(
listener: (context, state) {
if (state is WriteSuccessState<UserUpdateSuccessModel>) {
} else if (state is WriteFailedState<UserUpdateFailedModel>) {
} else if (state is WriteErrorState) {}
},
builder: (context, state, child) {
if (state is WriteLoadingState) {}
return Text(state.message);
},
),
);
copied to clipboard
Unlike the ReadController, the initial state of WriteControllerRequest is idle state, so to run the request you need to trigger the controller.run() manually.
Generating Api Bloc Structure (Optional) #
To quickly create a module, for example GET detail and GET list, also PUT update, POST create, and DELETE for a module called USER using this library, run this command in terminal:
dart run api_bloc --output lib/src --create user --read detail,list --write update,create,delete
copied to clipboard
It will generate this structure in your project:
📂 lib/src/user/
📄 lib/src/user/user.dart
📄 lib/src/user/controllers/user_detail.dart
📄 lib/src/user/controllers/user_list.dart
📄 lib/src/user/controllers/user_update.dart
📄 lib/src/user/controllers/user_create.dart
📄 lib/src/user/controllers/user_delete.dart
📄 lib/src/user/models/user_detail.dart
📄 lib/src/user/models/user_list.dart
📄 lib/src/user/models/user_update.dart
📄 lib/src/user/models/user_create.dart
📄 lib/src/user/models/user_delete.dart
📄 lib/src/user/views/user_detail.dart
📄 lib/src/user/views/user_list.dart
📄 lib/src/user/views/user_update.dart
📄 lib/src/user/views/user_create.dart
📄 lib/src/user/views/user_delete.dart
📂 test/src/user/
📄 test/src/user/controllers/user_detail.dart
📄 test/src/user/controllers/user_list.dart
📄 test/src/user/controllers/user_update.dart
📄 test/src/user/controllers/user_create.dart
📄 test/src/user/controllers/user_delete.dart
📄 test/src/user/models/user_detail.dart
📄 test/src/user/models/user_list.dart
📄 test/src/user/models/user_update.dart
📄 test/src/user/models/user_create.dart
📄 test/src/user/models/user_delete.dart
📄 test/src/user/views/user_detail.dart
📄 test/src/user/views/user_list.dart
📄 test/src/user/views/user_update.dart
📄 test/src/user/views/user_create.dart
📄 test/src/user/views/user_delete.dart
copied to clipboard
Sentry Integration #
You also can integrate this library with Sentry by creating custom controllers like this:
abstract class ReadSentryController extends BlocRequest<ReadStates> {
ReadSentryController({
this.autoRun = true,
JSON args = const {},
}) : super(value: const ReadLoadingState()) {
if (autoRun) run(args);
}
@override
Future<void> run([JSON args = const {}]) async {
emit(const ReadLoadingState());
final http = SentryHttpClient();
try {
await onRequest(http, args);
} catch (e, s) {
await onError(e, s);
} finally {
http.close();
}
}
Future<void> onRequest(SentryHttpClient http, JSON args);
Future<void> onError(dynamic e, StackTrace s) async {
await Sentry.captureException(e, stackTrace: s);
emit(ReadErrorState(message: e.toString(), data: s));
}
final bool autoRun;
}
abstract class WriteControllerSentryController extends BlocRequest<WriteControllerStates> {
WriteControllerSentryController() : super(value: const WriteControllerIdleState());
@override
Future<void> run([JSON args = const {}]) async {
emit(const WriteControllerLoadingState());
final http = SentryHttpClient();
try {
await onRequest(http, args);
} catch (e, s) {
await onError(e, s);
} finally {
http.close();
}
}
Future<void> onRequest(SentryHttpClient http, JSON args);
Future<void> onError(dynamic e, StrackTrace s) async {
await Sentry.captureException(e, stackTrace: s);
emit(WriteControllerErrorState(message: e.toString(), data: s));
}
}
copied to clipboard
Whenever you want to interact with the API, create a controller like this:
class ReadUserRequest extends ReadSentryController {
Future<void> onRequest(http, args) async {
await Future.delayed(const Duration(milliseconds: 300));
final response = await http.get(Uri('http://baseUrl/api/user/123'));
emit(ReadSuccessState<UserModel>(data: UserModel.fromJSON(jsonDecode(response.body))));
}
}
copied to clipboard
Example #
https://github.com/Nialixus/api_bloc/tree/main/example/lib
https://medium.com/@nialixus/flutter-simplifying-api-requests-with-api-bloc-library-17222128422e
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.