2015-08-24 17 views
12

sto provando Content-type Akka-http e si spera che qualcuno può far luce su una delle seguenti domande:Akka-http: Accetta e movimentazione

  1. Come si fa a creare percorsi diversi in base alla accettare : intestazione nella richiesta? Ad esempio, voglio un percorso di codice per gestire "json" e uno per gestire le richieste "xml" (con predefinito su "json" se manca l'intestazione)

  2. Nei casi in cui non desidero che il contentType sia dedotto, come posso specificarlo? Ad esempio, nel codice qui sotto cerco di eseguire json tramite compactPrint() ma questo lo cambia in una stringa, quindi "text/plain". Voglio scavalcarlo e dire al cliente che è ancora json.

Il mio codice è qualcosa del genere;

... 
path("api") { 
      get { 
       complete { 
       getStuff.map[ToResponseMarshallable] { 
        case Right(r) if r.isEmpty => List[String]().toJson.compactPrint 
        case Right(r) => r.toJson.compactPrint 
        case Left(e) => BadRequest -> e 
       } 
       } 
      } 
     } 
... 

La risposta in questo caso è text/plain, poiché compactPrint crea una stringa. critica molto gradita. ;)

+1

Per utilizzare la funzione di negoziazione del contenuto automatico di akka-http è necessario fornire un marshaller per il proprio tipo di origine che possa eseguire il marshalling su diversi tipi di contenuto. Puoi usare 'Marshaller.oneOf' per comporre diversi marshaller in cui ogni marshaller sa come effettuare il marshalling di un solo tipo di contenuto. Hai visto la documentazione su Marshaller su http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0/scala/http/common/marshalling.html#Custom_Marshallers? – jrudolph

+0

Grazie. Ho finito per percorrere questa strada. –

risposta

8

È possibile definire il tipo di contenuto come segue,

complete { 
      HttpResponse(entity = HttpEntity(ContentType(MediaTypes.`application/json`), """{"id":"1"}""")) 
     } 

È possibile creare la direttiva personalizzato come,

def handleReq(json: String) = { 
    (get & extract(_.request.acceptedMediaRanges)) { 
     r => 
     val encoding: MediaRange = 
      r.intersect(myEncodings).headOption 
      .getOrElse(MediaTypes.`application/json`) 
     complete { 
      // check conditions here 
     // HttpResponse(entity = HttpEntity(encoding.specimen, json)) // 
     } 
    } 
    } 

e utilizzare la direttiva nel percorso come

val route = path("api"){ handleReq(json) } 
+0

Grazie. Speravo solo che una direttiva eseguisse un rifiuto basato sull'intestazione, non per comprendere l'elaborazione effettiva. Ma comunque, ho finito per implementare i marshaller che si occupano automaticamente della serializzazione in XML o JSON, quindi non ho più bisogno di questo approccio. Ma grazie per il tuo aiuto, mi ha aiutato a superare la mia frustrazione, ed è un modo di implementare le cose. Quindi accetterò la risposta. –

+0

qui meglio usare ContentTypes.'application/json' invece di ContentType (MediaTypes.application/json') – RomKazanova

1

Una potenziale risposta alla domanda n. 1 sembra essere questa, ma mi piacerebbe farlo tramite una direttiva personalizzata o qualcosa di più elegante. Sfortunatamente la documentazione per le direttive personalizzate Akka-Http sembra mancare.

// the encodings I want, in the order of preference 
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange(`application/json`)) 

    ... 
    path("api") { 
       (get & extract(_.request.acceptedMediaRanges)){ 
        r => 
        val encoding = 
         r.intersect(myEncodings).headOption 
         .getOrElse(MediaRange(`application/json`)) 
        complete { 
         // check "encoding" here and make decision. 
        } 
       } 
      } 
    ... 

Sperando che qualcuno possa fornire qualcosa di più pulito.

+0

Ho aggiornato la risposta, è possibile controllare, è quello che vuoi. –

0

Sembra che la risposta accettata non funzioni più con akka-http v10.0.3.

Questo funziona però:

// the encodings I want, in the order of preference 
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange(`application/json`)) 

... 
path("api") { 
      (get & extract(_.request.headers)){ requestHeaders => 
       val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders) 
       val encoding = mediaTypeNegotiator 
        .acceptedMediaRanges 
        .intersect(myEncodings) 
        .headOption 
        .getOrElse(MediaRange(`application/json`)) 
       complete { 
        // check "encoding" here and make decision. 
       } 
      } 
     } 
... 

si potrebbe anche fare

val myEncodings = Seq(MediaRange(`application/xml`),MediaRange(`application/json`)) 

path("api") { 
     (get & extract(_.request.headers)){ requestHeaders => 
     complete { 
      val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders) 
      if(mediaTypeNegotiator.accept(MediaTypes.`application/xml`)) { 
      // respond with xml 
      } else if(mediaTypeNegotiator.accept(MediaTypes.`application/json`)) { 
      // respond with json 
      } else { 
      // respond with json by default or reject properly : 
      reject(UnsupportedRequestContentTypeRejection(Set(MediaTypes.`application/xml`, MediaTypes.`application/json`))) 
      } 
     } 
    } 
} 

spera che questo aiuta.