On 25/04/2017 00:13, Andras Szerdahelyi wrote:

I have a need to encode exception messages in to a specific JSON format in
my http responses. I was wondering how I could catch a
DeserializationException in my route or outside of it or encode the
DeserializationException.

Here's how I did it so that it integrasted into my existing REST service error handling:

Wrapped the deserialization operation in a try block:

def getParam[T: JsonReader](params: MMap[String, JsValue], key: String, delete: Boolean = true): T = {
    val value = params.get(key) match {
      case Some(v) => try {
          v.convertTo[T]
        } catch {
case de: DeserializationException => throw deserializationToRESTException(de, key)
        }
      case None => throw RESTException(ERR_MISSING_ARG(key))
    }
    if (delete) params -= key
    value
  }

  val restErrorRE: Regex = """^Expected (\w+) as \w+, but got (.+)$""".r

def deserializationToRESTException(de: DeserializationException, key: String) = {
    val msg = de.msg match {
      case restErrorRE(t, v) => s"expected $key to be $t but got $v"
      case _ => s"invalid value for $key"
    }
    RESTException(ERR_INVALID_ARG(msg), de)
  }

Then I wrapped all the individual deserialization calls in a try block:

   try {
   :
     val name = getParam[String](fields, "name")
     val uid = getParam[Int](fields, "uid")
   :
   } catch {
      case re: RESTException => complete(re.toResponse)

final case class RESTException(error: RESTError, cause: Throwable = null) extends Exception(error.toString, cause) {
    def toResponse: HttpResponse = error.toResponse
  }

  final case class ERR_INVALID_ARG(det: String = null)
    extends RESTErrorWithDetail(400, "invalid input argument", det)

RESTErrorWithDetail just maps the error code and message onto a normal HttpResponse containing the HTTP status code and a JSON formatted error message:

  override def toResponse: HttpResponse = {
    if (detail != null) {
HttpResponse(status = code, entity = HttpEntity(MediaTypes.`application/json`, """{ "fault": { "code": %d, "name": %s, "message": %s } }""".format(
          code, name.toJson, s"$msg ($detail)".toJson)))
    } else {
      super.toResponse
    }
  }

That way the JSON deserialization errors are handled as normal completions rather than using a specific Akka-HTTP exception handler.

--
Alan Burlison
--

--
     Read the docs: http://akka.io/docs/
     Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
     Search the archives: https://groups.google.com/group/akka-user
--- You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Reply via email to