diff options
author | vlad <vlad@driver.xyz> | 2017-07-20 10:37:08 -0700 |
---|---|---|
committer | vlad <vlad@driver.xyz> | 2017-07-20 10:37:08 -0700 |
commit | 5279d01cedb35a759347f194c0e8adb21d19e88e (patch) | |
tree | e340bb2eaba41d917bbca8c5e42b0b76bd164e37 /src/main/scala/xyz/driver/pdsuicommon/error | |
parent | d9c3283c307105e03253c621b9b25a6308ac3b94 (diff) | |
parent | 7f7bd651122754a3df47894b64ddb0456561bbe7 (diff) | |
download | rest-query-5279d01cedb35a759347f194c0e8adb21d19e88e.tar.gz rest-query-5279d01cedb35a759347f194c0e8adb21d19e88e.tar.bz2 rest-query-5279d01cedb35a759347f194c0e8adb21d19e88e.zip |
Merge remote-tracking branch 'origin/master'
# Conflicts:
# build.sbt
# src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala
# src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
# src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuicommon/error')
3 files changed, 111 insertions, 0 deletions
diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala index 4bf90d1..c761414 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala @@ -28,3 +28,14 @@ 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. */ +// 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/ErrorCode.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala new file mode 100644 index 0000000..5574c01 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala @@ -0,0 +1,17 @@ +package xyz.driver.pdsuicommon.error + +import play.api.libs.functional.syntax._ +import play.api.libs.json.{Format, Reads, Writes} + +@SuppressWarnings(Array("org.wartremover.warts.Enumeration")) +object ErrorCode extends Enumeration { + + type ErrorCode = Value + val Unspecified = Value(1) + + private val fromJsonReads: Reads[ErrorCode] = Reads.of[Int].map(ErrorCode.apply) + private val toJsonWrites: Writes[ErrorCode] = Writes.of[Int].contramap(_.id) + + implicit val jsonFormat: Format[ErrorCode] = Format(fromJsonReads, toJsonWrites) + +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala new file mode 100644 index 0000000..3761cc5 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala @@ -0,0 +1,83 @@ +package xyz.driver.pdsuicommon.error + +import xyz.driver.pdsuicommon.json.Serialization.seqJsonFormat +import ErrorCode.{ErrorCode, Unspecified} +import ErrorsResponse.ResponseError +import xyz.driver.pdsuicommon.auth.{AnonymousRequestContext, RequestId} +import xyz.driver.pdsuicommon.utils.Utils +import play.api.libs.functional.syntax._ +import play.api.libs.json._ +import play.api.mvc.Results +import xyz.driver.pdsuicommon.validation.JsonValidationErrors + +final case class ErrorsResponse(errors: Seq[ResponseError], requestId: RequestId) + +object ErrorsResponse { + + /** + * @param data Any data that can be associated with particular error.Ex.: error field name + * @param message Error message + * @param code Unique error code + * + * @see https://driverinc.atlassian.net/wiki/display/RA/REST+API+Specification#RESTAPISpecification-HTTPStatuscodes + */ + final case class ResponseError(data: Option[String], message: String, code: ErrorCode) + + object ResponseError { + + implicit val responseErrorJsonFormat: Format[ResponseError] = ( + (JsPath \ "data").formatNullable[String] and + (JsPath \ "message").format[String] and + (JsPath \ "code").format[ErrorCode] + )(ResponseError.apply, unlift(ResponseError.unapply)) + + } + + 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)( + implicit context: AnonymousRequestContext): ErrorsResponse = { + new ErrorsResponse( + errors = Seq( + ResponseError( + data = None, + message = message, + code = Unspecified + )), + requestId = context.requestId + ) + } + + // scalastyle:off null + def fromExceptionMessage(e: Throwable, httpStatus: Results#Status = Results.InternalServerError)( + implicit context: AnonymousRequestContext): ErrorsResponse = { + val message = if (e.getMessage == null || e.getMessage.isEmpty) { + Utils.getClassSimpleName(e.getClass) + } else { + e.getMessage + } + + fromString(message, httpStatus) + } + // scalastyle:on null + + // deprecated, will be removed in REP-436 + def fromJsonValidationErrors(validationErrors: JsonValidationErrors)( + implicit context: AnonymousRequestContext): ErrorsResponse = { + val errors = validationErrors.map { + case (path, xs) => + ResponseError( + data = Some(path.toString()), + message = xs.map(_.message).mkString("\n"), + code = Unspecified + ) + } + + new ErrorsResponse(errors, context.requestId) + } + +} |