web-dev-qa-db-fra.com

Akka-http: Accepter et traitement du type de contenu

J'essaie Akka-http et j'espère que quelqu'un pourra faire la lumière sur les questions suivantes:

  1. Comment créer des itinéraires différents en fonction de l'en-tête accept: de la demande? Par exemple, je veux un chemin de code pour gérer "json" et un pour gérer les requêtes "xml" (avec par défaut "json" si l'en-tête est manquant)

  2. Dans les cas où je ne veux pas que le contentType soit déduit, comment puis-je le spécifier? Par exemple, dans le code ci-dessous, j'essaie d'exécuter le JSON via compactPrint (), mais cela le change en chaîne, d'où le libellé "text/plain". Je veux annuler cela et dire au client que c'est toujours JSON. 

Mon code est quelque chose comme ça;

...
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 réponse dans ce cas est text/plain, puisque compactPrint crée une chaîne . Critique très bienvenue. ;)

12
Will I Am

Vous pouvez définir le type de contenu comme suit,

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

Vous pouvez créer votre directive personnalisée en tant que,

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

et utiliser la directive en route comme

val route = path("api"){ handleReq(json) }
9
S.Karthik

La réponse possible à la question n ° 1 semble être la suivante, mais j'aimerais le faire via une directive personnalisée ou quelque chose de plus élégant. Malheureusement, la documentation relative aux directives personnalisées Akka-Http semble faire défaut. 

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

En espérant que quelqu'un puisse fournir quelque chose de plus propre.

1
Will I Am

Il semble que la réponse acceptée ne fonctionne plus avec akka-http v10.0.3.

Cela fonctionne bien:

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

tu pourrais aussi faire 

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`)))
          }
      }
    }
}

J'espère que cela aide.

1
fchaillou