fresult 1.1.2 copy "fresult: ^1.1.2" to clipboard
fresult: ^1.1.2 copied to clipboard

A Dart package providing Result types for better error handling with freezed.

fresult #

License: MIT

A Dart package providing Result types for better error handling using Freezed. This package helps you write more robust and functional code by avoiding exceptions and providing type-safe error handling.

Features #

  • 🎯 Type-safe error handling - No more exceptions for expected errors
  • 🔒 Immutable Result types - Built with Freezed for immutability
  • 🔄 Functional programming patterns - Map, flatMap, and chain operations
  • Async/await support - Work seamlessly with Futures
  • 🛡️ Null safety - Full null safety support
  • 📚 Comprehensive documentation - Well-documented API with examples
  • 100% test coverage - Thoroughly tested

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  fresult: ^1.1.1

dev_dependencies:
  build_runner: ^2.7.1
  freezed: ^3.1.0

Then run:

dart pub get
dart run build_runner build

Quick Start #

import 'package:fresult/fresult.dart';

void main() {
  // Create a successful result
  final success = Result<String, String>.success('Hello World');
  
  // Create a failed result
  final failure = Result<String, String>.failure('Something went wrong');
  
  // Pattern matching with when
  success.when(
    success: (value) => print('Success: $value'),
    failure: (error) => print('Error: $error'),
  );
  
  // Check if result is success or failure
  if (success.isSuccess) {
    print('Value: ${success.valueOrNull}');
  }
  
  // Transform values
  final doubled = Result<int, String>.success(5)
      .map((value) => value * 2);
  
  // Chain operations
  final result = Result<int, String>.success(5)
      .flatMap((value) => value > 0 
          ? Result.success('Positive: $value')
          : Result.failure('Not positive'));
}

API Reference #

Result<T, E> #

A sealed class representing either a success with a value of type T or a failure with an error of type E.

Constructors

  • Result.success(T value) - Creates a successful result
  • Result.failure(E error) - Creates a failed result

Properties

  • bool isSuccess - Returns true if this result is a success
  • bool isFailure - Returns true if this result is a failure
  • T? valueOrNull - Returns the value if success, otherwise null
  • E? errorOrNull - Returns the error if failure, otherwise null

Methods

Pattern Matching
result.when(
  success: (value) => 'Success: $value',
  failure: (error) => 'Error: $error',
);
Value Extraction
// Get value with default
final value = result.valueOr('Default');

// Get value with computed default
final value = result.valueOrElse(() => 'Computed');

// Get value or throw error
final value = result.valueOrThrow;
Transformations
// Map success value
final mapped = result.map((value) => value.toString());

// Map error
final mapped = result.mapError((error) => 'Mapped: $error');

// Map both
final mapped = result.mapBoth(
  successMapper: (value) => 'Success: $value',
  failureMapper: (error) => 'Error: $error',
);

// Chain operations
final chained = result.flatMap((value) => 
    Result.success(value * 2));

Extensions #

ResultExtensions

// Execute side effects
result.onSuccess((value) => print('Success: $value'));
result.onFailure((error) => print('Error: $error'));

NullableToResult

// Convert nullable to Result
final result = nullableValue.toResult('Custom error message');

FutureResultExtensions

// Work with Future Results
final futureResult = Future.value(Result.success(5));

// Map async results
final mapped = await futureResult.map((value) => value * 2);

// Chain async operations
final chained = await futureResult.flatMap((value) => 
    Future.value(Result.success(value.toString())));

Examples #

Basic Usage #

import 'package:fresult/fresult.dart';

void main() {
  // Creating Results
  final success = Result<String, String>.success('Hello World');
  final failure = Result<String, String>.failure('Error occurred');
  
  // Pattern matching
  success.when(
    success: (value) => print('Success: $value'),
    failure: (error) => print('Error: $error'),
  );
  
  // Using extensions
  success.onSuccess((value) => print('Got value: $value'));
  failure.onFailure((error) => print('Got error: $error'));
}

