formatErrorMessage method

ApiError formatErrorMessage(
  1. dynamic error,
  2. String defaultErrorMessage
)

Normalises an arbitrary throwable into an ApiError.

Matching is done with is checks rather than on runtimeType.toString(): the latter silently stops matching under release obfuscation (--obfuscate) and never matches subclasses.

An error that is already an ApiError is returned unchanged, so a custom error thrown by an interceptor keeps its own message and code.

Implementation

ApiError formatErrorMessage(dynamic error, String defaultErrorMessage) {
  if (error is ApiError) return error;

  final String message;
  final int code;

  if (error is SocketException ||
      error is HttpException ||
      error is RedirectException ||
      error is WebSocketException) {
    message = 'Please check your internet connection and try again';
    code = ErrorCodes.network;
  } else if (error is HandshakeException) {
    message = 'Could not establish secure connection with the server';
    code = ErrorCodes.handshake;
  } else if (error is CertificateException) {
    message = 'An error occurred, could not verify server certificate';
    code = ErrorCodes.certificate;
  } else if (error is FileSystemException) {
    message = 'A filesystem exception has occurred';
    code = ErrorCodes.fileSystem;
  } else if (error is TlsException) {
    message = 'SSL error occurred ${error.message}';
    code = ErrorCodes.tls;
  } else if (error is ClientException) {
    message = 'Client exception occurred, could not connect to the server';
    code = ErrorCodes.client;
  } else if (error is TimeoutException) {
    message = 'Connection Timed out please check your internet connection';
    code = ErrorCodes.timeout;
  } else if (error is FormatException) {
    message = 'Improperly formatted value';
    code = ErrorCodes.format;
  } else if (error is MissingPluginException) {
    message = 'Plugin not found';
    code = ErrorCodes.missingPlugin;
  } else if (error is NetworkImageLoadException) {
    message = 'Could not load the image';
    code = ErrorCodes.imageLoad;
  } else if (error.toString().contains('SocketException')) {
    // Some platforms wrap the socket failure in an opaque type.
    message = 'Please check your internet connection and try again';
    code = ErrorCodes.network;
  } else {
    ApiConfig().log('unmapped error ${error.runtimeType}: $error');
    message = defaultErrorMessage.isNotEmpty
        ? defaultErrorMessage
        : ApiConfig().defaultErrorMessage;
    code = ErrorCodes.unknown;
  }

  return ApiError(message, code);
}