2016-01-05 6 views
5

Ich möchte das Akka Http-Routing-System zusammen mit seinem Ablehnungssystem verwenden, muss aber die Antwort Json für eine Ablehnung in einem generischen Json-Nachrichtenblock verschachteln.Wie generiere ich eine Abweisung generisch mit Akka-Http

Ich habe dies funktioniert in einer sehr nicht-generischen Art und Weise erstellen eine AblehnungHandler dann Fällen für alle möglichen Ablehnungen hinzufügen und sie alle mit dem spezifischen Antwortcode und Nachricht behandeln.

Beispiel:

// 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){ 
    ... 
} 

Aber was ich möchte, ist der Antwortcode, der Akka HTTP standardmäßig bereitstellt und auch die hübsche Drucknachricht, die bereitgestellt wird, verschachtelt nur innerhalb einer Json Steuer Wrapper ohne Linie für jeder mögliche Ablehnungstyp. Das scheint so zu sein, als ob es möglich wäre, aber ich konnte es nicht abschließen.

Antwort

5

Ich denke, es ist möglich zu tun, was Sie wollen mit einer Kombination von handleRejections explizit mit mapResponse. Zunächst betrachten diese einfache Route Definition:

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

Wenn ich eine passende Anfrage erhalten werde ich glücklich mit json und mein Anrufer reagieren, weil sie die Antwort als json analysieren kann. Aber wenn Sie diesen Endpunkt versuchen und rufen mit einer POST-Anfrage, erhalten Sie eine Antwort erhalten wie folgt:

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 

Also hier haben wir eine einfache Text Antwort erhalten, was nicht wünschenswert ist. Wir können dieses Problem universell lösen, indem ein paar Richtlinien an die Spitze meiner Routing-Baum Hinzufügen wie so:

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

Mit wrapToJson wird wie folgt definiert:

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 
} 

Dies ist ein sehr einfaches Beispiel, und Sie würden wahrscheinlich eine bessere Möglichkeit haben, den JSON zu generieren, aber dies dient nur dazu, zu zeigen, wie Sie die Plan-Text-Antworten vom Standard-Ablehnungs-Handler reparieren können. Jetzt müssen Sie den standardmäßigen Ablehnungshandler explizit unter mapResponse verschachteln, da die automatische Verarbeitung außerhalb der obersten Ebene des von Ihnen definierten Baums hinzugefügt wird und somit mapResponse die Ablehnungsfälle nicht sehen würde. Sie erhalten jedoch immer noch die Standardbehandlung über RejectionHandler.default.

Hoffentlich ist dies nah an dem, was Sie wollten.

+0

Das ist sehr interessant, ich hatte nicht gedacht, eine Kombination mit Kartenantwort zu verwenden, ich werde diese Option betrachten. – AlexC

+0

Ist es möglich, als benutzerdefinierten RejectionHandler zu schreiben? Ich könnte nicht mit einer solchen Lösung kommen, weil es beim Verlassen "Route" erfordert, wo wir in Ihrem Fall "Richtlinie" haben. – expert

+0

@ruslan, ich bin mir nicht sicher, was genau du fragst. Sie können sicherlich einen benutzerdefinierten Ablehnungs-Handler erstellen, wie hier beschrieben: http://doc.akka.io/docs/akka-stream-und-http-experimental/2.0.2/scala/http/routing-dsl/rejections.html# Customizing_Rejection_Handling. Nicht sicher, warum Sie auf der "Route" gegen "Direktive" beim Verlassen meinen. Vielleicht erstellen Sie auf dieser Grundlage eine neue Frage, die Ihre Situation besser beschreibt. – cmbaxter

Verwandte Themen