API Error Handling #

sealed class ApiError {
  const ApiError();
}

class NetworkError extends ApiError {
  final String message;
  const NetworkError(this.message);
}

class ValidationError extends ApiError {
  final String field;
  final String message;
  const ValidationError(this.field, this.message);
}

class UserService {
  Future<Result<User, ApiError>> getUser(String id) async {
    if (id.isEmpty) {
      return Result.failure(ValidationError('id', 'ID cannot be empty'));
    }
    
    try {
      final user = await apiClient.getUser(id);
      return Result.success(user);
    } catch (e) {
      return Result.failure(NetworkError(e.toString()));
    }
  }
}

Async Operations #

Future<Result<String, String>> fetchData() async {
  await Future.delayed(Duration(seconds: 1));
  return Result.success('Data fetched');
}

void main() async {
  final result = await fetchData()
      .map((data) => 'Processed: $data')
      .flatMap((processed) => 
          Future.value(Result.success('Final: $processed')));
  
  result.when(
    success: (value) => print('Final result: $value'),
    failure: (error) => print('Error: $error'),
  );
}

Running Examples #

The package includes comprehensive example applications:

# Basic usage and transformations
dart run example/basic_usage.dart

# Real-world API example with error handling
dart run example/api_example.dart

Example 1: Basic Usage (example/basic_usage.dart) #

Demonstrates fundamental Result operations:

  • Creating success and failure results
  • Pattern matching with when
  • Using extensions for side effects
  • Value extraction with defaults
  • Transformations and chaining
  • Working with nullable values
  • Error handling patterns

Example 2: API Example (example/api_example.dart) #

A comprehensive real-world example showing:

  • Custom error types (NetworkError, ValidationError, etc.)
  • User service with CRUD operations
  • Complex error handling scenarios
  • Chaining async operations
  • Error transformation to user-friendly messages
  • Side effects with extensions

Development Workflow #

Local Testing #

Use the provided test script to run all checks locally:

./scripts/test.sh

This script will:

  • Install dependencies
  • Generate Freezed code
  • Check formatting
  • Run static analysis
  • Run all tests

GitHub Actions #

The repository includes automated workflows:

1. CI Workflow (.github/workflows/ci.yml)

  • Runs on every push and pull request
  • Executes tests, formatting checks, and static analysis
  • Generates test coverage reports

2. Test and Auto-PR Workflow (.github/workflows/test-and-pr.yml)

  • Triggers on pushes to develop branch
  • Runs result_test.dart and result_extensions_test.dart
  • Automatically creates a pull request to main when tests pass
  • Auto-merges the PR after approval

3. Publish Workflow (.github/workflows/publish.yml)

  • Triggers on GitHub releases
  • Publishes the package to pub.dev automatically

Branch Strategy #

  • develop - Development branch for new features
  • main - Production-ready code
  • Feature branches - Created from develop

Workflow Steps #

  1. Develop: Work on features in the develop branch
  2. Test: Push to develop triggers automatic testing
  3. Auto-PR: If tests pass, a PR to main is created automatically
  4. Review: Review and approve the auto-created PR
  5. Merge: PR is automatically merged to main
  6. Release: Create a GitHub release to publish to pub.dev

Testing #

Run the test suite:

dart test

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog #

See CHANGELOG.md for a list of changes and version history.

  • freezed - Code generation for immutable classes
  • dartz - Functional programming in Dart
  • fpdart - Functional programming in Dart

Support #

If you find this package helpful, please consider giving it a ⭐ on github and 👍 on pub.dev!

1
likes
160
points
290
downloads

Publisher

unverified uploader

Weekly Downloads

A Dart package providing Result types for better error handling with freezed.

Repository (GitHub)
View/report issues

Topics

#result #error-handling #freezed #functional-programming

Documentation

API reference

License

MIT (license)

Dependencies

freezed_annotation

More

Packages that depend on fresult