How to Wrap Rejection Overall with Akka-Http

I would like to use the Akka Http routing system along with its reject system, but you need to enclose a Json response to reject in the general Json message block.

This does not work for me in a very general way, creating a RejectionHandler, and then adding cases for all possible failures and handling them all with a specific response code and message.

Example:

// Wraps string into control block format def WrappingBlock(msg: String) = ??? val myRejectionHandler = RejectionHandler .newBuilder() .handle{case MalformedRequestContentRejection(msg, detail) => complete(BadRequest, WrappingBlock(msg)) } ... // Further lines for all other possible rejections ... // along with their response codes and messages. ... // It would be nice if this was just generic code ... // rather than specific to every rejection type. .result() val routes = handleRejections(myRejectionHandler){ ... } 

However, I would like it to be the response code that Akka HTTP provides by default, as well as the pretty printed message provided, simply embedded in the Json control shell without a string for each possible type of rejection. It seems to be possible, but I could not complete it.

+5
source share
1 answer

I think you can do what you want by using the handleRejections combination explicitly with mapResponse . First, consider this simple route definition:

 (get & path("foo")){ complete((StatusCodes.OK, HttpEntity(ContentTypes.`application/json`, """{"foo": "bar"}""" ))) } 

If I get the corresponding request, I will respond using json and my caller will be happy because they will be able to parse the response as json. But if you try to call this endpoint with a POST request, you will get the answer as follows:

 HTTP 405 Method Not Allowed Date: Wed, 06 Jan 2016 13:19:27 GMT Content-Type: text/plain; charset=UTF-8 Content-Length: 47 Allow: GET Server: akka-http/2.3.12 HTTP method not allowed, supported methods: GET 

So here we get a simple text response that is undesirable. We can solve this problem everywhere by adding a couple of directives to the very top of my routing tree:

 mapResponse(wrapToJson){ handleRejections(RejectionHandler.default){ (get & path("foo")){ complete((StatusCodes.OK, HttpEntity(ContentTypes.`application/json`, """{"foo": "bar"}""" ))) } } } 

With wrapToJson is defined as:

 def wrapToJson(resp:HttpResponse):HttpResponse = { //If we get a text/plain response entity, remap it otherwise do nothing val newResp = resp.entity match{ case HttpEntity.Strict(ContentTypes.`text/plain(UTF-8)` , content ) => val jsonResp = s"""{"error": "${content.utf8String}"}""" resp.copy(entity = HttpEntity(ContentTypes.`application/json`, jsonResp)) case other => resp } newResp } 

This is a very simple example, and you will probably have a better way to generate json, but it just shows how you can fix the plan text responses from the default reject handler. Now you must explicitly mapResponse default deviation handler in mapResponse , because automatic processing is added beyond the top level of any tree you define, and thus mapResponse will not see deviation cases. You still get the default processing, but through RejectionHandler.default .

Hope this is close to what you were.

+5
source

Source: https://habr.com/ru/post/1239925/


All Articles