`Failure` is a wrapper object for `Exception`, allowing you to `catch` exceptions and turn them into and object that is easier to handle. `Failure` works by holding a list of objects called `properties`. This list can contain anything from the exception itself to stack traces or custom error messages. This list of properties allows `Failure` objects to be compared using `Equatable` so we can adapt our behavior on a runtime basis.
Each type of `Failure` has a specific use case, and should be used with `Result<T>`, so an example will be provided at the bottom of the page.
# What is `Result<T>`?
`Result<T>` is a wrapper object for any type of response we expect from an asynchronous data source. Since the data source is asynchronous, there is a possibility we could time out or throw an exception, and since we don't want the app to crash we need to catch that somehow. `Result<T>` solves this by wrapping responses and identifying itself as `T data` or `Failure failure `. This prevents runtime exceptions when running asynchronous queries and guarantees that we always get a response back no matter what happens.
# How does `Result<T>` work?
`Result<T>` works by having two constructors: `Result.data({required T data})` and `Result.failure({required Failure failure})`.
-`Result.data({required T data})` tells `Result<T>` that you are an instance of `T data` and that whatever you contain is a valid response.
-`Result.failure({required Failure failure})` tells `Result<T>` that you are an instance of `Failure` and that whatever you contain is an invalid response and should be handled.
These checks allow us to create dud data on the fly when a query fails.
# How does this all come together?
Using `Result<T>` and `Failure` together can best be seen in the `LoginRepositoryHTTP` when trying to log a player in.
final response = await loginWithCredentialsDatasource.loginWithCredentials(request: request);
return Result.data(data: response);
} catch (exception, stackTrace) {
return Result.failure(
failure: HTTPFailure(
message: '$exception : $stackTrace',
),
);
}
# What is `Result`?
`Result` is a wrapper for `Future` responses. Used to prevent crashes caused by runtime exceptions. Result can either be an instance of `ResultData` or `ResultFailure`. If an exception is thrown, then `Result` is an instance of `ResultFailure`. If data is received, then `Result` is an instance of `ResultData`.
```dart
@freezed
classResult<T>with_$Result<T>{
///
/// Creates an instance of `ResultData` from data `T`.
///
factoryResult.data({
requiredTdata,
})=ResultData;
///
/// Creates and instance of `ResultFailure` from failure `Failure`.
///
factoryResult.failure({
requiredFailurefailure,
})=ResultFailure;
}
```
First, we query the login server, but since we don't know if the server is actually up, we could throw an exception. So by wrapping the `await loginWithCredentialsDatasource.loginWithCredentials` function in a try catch we can break the logic into two parts: we succeed or we fail. We can then create a `Result<T>` from this logic stating that if we get a response, we can make a `Result.data`, and if we fail, we can make a `Result.error`.
This information can then be unwrapped using a `when` check, as shown in the following example:
**LoginController**
```
/// Query the login repository
final response = await _repository.loginWithCredentials(
request: LoginWithCredentialsRequest(
username: username,
password: password,
),
);
/// When we get a response, use it to set the local response.
The underlying boilerplate code for `Result` is autogenerated by a package called `Freezed`, so the actual `ResultData` and `ResultFailure` types are not exposed to the user. However, both types will present as the generic type `Result` in code and can be checked using a `.when` statement as seen in the example below.
```dart
///
/// This portion of code is snagged from the `LoginController` and best
/// represents how to use `Result`.
///
/// Assume `LoginWithCredentialsResponse` is an object that holds an
/// int named `playerID`. Assume `response` is an instance of
First, we query the login repository, which was shown above. This provides us with a response, however, we don't know if this response is valid or not, so we need to check.
This is where we use the `when` check, which breaks our response into two parts: what do we do when we get data vs when we get a failure? When we get a failure we can create a dud response to make it seem like we actually got one.
# Why do we use `Result<T>` and `Failure`?
These two components used together allow us to handle runtime exceptions and prevent the UI from crashing when something goes wrong. It also allows us to account for circumstances where the servers are down or something behaves incorrectly.
# What is `Failure`?
`Failure` is a wrapper for `Exception` objects, allowing them to be translated to useable objects in code. Our template for `Failure` has a list of objects known as properties, which can hold anything from the exception itself to a string message or a stack trace.