New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Either with then() and catchError() #34
Comments
You just forgot to type Right and Left. Try this:
|
@torbenkeller thanks! |
@torbenkeller it's really strange, but I'm trapped in the similar situation :). Now I have a runtime exeption:
When your code goes into |
I don't know exactly why converting results of Futures to Eithers doesnt work as expected but there is the Task<MyResponse>(() => restClient.request())
.attempt() //returns Task<Either<Object, MyResponse>>
//Now you have to convert Task<Either<Object, MyResponse>> to Task<Either<Failure, MyResponse>>
.map(
(Either<Object, MyResponse> either) => either.leftMap((Object obj) {
try {
return obj as Failure;
} catch (e) {
throw obj;
}
}),
)
// Now you have to convert it to a Future<Either<Failure, MyResponse>> again
.run(); But this map function is boilerplate code so you can outsource it to an extension. Try this: extension TaskX<T extends Either<Object, dynamic>> on Task<T> {
Task<Either<Failure, A>> mapLeftToFailure<A>() {
return map<Either<Failure, A>>((Either<Object, dynamic> either) =>
either.fold<Either<Failure, A>>((Object obj) {
try {
return Left<Failure, A>(obj as Failure);
} catch (e) {
throw obj;
}
}, (dynamic u) {
try {
return Right<Failure, A>(u as A);
} catch (e) {
throw u;
}
}));
}
} You can use it like this: import'###extension.dart###';
...
Task<MyResponse>(() => restClient.request())
.attempt()
.mapLeftToFailure<MyResponse>()
.run(); |
@torbenkeller many thanks for this extension!
So now I can do this:
But let's suppose I want to call and return in
But now I also need to
So, I need to mark it as |
I would not recommend changing the extension. It is against the idea why you want to use an The Idea is you have runtime exceptions and specific cases like "No Data Selected" and create Failures from it. You use Failures to be independent of the "data selection layer". So when you create the Either the "data selection layer" is already throwing Failures and not HTTP Response Exceptions for example. And when you create the Either you don't want to be any buisness logic there. In code it would be like this: import 'package:http/http.dart' as http;
class RestClient {
...
Future<MyResponse> request() {
final Response response = await http.get(...);
switch (response.statusCode) {
case 200:
return MyResponse(response.body);
case 404:
throw ...Failure();
...
}
throw Failure();
}
} |
@torbenkeller you are right. But my |
Then write a wrapper function around the request function like this: Future<MyResponse> requestWrapper() async {
try {
return await http.get(...);
} on ...Exception {
throw ...Failure();
}
} |
@torbenkeller unfortunately, I didn't get your whole idea. I have
And NetworkRepository:
Here is an example of the case when I call the request, get 401, refresh access token, and call the first request again. How do you propose to do this and similar tasks? |
Hello, I didn't read through the whole conversation here but I think you may find these extension methods useful. Since I'm not an FP pro by any means, they're probably badly named but they serve the purpose well. Basically, it's an import 'package:dartz/dartz.dart';
extension FutureEither<L, R> on Future<Either<L, R>> {
Future<Either<L, R2>> flatMap<R2>(Function1<R, Future<Either<L, R2>>> f) {
return then(
(either1) => either1.fold(
(l) => Future.value(left<L, R2>(l)),
f,
),
);
}
Future<Either<L, R2>> map<R2>(Function1<R, Either<L, R2>> f) {
return then(
(either1) => either1.fold(
(l) => Future.value(left<L, R2>(l)),
(r) => Future.value(f(r)),
),
);
}
// TODO: Find an official FP name for mapping multiple layers deep into a nested composition
Future<Either<L, R2>> nestedMap<R2>(Function1<R, R2> f) {
return then(
(either1) => either1.fold(
(l) => Future.value(left<L, R2>(l)),
(r) => Future.value(right<L, R2>(f(r))),
),
);
}
Future<Either<L2, R>> leftMap<L2>(Function1<L, L2> f) {
return then(
(either1) => either1.fold(
(l) => Future.value(left(f(l))),
(r) => Future.value(right<L2, R>(r)),
),
);
}
} These allow you to |
@ResoDev, great stuff! Thank you for helping! Thank you also @torbenkeller for helping out! I'll close this ticket for now, since it looks a bit too open ended, but feel free to re-open if you feel the need. |
@ResoDev: Oh, and if one chooses to view your extensions as forming a composed monad, it is probably the current |
Inspired by ResoDev, I wrote something like this import 'package:dartz/dartz.dart';
extension FutureOption<A> on Future<Option<A>> {
Future<Option<B>> flatMap<B>(Function1<A, Future<Option<B>>> f) {
return then(
(option) => option.fold(
() => Future.value(none<B>()),
f,
),
);
}
Future<Option<B>> attemptMap<B>(Function1<A, Option<B>> f) {
return then(
(option) => option.fold(
() => Future.value(none<B>()),
(r) => Future.value(f(r)),
),
);
}
Future<Option<B>> nestedMap<B>(Function1<A, B> f) {
return then(
(option) => option.fold(
() => Future.value(none<B>()),
(r) => Future.value(some(f(r))),
),
);
}
Future<Either<L2, A>> toEither<L2>(L2 l) {
return then(
(option) => option.fold(
() => Future.value(left<L2, A>(l)),
(r) => Future.value(right<L2, A>(r)),
),
);
}
} |
Why we can't have this on docs? Actually, this package have any docs somewhere? |
@post("apiPrefix") _client.initLoginApi(fields).then((value) async {
flutter catachError not working. |
I want to use
Either
in this way:But it seems that I can't do this:
I necessarily need to use explicit type casting, like this:
even if I already return
Left(Failure())
in thecatchError()
.So, is explicit casting the most concise and elegant solution?
The text was updated successfully, but these errors were encountered: