operation_result 1.1.0 copy "operation_result: ^1.1.0" to clipboard
operation_result: ^1.1.0 copied to clipboard

The Result that allows to specify a list of expected errors.

Build Status codecov

Why another implementation of the Result pattern? #

This package arises from the need to specify expected errors from API calls and handle them in a more convenient way. The original workaround was to use comments on the function signature:

// Throws Unauthorized, InvalidFormField
Future<Profile> editProfile(EditProfile editProfile) async

But comments are not checked either by the compiler or on runtime. So they become outdated and not reliable.

With the operation_result package errors can be specified in the next way:

AsyncResult<Profile, Errors2<Unauthorized, InvalidFormField>> editProfile(
    EditProfile editProfile) async

Usage #

The example shows how operation_result can be used to handle API errors.


AsyncResult<Response, Errors2<Unauthorized, ValidationError>> httpPost(String path,
    Object data) async {
  final response = await client.post(path, data);
  
  if (response.statusCode == 200) {
    return success2(response);
  }

  if (response.statusCode == 401) {
    return failure2(Unauthorized());
  }

  if (response.statusCode == 400) {
    final List<dynamic> errors = response.data['errors'];
    // Result can contains multiple errors.
    return failures2(errors.map((e) => ValidationError.fromMap(e)));
  }

  throw Exception('Unexpected status code: ${response.statusCode}');
}

AsyncResult<AuthToken, Errors2<InvalidCredentials, EmailNotConfirmed>> login(String login,
    String password) async {
  final response = await httpPost('/auth/login', {'login': login, 'password': password});
  return response.forward2(
      success: (r) => AuthToken.parse(r.data),
      failure: (e) =>
      switch (e) {
        (ValidationError e) when e.code == 'email-not-confirmed' => EmailNotConfirmed(),
        (Unauthorized _) => InvalidCredentials(),
        _ => e
      });
}

AsyncResult<Profile, Errors2<Unauthorized, InvalidFormField>> editProfile(
    EditProfile editProfile) async {
  final response = await httpPost('/profile/edit', editProfile.toMap());
  return response.forward2(
    success: (response) => Profile.fromMap(response.data),
    failure: (e) =>
    switch (e) {
      (Unauthorized e) => e,
      (ValidationError e) when e.code == 'incorrect-value' =>
          InvalidFormField(fieldName: e.incorrectValue, message: e.message),
      _ => e
    },
  );
}

// Login screen
void onLoginPressed() async {
  final loginResult = await login('login', 'password');
  if (loginResult.hasError<InvalidCredentials>()) {
    form.setFailure(['Password or email are incorrect']);
    return;
  }

  if (loginResult.hasError<EmailNotConfirmed>()) {
    router.redirectToConfirmationPage();
    return;
  }

  authStorage.storeToken(loginResult.value);
  router.goToHomePage();
}


// Profile screen
void onEditProfilePressed() async {
  final editResult = await editProfile(editProfile);
  if (editResult.hasError<Unauthorized>()) {
    router.redirectToLoginPage();
    return;
  }

  final fieldErrors = editResult.getErrors<InvalidFormField>();
  if (fieldErrors.isNotEmpty) {
    for (final fieldError in fieldErrors) {
      form.setError(fieldError.fieldName, fieldError.message);
    }
    return;
  }

  if (editResult.failed) {
    form.setFailure(['Unhandled errors: ${editResult.errors}']);
    return;
  }

  form.setSuccess();
}

What is the package not meant to be used for? #

This package doesn't have a goal to replace exceptions as a generic error-handling mechanism in Dart. It is tailored for the specific use case of "expected" errors, where the usage of exceptions is not convenient.

Limitations and drawbacks #

  • Dart generics do not support variadic parameters, so you need to use specific types like Errors2, Errors3 etc. And corresponding function like forward2, forward3, success2, failure2 etc.

  • Most of checks are done on runtime.

0
likes
160
points
249
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

The Result that allows to specify a list of expected errors.

Repository (GitHub)
View/report issues

License

MIT (license)

More

Packages that depend on operation_result