From 0219e3d5579411dc317279b29f43ec440ab3d476 Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Thu, 10 Nov 2022 22:58:35 -0500 Subject: [PATCH] doc(arch): update readme --- packages/wyatt_architecture/README.md | 156 ++++++++++++++++-- .../test/wyatt_architecture_test.dart | 2 +- 2 files changed, 143 insertions(+), 15 deletions(-) diff --git a/packages/wyatt_architecture/README.md b/packages/wyatt_architecture/README.md index 2c025669..6a0e2acb 100644 --- a/packages/wyatt_architecture/README.md +++ b/packages/wyatt_architecture/README.md @@ -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 . --> - # Flutter - Wyatt Architecture

+ Style: Wyatt Analysis + SDK: Flutter

-Architecture for Flutter. - -Following: +The Wyatt Architecture for Flutter. ## Features -- Usecase -- Repository -- DataSource -- Entity - -## Getting started - - +* Usecase +* Repository +* DataSource +* Entity ## Usage - \ No newline at end of file +### 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 getPhoto(int id); + Future> getAllPhotos({int? start, int? limit}); +} + +``` + +Then you can create your repositories by extenting `BaseRepository` : + +```dart +abstract class PhotoRepository extends BaseRepository { + FutureResult getPhoto(int id); + FutureResult> 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` : + +```dart +class RetrieveAllPhoto extends UseCase> { + final PhotoRepository _photoRepository; + + RetrieveAllPhotos(this._photoRepository); + + @override + FutureResult> 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 getPhoto(int id) async { + final response = await _client.get(Uri.parse('/photos/$id')); + final photo = + PhotoModel.fromJson(jsonDecode(response.body) as Map); + return photo; + } + + @override + Future> 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 getPhoto(int id) => Result.tryCatchAsync( + () => _photoRemoteDataSource.getPhoto(id), + (error) => ServerException('Cannot retrieve photo $id.'), + ); + + @override + FutureResult> getAllPhotos({int? start, int? limit}) async => + Result.tryCatchAsync( + () => _photoRemoteDataSource.getAllPhotos(start: start, limit: limit), + (error) => ServerException('Cannot retrieve all photos.'), + ); +} +``` + +That's all. \ No newline at end of file diff --git a/packages/wyatt_architecture/test/wyatt_architecture_test.dart b/packages/wyatt_architecture/test/wyatt_architecture_test.dart index 43aa5bf9..dc7ea003 100644 --- a/packages/wyatt_architecture/test/wyatt_architecture_test.dart +++ b/packages/wyatt_architecture/test/wyatt_architecture_test.dart @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// TODO(wyatt): Add some tests +// Nothing to test as there is no logic in this package.