Comments (13)
Some suggestions on your implementation.
If getHeader
can fail then remember to wrap it in TaskEither
, otherwise use Task
instead of a Future
, something like the following:
final cachedHeader = await _(Task(() async => _headerCache.getHeader(fullPathToMarkdownFile)).toTaskEither());
When you use the .Do
constructor you can get and use response
like the following:
final response = await _(TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(error, stackTrace) => ApiFailure(
'Error on network request',
errorObject: error,
stackTrace: stackTrace,
),
));
You can then expand the logic without using map
or flatMap
:
return TaskEither.Do(
(_) async {
final requestUri =
await _(_uriParser(fullPathToMarkdownFile).toTaskEither());
final cachedHeader = await _headerCache.getHeader(fullPathToMarkdownFile);
final response = await _(TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(error, stackTrace) => ApiFailure(
'Error on network request',
errorObject: error,
stackTrace: stackTrace,
),
));
if (response.statusCode == 304) {
// ...
} else if (response.statusCode == 200) {
// You can run async code here using other TaskEither(s)
} else {
// ...
}
},
);
Let me know if this is clear, feel free to ask other questions otherwise
from fpdart.
Closing the issue as I have successfully migrated my project to fpdart 🥳
Thank you very much @SandroMaglione
from fpdart.
Thanks for responding. I will do as you have suggested in the evening. If everything works, I'm gonna close this issue. If I happen to encounter any issue, I shall post my question here again. Until then let's have this issue opened.
Thanks.
from fpdart.
Hi @SandroMaglione. I've a question.
TaskEither<Failure, RemoteResponse<String>> getDetail(
int id,
String fullPathToMarkdownFile,
) {
return TaskEither.Do(
(_) async {
final requestUri =
await _(_uriParser(fullPathToMarkdownFile).toTaskEither());
final cachedHeader = await _(
Task(
() => _headerCache.getHeader(fullPathToMarkdownFile),
).toTaskEither(),
);
final response = await _(
TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(e, stackTrace) {
if (e is DioException && e.isNoConnectionError) {
// How do I return RemoteResponse type object as this is my requirement?
}
return ApiFailure(
'Error on network request',
errorObject: e,
stackTrace: stackTrace,
);
},
),
);
if (response.statusCode == 200) {
final header = GithubHeader.parse(
id,
response,
fullPathToMarkdownFile,
);
await _(Task(() => _headerCache.saveHeader(header)).toTaskEither());
final html = response.data!;
return RemoteResponse.withNewData(html);
}
return const RemoteResponse.notModified();
},
);
}
The question has been commented down in the code. I couldn't figure out a way of doing it. Any help shall be appreciated. Thanks.
from fpdart.
In this case you should use mapLeft
to change the error type of TaskEither
:
final response = await _(
TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(e, stackTrace) {
return ApiFailure(
'Error on network request',
errorObject: e,
stackTrace: stackTrace,
);
},
).mapLeft((apiFailure) {
if (apiFailure.errorObject is DioException && apiFailure.errorObject.isNoConnectionError) {
/// return [RemoteResponse]
} else {
return apiFailure;
}
}),
);
from fpdart.
Unfortunately, it didn't work. Maybe looking at the entire source code for this file might help.
typedef _RemoteMarkdown = TaskEither<Failure, RemoteResponse<String>>;
abstract class DetailRemoteService {
DetailRemoteService({
Dio? dio,
HeaderCache? headerCache,
}) : _dio = dio ?? Dio(),
_headerCache = headerCache ?? GithubHeaderCache();
final Dio _dio;
final HeaderCache _headerCache;
@protected
_RemoteMarkdown getDetail(
int id,
String fullPathToMarkdownFile,
) {
return TaskEither.Do(
(_) async {
final requestUri =
await _(_uriParser(fullPathToMarkdownFile).toTaskEither());
final cachedHeader = await _(
Task(
() => _headerCache.getHeader(fullPathToMarkdownFile),
).toTaskEither(),
);
final response = await _(
TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(e, stackTrace) {
return ApiFailure(
'Error on network request',
errorObject: e,
stackTrace: stackTrace,
);
},
).mapLeft(
(failure) {
final error = failure.errorObject;
if (error is DioException && error.isNoConnectionError) {
return const RemoteResponse.noConnection(); // The return type 'RemoteResponse<dynamic>' isn't a 'Failure', as required by the closure's context.
}
return failure;
},
),
);
if (response.statusCode == 200) {
final header = GithubHeader.parse(
id,
response,
fullPathToMarkdownFile,
);
await _(Task(() => _headerCache.saveHeader(header)).toTaskEither());
final html = response.data!;
return RemoteResponse.withNewData(html);
}
return const RemoteResponse.notModified();
},
);
}
}
IOEither<Failure, Uri> _uriParser(String uri) {
return IOEither.tryCatch(
() => Uri.parse(uri),
(e, stackTrace) => UriParserFailure(
'Invalid Uri string',
errorObject: e,
stackTrace: stackTrace,
),
);
}
I have commented the error message that I am receiving.
from fpdart.
That's because _RemoteMarkdown
is defined as TaskEither<Failure, Response<String>>
, therefore the context (i.e. the .Do
constructor) expects the error type to be of type Failure
.
The error is saying that RemoteResponse
is not of type Failure
, so it is not valid as an error type. How is RemoteResponse
defined? Is it an instance of Failure
?
from fpdart.
RemoteResponse is a union type. It doesn't extend Failure and I don't want to as well in this case. In the old imperative code, I had this logic where if DioException is caught and if it's no connection error, I would return RemoteResponse.noConnection()
instead of throwing. To have a look at my old imperative code, check this out.
https://github.com/Biplab-Dutta/now-in-dart-flutter/blob/master/lib/features/detail/core/data/detail_remote_service.dart
You would want to check this repository too (imperative one) to understand what I am trying to achieve here.
https://github.com/Biplab-Dutta/now-in-dart-flutter/blob/master/lib/features/detail/dart_detail/data/dart_detail_repository.dart
from fpdart.
Got it. You are trying to recover from an error. In this case you should use orElse
:
final response = await _(
TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(e, stackTrace) {
return ApiFailure(
'Error on network request',
errorObject: e,
stackTrace: stackTrace,
);
},
).orElse(
(failure) {
final error = failure.errorObject;
if (error is DioException && error.isNoConnectionError) {
return TaskEither.right(const RemoteResponse.noConnection());
}
return TaskEither.left(failure);
},
),
);
Using orElse
you get the ApiFailure
(failure
) and you can return a right value (RemoteResponse
) or otherwise return again the Failure
.
from fpdart.
@SandroMaglione Unfortunately, it doesn't seem to work.
TaskEither<Failure, RemoteResponse<String>> getDetail(
int id,
String fullPathToMarkdownFile,
) {
return TaskEither.Do( // Here, the right is RemoteResponse<String>
(_) async {
final requestUri =
await _(_uriParser(fullPathToMarkdownFile).toTaskEither());
final cachedHeader = await _(
Task(
() => _headerCache.getHeader(fullPathToMarkdownFile),
).toTaskEither(),
);
final response = await _(
TaskEither<Failure, Response<String>>.tryCatch( // Here, the right is Response<String>
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(e, stackTrace) {
return ApiFailure(
'Error on network request',
errorObject: e,
stackTrace: stackTrace,
);
},
).orElse(
(failure) {
final error = failure.errorObject;
if (error is DioException && error.isNoConnectionError) {
return TaskEither.of(const RemoteResponse.noConnection()); // The argument type 'RemoteResponse<dynamic>' can't be assigned to the parameter type 'Response<String>'.
}
return TaskEither.left(failure);
},
),
);
if (response.statusCode == 200) {
final header = GithubHeader.parse(
id,
response,
fullPathToMarkdownFile,
);
await _(Task(() => _headerCache.saveHeader(header)).toTaskEither());
final html = response.data!;
return RemoteResponse.withNewData(html);
}
return const RemoteResponse.notModified();
},
);
}
My method has the return type of TaskEither<Failure, RemoteResponse<String>>
. Then the inner TaskEither.tryCatch
has the return type of TaskEither<Failure, Response<String>>
.
RemoteResponse<T>
is a union type (by freezed).
Response<T>
is an object from dio package.
Maybe you got confused there by similar object names. Sorry if that was the case.
from fpdart.
Inside a .Do
constructor the left and right types returned by calling _
must always be the same, returning Response<string>
won't work.
In this case you need to use flatMap
first to convert Response
to RemoteResponse
, and then call orElse
:
final response = await _(
TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(e, stackTrace) {
return ApiFailure(
'Error on network request',
errorObject: e,
stackTrace: stackTrace,
);
},
).flatMap((response) {
return TaskEither<Failure, RemoteResponse<String>>(() async {
if (response.statusCode == 200) {
final header = GithubHeader.parse(
id,
response,
fullPathToMarkdownFile,
);
await _headerCache.saveHeader(header);
final html = response.data!;
return RemoteResponse.withNewData(html);
}
return const RemoteResponse.notModified();
});
}).orElse(
(failure) {
final error = failure.errorObject;
if (error is DioException && error.isNoConnectionError) {
return TaskEither.of(const RemoteResponse.noConnection());
}
return TaskEither.left(failure);
},
),
);
from fpdart.
Thanks. Using flatMap was the right call here. I made small changes to your last suggestion and I am not getting any compile time errors.
_RemoteMarkdown getDetail(
int id,
String fullPathToMarkdownFile,
) {
return TaskEither.Do(
(_) async {
final requestUri =
await _(_uriParser(fullPathToMarkdownFile).toTaskEither());
final cachedHeader = await _(
Task(
() => _headerCache.getHeader(fullPathToMarkdownFile),
).toTaskEither(),
);
return _(
TaskEither<Failure, Response<String>>.tryCatch(
() => _dio.getUri<String>(
requestUri,
options: Options(
headers: <String, String>{
'If-None-Match': cachedHeader?.eTag ?? '',
},
),
),
(e, stackTrace) {
return ApiFailure(
'Error on network request',
errorObject: e,
stackTrace: stackTrace,
);
},
).flatMap(
(response) {
return TaskEither<Failure, RemoteResponse<String>>(
() async {
if (response.statusCode == 200) {
final header = GithubHeader.parse(
id,
response,
fullPathToMarkdownFile,
);
await _(
Task(
() => _headerCache.saveHeader(header),
).toTaskEither(),
);
final html = response.data!;
return right(RemoteResponse.withNewData(html));
}
return right(const RemoteResponse.notModified());
},
);
},
).orElse(
(failure) {
final error = failure.errorObject;
if (error is DioException && error.isNoConnectionError) {
return TaskEither.right(const RemoteResponse.noConnection());
}
return TaskEither.left(failure);
},
),
);
},
);
}
from fpdart.
Is it okay if I keep this issue opened until I am done migrating my entire project to fpdart? I shall close it once I am done with migration.
from fpdart.
Related Issues (20)
- [BUG]: unnable to create stubs any of the fpdart types HOT 7
- DISCUSSION : Extension HOT 1
- Factory const constructor(s) HOT 1
- [Question] Update 0.6.0 functions to 1.1.0 HOT 2
- Mockito can't generate stubs for functions returning Either HOT 1
- Support for TaskEither.tryCatchK HOT 1
- Code formatting HOT 2
- Anchors in menu of readme file doesn't work HOT 2
- Export fpdart package conflict with State of material. HOT 3
- Do Notation throws instance of '_OptionThrow' HOT 7
- [question] cannot use .andThen in option HOT 4
- TaskEither from predicate should accept a FutureOr. HOT 1
- How do i chain TaskEither with flatMap properly HOT 2
- Help converting error types HOT 1
- [Question] Any side effect function in TaskEither or Either? HOT 3
- Couldn't access https://www.sandromaglione.com HOT 1
- Lint roadmap HOT 1
- Confusing Documentation for foldLeft and foldRight Methods in Either Class HOT 1
- Multi dependencies using Reader
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fpdart.