Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/avdosev/either_dart
Either class for Dart or Flutter projects.
https://github.com/avdosev/either_dart
dart dart-either dart-either-monad dart-functional-programming either either-dart error-handling flutter functional-programming
Last synced: 5 days ago
JSON representation
Either class for Dart or Flutter projects.
- Host: GitHub
- URL: https://github.com/avdosev/either_dart
- Owner: avdosev
- License: mit
- Created: 2020-09-12T15:47:48.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2023-06-10T18:37:27.000Z (over 1 year ago)
- Last Synced: 2024-08-01T12:19:04.475Z (3 months ago)
- Topics: dart, dart-either, dart-either-monad, dart-functional-programming, either, either-dart, error-handling, flutter, functional-programming
- Language: Dart
- Homepage: https://pub.dev/packages/either_dart
- Size: 97.7 KB
- Stars: 26
- Watchers: 4
- Forks: 7
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# either dart · ![build status](https://github.com/avdosev/either_dart/workflows/unittests/badge.svg)
The library for error handling and railway oriented programming.
This library supports async "map" and async "then" hiding the boilerplate of working with asynchronous computations Future\[Either\].
## Installation
Add to pubspec.yml:
```
dependencies:
either_dart: ... // latest package version
```## Documentation
https://pub.dev/documentation/either_dart/latest/either/either-library.html
## Pub dev
https://pub.dev/packages/either_dart
## How to use it?
Sections:
* [Basic usage](#basic-usage)
* [Advanced usage](#advanced-usage)
* [Case - Solution](#case---solution)### Basic usage
Create two entities for example, you can use your own abstractions for your project.
```dart
enum AppError {
NotFound,
// some errors codes
}class MyError {
final AppError key;
final String? message;const MyError({
required this.key,
this.message,
});
}
```We can use Either as shown below:
```dart
Either getCityNameByCode(int code) {
const cities = {
/// some cities
};if (cities.contains(code)) {
return Right(cities[code]!);
} else {
return Left(
key: AppError.NotFound,
message: '[getCityNameByCode] can`t convert code:$code to city name',
);
}
}
```Too, you can use `Either.cond` and `Either.condLazy` for simple cases:
```dart
return Either.condLazy(cities.contains(code),
() => cities[code]!,
() => MyError(
key: AppError.NotFound,
message: '[getCityNameByCode] can`t convert code:$code to city name',
),
);
```Either has the following methods:
***note:*** \
L - current `Left` type \
TL - new generic `Left` type \
R - current `Right` type \
TR - new generic `Right` type| name | result | description |
| --- | --- | --- |
| `isLeft` | `bool` | Represents the left side of Either class which by convention is a "Failure". |
| `isRight` | `bool` | Represents the right side of Either class which by convention is a "Success" |
| `left` | `L` | Get Left value, may throw an exception when the value is Right. **read-only** |
| `right` | `R` | Get Right value, may throw an exception when the value is Left. **read-only** |
| `either(TL fnL(L left), TR fnR(R right))` | `Either` | Transform values of Left and Right, equal of `bimap` in fp-libraries
| `fold(T fnL(L left), T fnR(R right))` | `T` | Fold Left and Right into the value of one type
| `map(TR fnR(R right))` | `Either` | Transform value of Right
| `mapLeft(TL fnL(L left))` | `Either` | Transform value of Left
| `mapAsync(FutureOr fnR(R right))` | `Future>` | Transform value of Right
| `mapLeftAsync(FutureOr fnL(L left))` | `Future>` | Transform value of Left
| `swap()` | `Either` | Swap Left and Right
| `then(Either fnR(R right))` | `Either` | Transform value of Right when transformation may be finished with an error
| `thenLeft(Either fnL(L left))` | `Either` | Transform value of Left when transformation may be finished with an Right
| `thenAsync(FutureOr> fnR(R right))` | `Future>` | Transform value of Right when transformation may be finished with an error
| `thenLeftAsync(FutureOr> fnL(L left))` | `Future>` | Transform value of Left when transformation may be finished with an Right### Advanced usage
This library provides an `FutureEither` extension which is designed to handle asynchronous computation with ease.
You don't need to import or use new classes to use it - just use `Future>`
| name | result | description |
| --- | --- | --- |
`either(TL fnL(L left), TR fnR(R right))` | `Future>` | Transform values of Left and Right
`fold(T fnL(L left), T fnR(R right))` | `Future` | Fold Left and Right into the value of one type
`mapRight(FutureOr fnR(R right))` | `Future>` | Transform value of Right
`mapLeft(FutureOr fnL(L left))` | `Future>` | Transform value of Left
`swap()` | `Future>` | Swap Left and Right
`thenRight(FutureOr> fnR(R right))` | `Future>` | Async transform value of Right when transformation may be finished with an error
`thenLeft(FutureOr> fnL(L left))` | `Future>` | Async transform value of Left when transformation may be finished with an RightExample:
```dart
/// --- helpers ---import 'package:either_dart/either.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'dart:convert';Future> safe(Future request) async {
try {
return Right(await request);
} catch (e) {
return Left(MyError(
key: AppError.BadRequest,
message: "Request executing with errors:$e"));
}
}Either checkHttpStatus(http.Response response) {
if (response.statusCode == 200)
return Right(response);
if (response.statusCode >= 500)
return Left(MyError(
key: AppError.ServerError,
message: "Server error with http status ${response.statusCode}"));
return Left(MyError(
key: AppError.BadResponse,
message: "Bad http status ${response.statusCode}"));
}Future> parseJson(http.Response response) async {
try {
return Right(await compute((body) {
final json = JsonCodec();
return json.decode(body));
}, response.body);
} catch (e) {
return Left(MyError(
key: AppError.JsonParsing,
message: 'failed on json parsing'));
}
}/// --- app code ---
//// network
Future> getDataFromServer() {
return
safe(http.get(Uri('some uri')))
.thenRight(checkHttpStatus)
.thenRight(parseJson)
.mapRight(Data.fromJson)
}```
### Case - Solution
* How I can use the value of `Either`?
You can use right or left getters, but you should check what value is stored inside (`isLeft` or `isRight`)
Also, my favorite methods `fold`, `either`
* `fold` - used when you need to transform two rails to one type
* `either` - used for two situations: 1. when you need transform left and right. 2. when you need to use stored value without next usage (see example).Example:
```dart
/// either method
showNotification(Either value) {
return value.either(
(left) => showWarning(left.message ?? left.key.toString()),
(right) => showInfo(right.toString()),
);
/// equal
if (value.isLeft) {
final left = value.left;
showWarning(left.message ?? left.key.toString()
} else {
showInfo(value.right.toString())
}
}
```
```dart
/// fold method
class MyWidget {
final Either> value;const MyWidget(this.value);
Widget build(BuildContext context) {
return Text(
value.fold(
(left) => left.message,
(right) => right.join(', ')),
);
/// or
return value.fold(
(left) => _buildSomeErrorWidget(context, left),
(right) => _buildSomeRightWidget(context, right),
);
}
}
```