2014-01-14 9 views
8

Im Spray würde ich gerne mit verschiedenen Inhaltstypen antworten, je nach gegebenem Accept Header. Ich habe ein paar Vorschläge in der question by rompetroll gesehen, aber ich würde gerne hören, ob es eine kanonische Art und Weise zu tun gibt (d. H. Einfach oder bereits implementiert).Spray Routing: Wie reagiert man mit verschiedenen Content-Typen?

Im Grunde, was ich geschehen vorstellen sollte, ist so etwas wie:

path("somepath") { 
    get { 
    // Find whatever we would like to return (lazily) 
    ... 
    // Marshall resource and complete depending on the `Accept` header 
    ... 
    } 
} 

Vielen Dank im Voraus.

Antwort

8

Spray untersucht tatsächlich den Accept Header-Wert und validiert dagegen. Wenn also die Route application/json oder text/plain zurückgibt und der Client image/jpeg akzeptiert, wird spray 406 Not Acceptable zurückgeben. Wenn der Kunde application/json oder text/plain von dieser Route anfordert, erhält er eine Antwort mit passendem Content-Type.

Der Haupttrick hier ist die Verwendung korrekter Marshaller für Rückgabeobjekte. Sie können mehr über das Marshalling here lesen.

Auch Sie können MediaType mit respondWithMediaType Richtlinie überschreiben, aber ich denke, es ist besser, richtige Marshaller zu verwenden.

+0

Das macht einen lotta Sinn. Das habe ich aus der Dokumentation total vermisst. Danke :) –

+1

Einverstanden, 'respondWithMediaType' ist normalerweise der falsche Weg zu gehen. Marshaller enthalten bereits die gesamte Logik für die automatische Inhaltsaushandlung. Siehe meine Antwort, wie man Marshaller für verschiedene Inhaltstypen zu einem kombiniert, der alle akzeptiert und den richtigen Marshaller für alle auswählt. – jrudolph

15

Siehe die Tests in this commit.

ich es hier als Referenz kopiert:

case class Data(name: String, age: Int) 
object Data { 
    import spray.json.DefaultJsonProtocol._ 
    import spray.httpx.SprayJsonSupport._ 

    // don't make those `implicit` or you will "ambiguous implicit" errors when compiling 
    val jsonMarshaller: Marshaller[Data] = jsonFormat2(Data.apply) 
    val xmlMarshaller: Marshaller[Data] = 
    Marshaller.delegate[Data, xml.NodeSeq](MediaTypes.`text/xml`) { (data: Data) ⇒ 
     <data><name>{ data.name }</name><age>{ data.age }</age></data> 
    } 

    implicit val dataMarshaller: ToResponseMarshaller[Data] = 
    ToResponseMarshaller.oneOf(MediaTypes.`application/json`, MediaTypes.`text/xml`) (jsonMarshaller, xmlMarshaller) 
} 

Sie dann complete mit in Ihre Route, Content-Type Verhandlung automatisch gesorgt genügen sollte:

get { 
    complete(Data("Ida", 83)) 
} 
+0

Dumme Frage, aber in dem Aufruf 'jsonFormat2 (Data.apply) oben, wo ist die' .apply' definiert? – ivcheto

+0

Es wird automatisch vom Scala-Compiler für eine 'case class' generiert, um die' Data (...) '-Syntax zu unterstützen, anstatt' 'new Data (...)' 'schreiben zu müssen. – jrudolph

+0

ah nett! Vielen Dank! – ivcheto