From 3e700be0b7df8022627b1f46890f3e3dad3fa54b Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Wed, 12 Jul 2017 22:26:07 -0700 Subject: Handle errors by failing futures in REST services --- src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala') diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala index 4bf90d1..fc8e474 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala @@ -28,3 +28,11 @@ object DomainError { Unsafe(Utils.getClassSimpleName(x.getClass)) } } + +/** Subclasses of this exception correspond to subclasses of DomainError. They + * are used in REST service implementations to fail futures rather than + * returning successful futures, completed with corresponding DomainErrors. */ +class DomainException(message: String) extends RuntimeException(message) +class NotFoundException(message: String) extends DomainException(message) // 404 +class AuthenticationException(message: String) extends DomainException(message) // 401 +class AuthorizationException(message: String) extends DomainException(message) // 403 -- cgit v1.2.3 From 99ebbb98068324c2c26dd59484acbe9a8b62ae59 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 18 Jul 2017 17:30:52 -0700 Subject: Fixes to error message handling --- .../xyz/driver/pdsuicommon/error/DomainError.scala | 11 +++++++---- .../driver/pdsuicommon/error/ErrorsResponse.scala | 20 +++++++------------- .../pdsuidomain/services/rest/RestHelper.scala | 8 ++++---- 3 files changed, 18 insertions(+), 21 deletions(-) (limited to 'src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala') diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala index fc8e474..c761414 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala @@ -32,7 +32,10 @@ object DomainError { /** Subclasses of this exception correspond to subclasses of DomainError. They * are used in REST service implementations to fail futures rather than * returning successful futures, completed with corresponding DomainErrors. */ -class DomainException(message: String) extends RuntimeException(message) -class NotFoundException(message: String) extends DomainException(message) // 404 -class AuthenticationException(message: String) extends DomainException(message) // 401 -class AuthorizationException(message: String) extends DomainException(message) // 403 +// scalastyle:off null +@SuppressWarnings(Array("org.wartremover.warts.Null")) +class DomainException(message: String, cause: Throwable = null) extends RuntimeException(message, cause) +class NotFoundException(message: String) extends DomainException(message) // 404 +class AuthenticationException(message: String) extends DomainException(message) // 401 +class AuthorizationException(message: String) extends DomainException(message) // 403 +// scalastyle:on null diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala index 6ceadb2..3761cc5 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala @@ -5,15 +5,12 @@ import ErrorCode.{ErrorCode, Unspecified} import ErrorsResponse.ResponseError import xyz.driver.pdsuicommon.auth.{AnonymousRequestContext, RequestId} import xyz.driver.pdsuicommon.utils.Utils -import play.api.http.Writeable import play.api.libs.functional.syntax._ import play.api.libs.json._ -import play.api.mvc.{Result, Results} +import play.api.mvc.Results import xyz.driver.pdsuicommon.validation.JsonValidationErrors -class ErrorsResponse(val errors: Seq[ResponseError], private val httpStatus: Results#Status, val requestId: RequestId) { - def toResult(implicit writeable: Writeable[ErrorsResponse]): Result = httpStatus(this) -} +final case class ErrorsResponse(errors: Seq[ResponseError], requestId: RequestId) object ErrorsResponse { @@ -36,12 +33,10 @@ object ErrorsResponse { } - implicit val writes: Writes[ErrorsResponse] = Writes { errorsResponse => - Json.obj( - "errors" -> Json.toJson(errorsResponse.errors), - "requestId" -> Json.toJson(errorsResponse.requestId.value) - ) - } + implicit val errorsResponseJsonFormat: Format[ErrorsResponse] = ( + (JsPath \ "errors").format[Seq[ResponseError]] and + (JsPath \ "requestId").format[String] + )((errs, req) => ErrorsResponse.apply(errs, RequestId(req)), res => (res.errors, res.requestId.value)) // deprecated, will be removed in REP-436 def fromString(message: String, httpStatus: Results#Status)( @@ -53,7 +48,6 @@ object ErrorsResponse { message = message, code = Unspecified )), - httpStatus = httpStatus, requestId = context.requestId ) } @@ -83,7 +77,7 @@ object ErrorsResponse { ) } - new ErrorsResponse(errors, Results.BadRequest, context.requestId) + new ErrorsResponse(errors, context.requestId) } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala index 5284ff1..bc886ba 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala @@ -92,10 +92,10 @@ trait RestHelper { def extractErrorMessage(response: HttpResponse): Future[String] = { import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ Unmarshal(response.entity) - .to[ErrorsResponse.ResponseError] + .to[ErrorsResponse] .transform( - _.message, - ex => new DomainException(ex.getMessage) + response => response.errors.map(_.message).mkString(", "), + ex => new DomainException("Response has invalid format", ex) ) } @@ -108,7 +108,7 @@ trait RestHelper { case StatusCodes.Forbidden => new AuthorizationException(message) case StatusCodes.NotFound => new NotFoundException(message) case other => - new DomainException(s"Unhandled domain error for HTTP status ${other.value}. Message ${message}") + new DomainException(s"Unhandled domain error for HTTP status ${other.value}. ${message}") }) } } -- cgit v1.2.3