Created
December 17, 2019 22:36
-
-
Save MaxwellBo/7a1a3a1d1d0a00d7a37484c2e376518c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io.circe.JsonObject | |
object BaseExError { | |
def generateErrorId(): String = UUID.randomUUID().toString.take(8) | |
def errorDataFromJsonObj(jsonObj: JsonObject): Map[String, String] = | |
jsonObj.toMap.mapValues(_.noSpaces) | |
/** | |
* We sometimes need to generate a message to show to the user given a Throwable. | |
* e.g. we make several network calls and want to report every error to the user, hiding unexpected exceptions | |
* under a generic error message. | |
* We need to ensure we're not leaking errors that shouldn't be leaked | |
*/ | |
def generateErrorMessage(e: Throwable, errorId: Option[String] = None): String = { | |
e match { | |
case err: ExceptionError => | |
s"There was an error while processing your request. Please contact customer support. Error ID: ${err.errorId}" | |
case err@(_: DisplayableExceptionError | _: UserError) => err.getMessage | |
case _: Throwable => s"There was an error while processing your request. Please contact customer support. Error ID: ${errorId.getOrElse(generateErrorId(): String)}" | |
} | |
} | |
} | |
sealed trait BaseExError extends BaseError { self: Throwable => | |
override val errorMsg: String = this.getMessage | |
// Each error that's instantiated will have an Error ID. This is used | |
// to reference a particular error without needing to let the end user | |
// see the details of the error | |
val errorId: String = BaseExError.generateErrorId() | |
/** Any extra data relevant for this error */ | |
def errorData: Map[String, String] = Map.empty | |
final def asThrowable: Throwable = self | |
} | |
/** An error which wraps an Exception. No information will be rendered to the user. | |
* If you have an internal errors which we want to track through error reporting (e.g. impossible state observerd) | |
* then you should extend this error | |
*/ | |
@SuppressWarnings(Array("org.wartremover.warts.Null")) | |
abstract class ExceptionError(errorMsg: String, cause: Option[Throwable]) extends Exception(errorMsg, cause.orNull) with BaseExError | |
/** | |
* An Error with a message that is "user-friendly" (can be shown to the user). | |
* Extend this error if you want to wrap an exception which can have a user-friendly message | |
*/ | |
@SuppressWarnings(Array("org.wartremover.warts.Null")) | |
abstract class DisplayableExceptionError(errorMsg: String, cause: Option[Throwable]) extends Exception(errorMsg, cause.orNull) with BaseExError | |
/** | |
* An Exception which the user can fix. This Exception is not reported when caught because it's a user error. | |
* We also enforce that a subclass of UserError should have a Http code associated with it. | |
* If you have an error deep down the stack which is caused by user error (and can provide infomation for them to fix it), | |
* then you can extend this class and throw it. | |
*/ | |
@SuppressWarnings(Array("org.wartremover.warts.Null")) | |
abstract class UserError(errorMsg: String, cause: Option[Throwable] = None) extends Exception(errorMsg, cause.orNull) with BaseExError with HttpError |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment