From e7d849b55f975f1c119cebb22f95d9de903ae3c3 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Thu, 19 Oct 2017 13:49:22 -0700 Subject: Stop catching throwable, remove PHI filtering, move status code logic to exception handler --- .../scala/xyz/driver/core/rest/DriverRoute.scala | 54 +++++++++++++++------- .../driver/core/rest/errors/serviceException.scala | 40 ++++------------ 2 files changed, 46 insertions(+), 48 deletions(-) (limited to 'src/main/scala') diff --git a/src/main/scala/xyz/driver/core/rest/DriverRoute.scala b/src/main/scala/xyz/driver/core/rest/DriverRoute.scala index f3260d0..be9c783 100644 --- a/src/main/scala/xyz/driver/core/rest/DriverRoute.scala +++ b/src/main/scala/xyz/driver/core/rest/DriverRoute.scala @@ -3,14 +3,14 @@ package xyz.driver.core.rest import java.sql.SQLException import akka.http.scaladsl.model._ -import akka.http.scaladsl.model.StatusCodes.{BadRequest, Conflict, InternalServerError} +import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.model.headers._ import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.{ExceptionHandler, RequestContext, Route} import com.typesafe.scalalogging.Logger import org.slf4j.MDC import xyz.driver.core.rest -import xyz.driver.core.rest.errors.ServiceException +import xyz.driver.core.rest.errors._ import scala.compat.Platform.ConcurrentModificationException @@ -29,38 +29,58 @@ trait DriverRoute { * @return Exception handling route for exception type */ protected def exceptionHandler: PartialFunction[Throwable, Route] = { - case api: ServiceException if api.isPatientSensitive => - ctx => - log.info("PHI Sensitive error") - errorResponse(ctx, InternalServerError, "Server error", api)(ctx) - - case api: ServiceException => - ctx => - log.info("API Error") - errorResponse(ctx, api.statusCode, api.message, api)(ctx) + case serviceException: ServiceException => + serviceExceptionHandler(serviceException) case is: IllegalStateException => ctx => log.warn(s"Request is not allowed to ${ctx.request.method} ${ctx.request.uri}", is) - errorResponse(ctx, BadRequest, message = is.getMessage, is)(ctx) + errorResponse(ctx, StatusCodes.BadRequest, message = is.getMessage, is)(ctx) case cm: ConcurrentModificationException => ctx => log.warn(s"Concurrent modification of the resource ${ctx.request.method} ${ctx.request.uri}", cm) - errorResponse(ctx, Conflict, "Resource was changed concurrently, try requesting a newer version", cm)(ctx) + errorResponse(ctx, + StatusCodes.Conflict, + "Resource was changed concurrently, try requesting a newer version", + cm)(ctx) case se: SQLException => ctx => log.warn(s"Database exception for the resource ${ctx.request.method} ${ctx.request.uri}", se) - errorResponse(ctx, InternalServerError, "Data access error", se)(ctx) + errorResponse(ctx, StatusCodes.InternalServerError, "Data access error", se)(ctx) - case t: Throwable => + case t: Exception => ctx => log.warn(s"Request to ${ctx.request.method} ${ctx.request.uri} could not be handled normally", t) - errorResponse(ctx, InternalServerError, t.getMessage, t)(ctx) + errorResponse(ctx, StatusCodes.InternalServerError, t.getMessage, t)(ctx) + } + + protected def serviceExceptionHandler(serviceException: ServiceException): Route = { + val statusCode = serviceException match { + case e: InvalidInputException => + log.info("Invalid client input error", e) + StatusCodes.BadRequest + case e: InvalidActionException => + log.info("Invalid client action error", e) + StatusCodes.Forbidden + case e: ResourceNotFoundException => + log.info("Resource not found error", e) + StatusCodes.NotFound + case e: ExternalServiceTimeoutException => + log.error("Service timeout error", e) + StatusCodes.GatewayTimeout + case e: DatabaseException => + log.error("Database error", e) + StatusCodes.InternalServerError + } + + { (ctx: RequestContext) => + errorResponse(ctx, statusCode, serviceException.message, serviceException)(ctx) + } } - protected def errorResponse[T <: Throwable](ctx: RequestContext, + protected def errorResponse[T <: Exception](ctx: RequestContext, statusCode: StatusCode, message: String, exception: T): Route = { diff --git a/src/main/scala/xyz/driver/core/rest/errors/serviceException.scala b/src/main/scala/xyz/driver/core/rest/errors/serviceException.scala index 94f9734..7aa70bf 100644 --- a/src/main/scala/xyz/driver/core/rest/errors/serviceException.scala +++ b/src/main/scala/xyz/driver/core/rest/errors/serviceException.scala @@ -1,41 +1,19 @@ package xyz.driver.core.rest.errors -import akka.http.scaladsl.model.{StatusCode, StatusCodes} - abstract class ServiceException extends Exception { - def isPatientSensitive: Boolean = false - - def statusCode: StatusCode def message: String } -final case class InvalidInputException(override val message: String = "Invalid input", - override val isPatientSensitive: Boolean = false) - extends ServiceException { - override def statusCode: StatusCode = StatusCodes.BadRequest -} +final case class InvalidInputException(override val message: String = "Invalid input") extends ServiceException -final case class InvalidActionException(override val message: String = "This action is not allowed", - override val isPatientSensitive: Boolean = false) - extends ServiceException { - override def statusCode: StatusCode = StatusCodes.Forbidden -} +final case class InvalidActionException(override val message: String = "This action is not allowed") + extends ServiceException -final case class ResourceNotFoundException(override val message: String = "Resource not found", - override val isPatientSensitive: Boolean = false) - extends ServiceException { - override def statusCode: StatusCode = StatusCodes.NotFound -} +final case class ResourceNotFoundException(override val message: String = "Resource not found") + extends ServiceException -final case class ExternalServiceTimeoutException(override val message: String = - "Another service took too long to respond", - override val isPatientSensitive: Boolean = false) - extends ServiceException { - override def statusCode: StatusCode = StatusCodes.GatewayTimeout -} +final case class ExternalServiceTimeoutException( + override val message: String = "Another service took too long to respond") + extends ServiceException -final case class DatabaseException(override val message: String = "Database access error", - override val isPatientSensitive: Boolean = false) - extends ServiceException { - override def statusCode: StatusCode = StatusCodes.InternalServerError -} +final case class DatabaseException(override val message: String = "Database access error") extends ServiceException -- cgit v1.2.3