app/lib/Response.scala (53 lines of code) (raw):

package lib import play.api.{Logger, Logging} import play.api.libs.json._ import play.api.mvc.{Result, Results} case class ApiError(message: String, friendlyMessage: String, statusCode: Int, statusString: String, data: Option[JsObject] = None) case class ApiSuccess[T](data: T, status: String = "Ok", statusCode: Int = 200, headers: List[(String,String)]= Nil) case object ApiError { implicit val apiErrorFormat: Format[ApiError] = Json.format[ApiError] } object ApiErrors { lazy val notFound = ApiError("ContentNotFound", "Content does not exist", 404, "notfound") lazy val invalidContentSend = ApiError("InvalidContentType", "could not read json from the request", 400, "badrequest") lazy val conflict = ApiError("WorkflowContentExists", s"This item is already tracked in Workflow", 409, "conflict") def jsonParseError(errMsg: String) = ApiError("JsonParseError", s"failed to parse the json. Error(s): $errMsg", 400, "badrequest") def updateError[A](id: A) = ApiError("UpdateError", s"Item with ID, $id does not exist", 404, "notfound") def databaseError(exc: String) = ApiError("DatabaseError", s"$exc", 500, "internalservererror") def composerItemLinked(id: Long, composerId: String): ApiError = { ApiError("ComposerItemIsLinked", s"This stub is already linked to a composer article", 409, "conflict", Some( Json.obj( "stubId" -> JsNumber(id), "composerId" -> JsString(composerId) ) ) ) } } object Response extends Results with Logging { type Response[T] = Either[ApiError, ApiSuccess[T]] def apply[T](action: => Response[T])(implicit tjs: Writes[T]): Result = { action.fold({ apiError => { logger.info(apiError.friendlyMessage) Status(apiError.statusCode) { JsObject(Seq( "status" -> JsString(apiError.statusString), "statusCode" -> JsNumber(apiError.statusCode), "error" -> Json.toJson(apiError) )) } } }, apiSuccess => { Status(apiSuccess.statusCode) { JsObject(Seq( "status" -> JsString(apiSuccess.status), "statusCode" -> JsNumber(apiSuccess.statusCode), "data" -> Json.toJson(apiSuccess.data) )) }.withHeaders(apiSuccess.headers:_*) }) } }