doc(arch): update readme
This commit is contained in:
parent
3de7d01173
commit
0219e3d557
@ -7,7 +7,7 @@
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
@ -16,31 +16,159 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
|
||||
# Flutter - Wyatt Architecture
|
||||
|
||||
<p align="left">
|
||||
<a href="https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_analysis">
|
||||
|
||||
<img src="https://img.shields.io/badge/Style-Wyatt%20Analysis-blue.svg?style=flat-square" alt="Style: Wyatt Analysis" />
|
||||
|
||||
</a>
|
||||
<img src="https://img.shields.io/badge/SDK-Flutter-blue?style=flat-square" alt="SDK: Flutter" />
|
||||
</p>
|
||||
|
||||
Architecture for Flutter.
|
||||
|
||||
Following: <https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html>
|
||||
The Wyatt Architecture for Flutter.
|
||||
|
||||
## Features
|
||||
|
||||
- Usecase
|
||||
- Repository
|
||||
- DataSource
|
||||
- Entity
|
||||
|
||||
## Getting started
|
||||
|
||||
<!-- TODO -->
|
||||
* Usecase
|
||||
* Repository
|
||||
* DataSource
|
||||
* Entity
|
||||
|
||||
## Usage
|
||||
|
||||
<!-- TODO -->
|
||||
### Domain
|
||||
|
||||
Create your entities by extending `Entity` :
|
||||
|
||||
```dart
|
||||
class Photo extends Entity {
|
||||
final int id;
|
||||
final String url;
|
||||
|
||||
const Photo({
|
||||
required this.id,
|
||||
required this.url,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Then create the data sources by extending `BaseLocalDataSource` or `BaseRemoteDataSource` depending the type of data source.
|
||||
|
||||
```dart
|
||||
abstract class PhotoRemoteDataSource extends BaseRemoteDataSource {
|
||||
Future<Photo> getPhoto(int id);
|
||||
Future<List<Photo>> getAllPhotos({int? start, int? limit});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Then you can create your repositories by extenting `BaseRepository` :
|
||||
|
||||
```dart
|
||||
abstract class PhotoRepository extends BaseRepository {
|
||||
FutureResult<Photo> getPhoto(int id);
|
||||
FutureResult<List<Photo>> getAllPhotos({int? start, int? limit});
|
||||
}
|
||||
```
|
||||
|
||||
> Here the repository is just a proxy of the data sources with result type (to have beautiful error handling).
|
||||
|
||||
And finaly create your different usecases by using `UseCase<Parameters, ReturnType>` :
|
||||
|
||||
```dart
|
||||
class RetrieveAllPhoto extends UseCase<QueryParameters, List<Photo>> {
|
||||
final PhotoRepository _photoRepository;
|
||||
|
||||
RetrieveAllPhotos(this._photoRepository);
|
||||
|
||||
@override
|
||||
FutureResult<List<Photo>> call(QueryParameters params) {
|
||||
final photos = _photoRepository.getAllPhotos(
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
);
|
||||
return photos;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> In fact, here we need a new parameter object, so let's create it:
|
||||
|
||||
```dart
|
||||
class QueryParameters {
|
||||
final int? start;
|
||||
final int? limit;
|
||||
|
||||
QueryParameters(this.start, this.limit);
|
||||
}
|
||||
```
|
||||
|
||||
### Data
|
||||
|
||||
We start by creating models for photos and list of photos. You can use `freezed`. The `PhotoModel` extends `Photo` with some de/serializer capabilities. And those are used only in data layer.
|
||||
|
||||
Then implements your data sources:
|
||||
|
||||
```dart
|
||||
class PhotoApiDataSourceImpl extends PhotoRemoteDataSource {
|
||||
final MiddlewareClient _client;
|
||||
|
||||
PhotoApiDataSourceImpl(this._client);
|
||||
|
||||
@override
|
||||
Future<Photo> getPhoto(int id) async {
|
||||
final response = await _client.get(Uri.parse('/photos/$id'));
|
||||
final photo =
|
||||
PhotoModel.fromJson(jsonDecode(response.body) as Map<String, Object?>);
|
||||
return photo;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Photo>> getAllPhotos({int? start, int? limit}) async {
|
||||
final startQuery = start.isNotNull ? '_start=$start' : '';
|
||||
final limitQuery = limit.isNotNull ? '_limit=$limit' : '';
|
||||
final delimiter1 =
|
||||
(startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : '';
|
||||
final delimiter2 =
|
||||
(startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : '';
|
||||
final url = '/photos$delimiter1$startQuery$delimiter2$limitQuery';
|
||||
final response = await _client.get(Uri.parse(url));
|
||||
final photos =
|
||||
ListPhotoModel.fromJson({'photos': jsonDecode(response.body)});
|
||||
return photos.photos;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 1: Note that here we use `MiddlewareClient` from our http package.
|
||||
|
||||
> 2: You can create multiple implementations (one real and one mock for example).
|
||||
|
||||
And implement the repositories:
|
||||
|
||||
```dart
|
||||
class PhotoRepositoryImpl extends PhotoRepository {
|
||||
final PhotoRemoteDataSource _photoRemoteDataSource;
|
||||
|
||||
PhotoRepositoryImpl(
|
||||
this._photoRemoteDataSource,
|
||||
);
|
||||
|
||||
@override
|
||||
FutureResult<Photo> getPhoto(int id) => Result.tryCatchAsync(
|
||||
() => _photoRemoteDataSource.getPhoto(id),
|
||||
(error) => ServerException('Cannot retrieve photo $id.'),
|
||||
);
|
||||
|
||||
@override
|
||||
FutureResult<List<Photo>> getAllPhotos({int? start, int? limit}) async =>
|
||||
Result.tryCatchAsync(
|
||||
() => _photoRemoteDataSource.getAllPhotos(start: start, limit: limit),
|
||||
(error) => ServerException('Cannot retrieve all photos.'),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
That's all.
|
@ -14,4 +14,4 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// TODO(wyatt): Add some tests
|
||||
// Nothing to test as there is no logic in this package.
|
||||
|
Loading…
x
Reference in New Issue
Block a user