Home > Net >  More than 1 valid return types | What is the correct way | Flutter
More than 1 valid return types | What is the correct way | Flutter

Time:07-27

Usually while writing my applications in Flutter, I like to mention the return types everywhere. This ensures that I do not return the wrong objects and also checks my code while I'm still writing it.

Let us say that I'm writing a method inside the ApiProvider which on a successful event returns a User object.

i.e.,

Future<UserModel> checkAuth (String username, String password) async {
  final result = client.get (.............);
  final UserModel model = UserModel.fromJson(result);
  return model;
}

Now everything is fine until I introduce try-catch blocks for the error handling. This would modify my code as below :

Future<UserModel> checkAuth (String username, String password) async {
 try {
  final result = client.get (.............);
  final UserModel model = UserModel.fromJson(result);
  return model;
 } on Exception catch(e) {
  return ErrorModel(e.statusCode, e.message);
 }
}

Now, as you can see, in case of an error I will have to return an error model or maybe just the string (e.message). However, my function could return only the instances of UserModel. I do NOT want to make the return type dynamic as It makes my code very loosely coupled.

How can I overcome this problem and is there a better way to do this ? Usually after getting the api response or an error response, I would populate the results inside a stream so that I could show them to the user on the UI. I make use of bloc architecture.

Any help would be appreciated. Thanks in advance!

CodePudding user response:

Use Exceptions:

class ApiProviderException implements Exception {
  final int? statusCode;
  final String? message;

  ApiProviderException(this.statusCode, this.message);

  @override
  String toString() {
    return '$statusCode - $message';
  }
}

...

Future<UserModel> checkAuth(String username, String password) async {
  try {
    final result = client.get (.............);
    final UserModel model = UserModel.fromJson(result);
    return model;
  } on Exception catch (e) {
    throw ApiProviderException(e.statusCode, e.message);
  }
}

To use it:

try {
  final model = await checkAuth(username, password);
  // some code
} on ApiProviderException catch (e) {
  // some code
}

CodePudding user response:

You can use either_dart package, it handles the "error" L and "success" R state of your function return, without the need of explicitly declaring the base class.

Using your function as example:

import 'package:either_dart/either.dart';

Future<Either<ErrorModel, UserModel>> checkAuth(String username, String password) async {
 try {
  final result = client.get (.............);
  final UserModel model = UserModel.fromJson(result);
  return Right(model);
 } on Exception catch(e) {
  return Left(ErrorModel(e.statusCode, e.message));
 }
}

And to use it:

final Either<ErrorModel, UserModel> result = await checkAuth(...);

if (result.isLeft) {
  // error...
  final ErrorModel user = result.left;
} else if (result.isRight) {
  // sucess...
  final UserModel user = result.right;
}

You can handle it's result in a kind of state manager class like BLoC, Mobx Store, Provider and send to the UI the correct text to be rendered. So:

// services/my_service_class.dart
class MyService {
  Either<L, R> callSomeApi() { }
}

// store/my_ui_manager_class.dart
class MyUIStateManagerClass extends BLoC { 
  final MyService service = MyService();

  Future<void> callSomething() async {
    final result = await service.callSomeApi();

    if (result.isLeft) {
      // error...
      final ErrorModel user = result.left;
    } else if (result.isRight) {
      // sucess...
      final UserModel user = result.right;
    }
  }
}

// widgets/my_ui_class.dart
class MyWidget {
  MyUIStateManagerClass stateManager;

  void initState() {
    super.initState();
    stateManager = MyUIStateManagerClass();

    stateManager.callSomething();
  }

  Widget build(BuildContext context) {
    return ...
  }
}
  • Related