repo_case 0.1.2 repo_case: ^0.1.2 copied to clipboard
repo_case allows you to auto-generate use cases classes from your repository signature class
Repo Case #
Automatically generate usecase classes from your repository class definition in Dart and Flutter.
Check out the official guide on repo_case and Clean Architecture #
Made by Sandro Maglione, check out his personal official website sandromaglione.com
Overview #
- Import the package (as well as the
repo_case_generator
andbuild_runner
) - Create a repository class
- Annotate the class with
@repoCase
- Run the build
- Complete!
Quick tutorial #
Create your repository class definition in a new repository.dart
file and annotate it with @repoCase
:
@repoCase
abstract class UserRepository {
String getString(int param);
}
Launch the build command to generate the usecase class:
flutter pub run build_runner build
The package will generate a usecase class for each method of the repository in a new repository.rc.dart
file as follows:
class GetStringRepo {
final UserRepository userRepository;
const GetStringRepo({
@required this.userRepository,
});
String call(GetStringRepoParams params) {
return userRepository.getString(
params.param,
);
}
}
class GetStringRepoParams {
final int param;
const GetStringRepoParams({
@required this.param,
});
}
You can now use the usecase class to access the repository:
/// Call repository with correct parameters
final String result = getStringRepo(
GetStringRepoParams(
param: 1,
),
);
Motivation #
This package is inspired by the by the Flutter TDD Clean Architecture Course from Reso Coder.
Specifically, the goal of the package is to autogenerate usecase classes. The template for the usecase class is presented in the 2nd video of the course.
The usecase class aims to abstract the domain layer from the presentation layer. For each method of the repository class we should write a new usecase class, which is then called from the presentation layer to access the repository.
The template of each usecase class as presented in the course is basically always the same. The only differences are the name of the method, the parameters, and its return type. Perfect usecase for code generation!
Import the package #
Import the repo_case
package as a normal dependencies and the repo_case_generator
package as a dev_dependencies as well as the build_runner
package (needed for code generation) in your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
repo_case: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: any
repo_case_generator: ^0.1.2
Clean Architecture #
Entity #
The entity class contains all the data exposed to the presentation layer
, which comes from the data layer
(database, local storage, etc.) and is accessed through the domain layer
. The presentation layer will call the usecase class to access the entity to be displayed in the app.
We create a new domain
folder and an entities
folder inside it. We then create a entity class in a new entity.dart
file inside the entities folder:
/// lib/domain/entities/entity.dart
class Entity {
final String data;
const Entity(this.data);
}
Model #
The models are used to fetch and convert external raw data (json, xml, etc.) to dart objects. These classes extends the entities in order to be passed from the data layer to the presentation layer.
We create a new data
folder and a models
folder inside it. We then create a model class in a new model.dart
file inside the models folder:
/// lib/data/models/model.dart
class Model extends Entity {
const Model(String data) : super(data);
}
Repository #
The repository contains the methods that will be called from the presentation layer to access the data from external sources. It defines all the usecases that can be accessed by the presentation layer. The repository will fetch the models
from the data layer and return entities
to the presentation layer.
We create a repository
folder inside the domain folder. We then create a repository class in a new dart file. The file must contain an abstract class
annotated with the @repoCase
annotation:
/// lib/domain/repository/user_repository.dart
@repoCase
abstract class UserRepository {
Entity getData(String param);
}
We can now run the build command to autogenerate the usecase classes:
flutter pub run build_runner build
This command will generate a new user_repository.rc.dart
file in the same folder of the repository class (rc
stays for 'repo_case'):
/// lib/domain/repository/user_repository.rc.dart
class GetDataRepo {
final UserRepository userRepository;
const GetDataRepo({
@required this.userRepository,
});
Entity call(GetDataRepoParams params) {
return userRepository.getData(
params.param,
);
}
}
class GetDataRepoParams {
final String param;
const GetDataRepoParams({
@required this.param,
});
}
Repository concrete implementation #
We must also define the concrete implementation of the repository class that will fetch the model from the data layer and return the respective entity.
We create a new repository
folder inside the data folder. We then create a new file containing the concrete implementation of our repository:
class UserRepositoryImpl implements UserRepository {
@override
Entity getData(String param) {
/// Get data from data sources (database, local storage, etc.)
return Model(param);
}
}
Access the entity from the presentation layer #
We can now call the usecase class from the presentation layer to access the entities.
For example, we could have a bloc
class that defines a method to fetch an entity to display in the app. Here below an example of how we would implement it:
class UserBloc {
/// Usecase class generated by the repo_case package
final GetDataRepo getDataRepo;
const UserBloc(this.getDataRepo);
Entity getDataFromRepository(String param) {
return getDataRepo(
/// Params class generated by the repo_case package
GetDataRepoParams(
param: param,
),
);
}
}
Injectable #
The package is designed to work with the injectable
package.
All the usecase classes have the -Repo
suffix. You can therefore add the following rule to your build.yaml
file to automatically add the usecase classes to the list of classes generated by the injectable package. Check out the example for more details:
targets:
$default:
builders:
injectable_generator:injectable_builder:
options:
auto_register: true
class_name_pattern: "Repo$"
Roadmap #
I am always open for suggestions and ideas for possible improvements or fixes.
Feel free to open a Pull Request if you would like to contribute to the project.
If you would like to have a new feature implemented, just write a new issue.
Versioning #
- v0.1.2 - 20 November 2020
- v0.1.1 - 20 November 2020
- v0.1.0 - 15 November 2020
License #
MIT License, see the LICENSE.md file for details.