scalaplayframeworkplayframework-2.2

How can I add a message body to a Play2.2 Scala WS GET?


I'm aware this is unconventional - I'm accessing an API that requires JSON objects posted as a message body for GET requests. Using Play 2.2.2 and play.api.libs.ws.WS

I'm attempting to add a message body to the WSRequestHolder. The .post() method allows this, but the .get() method doesn't have such a parameter. I'm looking at using the basic WSRequest class instead of the WSRequestHolder but not sure of a better way to do this.

Psuedo-code:

WS.url(url).get(Json.obj("param" -> "value"))

or

WS.url(url).setBody(Json.obj("param" -> "value")).get()

Any ideas? Thanks for your help!


Solution

  • When in doubt, roll your own solution.

    import scala.concurrent.{ Future, Promise }
    import play.api.libs.concurrent._
    import play.api.libs.iteratee._
    import play.api.libs.iteratee.Input._
    import play.api.libs.json._
    import play.api.http.{ Writeable, ContentTypeOf }
    import play.api.libs.ws.WS._
    import play.api.libs.ws.{SignatureCalculator, Response}
    import com.ning.http.client.Realm.AuthScheme
    import com.ning.http.client.PerRequestConfig
    
    
    class MyRequest(
      url: String,
      headers: Map[String, Seq[String]],
      queryString: Map[String, Seq[String]],
      calc: Option[SignatureCalculator],
      auth: Option[Tuple3[String, String, AuthScheme]],
      followRedirects: Option[Boolean],
      requestTimeout: Option[Int],
      virtualHost: Option[String]
    
    ) extends WSRequestHolder(url,headers,queryString,calc,auth,followRedirects,requestTimeout,virtualHost) {
    
      /**
       * Perform a GET on the request asynchronously with a body.
       */
      def get[T](body: T)(implicit wrt: Writeable[T], ct: ContentTypeOf[T]): Future[Response] = prepare("POST", body).execute
    
      /**
       * Prepare a request
       * @param method
       * @param body
       * @param wrt
       * @param ct
       * @tparam T
       * @return
       */
      override def prepare[T](method: String, body: T)(implicit wrt: Writeable[T], ct: ContentTypeOf[T]) = {
        val request = new WSRequest(method, auth, calc).setUrl(url)
          .setHeaders(Map("Content-Type" -> Seq(ct.mimeType.getOrElse("text/plain"))) ++ headers)
          .setQueryString(queryString)
          .setBody(wrt.transform(body))
        followRedirects.map(request.setFollowRedirects)
        requestTimeout.map {
          t: Int =>
            val config = new PerRequestConfig()
            config.setRequestTimeoutInMs(t)
            request.setPerRequestConfig(config)
        }
        virtualHost.map {
          v =>
            request.setVirtualHost(v)
        }
        request
      }
    
    }
    
    object MyWS {
      /**
       * Prepare a new request. You can then construct it by chaining calls.
       *
       * @param url the URL to request
       */
      def url(url: String): MyRequest = new MyRequest(url, Map(), Map(), None, None, None, None, None)
    }