[英]Return JSON errors in akka-http API
在我正在编写的API中,即使发生错误,我也想采用并返回JSON。 我试图弄清楚如何保留所有default
RejectionHandler
行为,但是将状态代码和文本转换为JSON对象。 由于默认行为是在函数调用中指定的,而不是在数据结构中指定的,因此似乎唯一的方法是转换其产生的结果的HttpEntity
。 有没有简单的方法可以做到这一点?
您可以在HttpService
编写类似的内容
private val defaultRejectionHandler = RejectionHandler.default
implicit def myRejectionHandler =
RejectionHandler.newBuilder()
.handleAll[Rejection] { rejections ⇒
def prefixEntity(entity: ResponseEntity): ResponseEntity = entity match {
case HttpEntity.Strict(contentType, data) => {
import spray.json._
val text = ErrorResponse(0, "Rejection", data.utf8String).toJson.prettyPrint
HttpEntity(ContentTypes.`application/json`, text)
}
case _ =>
throw new IllegalStateException("Unexpected entity type")
}
mapResponseEntity(prefixEntity) {
defaultRejectionHandler(rejections).getOrElse {
complete(StatusCodes.InternalServerError)
}
}
}.handleNotFound {
complete(StatusCodes.Forbidden -> ErrorResponse(StatusCodes.NotFound.intValue, "NotFound", "Requested resource is not found"))
}.result()
哪里可能有ErrorResponse
case class ErrorResponse(error: ErrorInfo)
case class ErrorInfo(code: Int, `type`: String, message: String)
您可以为其定义json编组器。
我把自己的版本拼凑在一起,但是有一些我不喜欢的粗糙边缘。 ruslan的回答给了我一些改进的想法。 这是我想出的,综合了两种方法的优点:
/**
* Modifies the Akka-Http default rejection handler to wrap the default
* message in JSON wrapper, preserving the original status code.
*
* @param rejectionWrapper wraps the message in a structure to format the
* resulting JSON object
* @param writer writer for the wrapper type
* @tparam WrapperType type of the wrapper
* @return the modified rejection handler
*/
def defaultRejectionHandlerAsJson[WrapperType](rejectionWrapper: String => WrapperType)(implicit writer: JsonWriter[WrapperType]) = {
def rejectionModifier(originalMessage: String): String = {
writer.write(rejectionWrapper(originalMessage)).prettyPrint
}
modifiedDefaultRejectionHandler(rejectionModifier, ContentTypes.`application/json`)
}
/**
* Modifies the Akka-Http default rejection handler, converting the default
* message to some other textual representation.
*
* @param rejectionModifier the modifier function
* @param newContentType the new Content Type, defaulting to text/plain
* UTF-8
* @return the modified rejection handler
*/
def modifiedDefaultRejectionHandler(rejectionModifier: String => String, newContentType: ContentType.NonBinary = ContentTypes.`text/plain(UTF-8)`) = new RejectionHandler {
def repackageRouteResult(entity: ResponseEntity): ResponseEntity = entity match {
// If the entity isn't Strict (and it definitely will be), don't bother
// converting, just throw an error, because something's weird.
case strictEntity: HttpEntity.Strict =>
val modifiedMessage = rejectionModifier(strictEntity.data.utf8String)
HttpEntity(newContentType, modifiedMessage)
case other =>
throw new Exception("Unexpected entity type")
}
def apply(v1: Seq[Rejection]): Option[Route] = {
// The default rejection handler should handle all possible rejections,
// so if this isn't the case, return a 503.
val originalResult = RejectionHandler.default(v1).getOrElse(complete(StatusCodes.InternalServerError))
Some(mapResponseEntity(repackageRouteResult) {
originalResult
})
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.