2016-01-05 7 views
5

Chciałbym użyć systemu routingu Akka Http, wraz z jego systemem odrzucania, ale trzeba zagnieździć Json odpowiedzi dla odrzucenia w ramach ogólnego bloku wiadomości Json.Jak ogólnie owinąć odrzucenie za pomocą Akka-Http

Mam to działa w bardzo nietypowy sposób, tworząc RejectionHandler, a następnie dodając przypadki dla wszystkich możliwych odrzuceń i obsługując je wszystkie za pomocą specjalnego kodu odpowiedzi i komunikatu.

przykład:

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

Jednak to, co chciałbym jest kod odpowiedzi, że Akka HTTP udostępnia domyślnie, a także całkiem wiadomość druku, który jest dostarczany tylko zagnieżdżony w opakowaniu jednostkowym sterowania Json bez linii do każdy możliwy rodzaj odrzucenia. Wygląda na to, że powinno być możliwe, ale nie byłem w stanie go ukończyć.

Odpowiedz

5

Myślę, że można zrobić to, co chcesz, używając kombinacji handleRejections jawnie z mapResponse. Po pierwsze, należy rozważyć tę prostą definicję trasy:

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

Jeśli dostanę wniosek pasujący będę reagować za pomocą JSON i mój rozmówca jest szczęśliwy, ponieważ mogą one analizować odpowiedź jako JSON. Ale jeśli spróbujesz i nazywają to końcowy z żądania POST, dostaniesz odpowiedź następująco:

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 

Więc tutaj mamy odpowiedź zwykłego tekstu, co nie jest pożądane. Możemy rozwiązać ten problem powszechnie dodając kilka dyrektyw samym szczycie mojego drzewa routingu tak:

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

Z wrapToJson jest zdefiniowany jako:

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 
} 

Jest to bardzo prosty przykład, i prawdopodobnie masz lepszy sposób na wygenerowanie jsona, ale służy to tylko po to, aby pokazać, jak możesz poprawić odpowiedzi tekstowe planu z domyślnej obsługi odrzucania. Teraz należy domyślnie zagnieździć domyślną procedurę obsługi odrzucania pod mapResponse, ponieważ automatyczna obsługa zostanie dodana poza najwyższym poziomem dowolnego drzewa zdefiniowanego przez użytkownika i dlatego nie będzie widać skrzynek odrzucania. Nadal masz domyślną obsługę za pośrednictwem RejectionHandler.default.

Mam nadzieję, że jest blisko tego, o co prosiłeś.

+0

To jest bardzo interesujące, nie myślałem o użyciu kombinacji z odpowiedzią na mapę, przyjrzę się tej opcji. – AlexC

+0

Czy można napisać jako niestandardowy RejectionHandler? Nie mogłem znaleźć takiego rozwiązania, ponieważ wymaga 'Route' przy wyjściu, gdzie jak w twoim przypadku mamy' dyrektywę'. – expert

+0

@ruslan, nie jestem pewien, o co pytasz. Z pewnością można utworzyć niestandardową procedurę obsługi odrzucania, jak opisano tutaj: http://doc.akka.io/docs/akka-stream-and-http-experimental/2.0.2/scala/http/routing-dsl/rejections.html# Customizing_Rejection_Handling. Nie wiesz, dlaczego masz na myśli "trasę" kontra "dyrektywę" przy wyjściu. Być może utwórz na tej podstawie nowe pytanie, które lepiej opisuje twoją sytuację. – cmbaxter