You are viewing the documentation for the 2.5.x release series. The latest stable release series is 2.6.x

Search

Sometimes we would like to call other HTTP services from within a Play application. Play supports this via its WS library, which provides a way to make asynchronous HTTP calls.

There are two important parts to using the WS API: making a request, and processing the response. We'll discuss how to make both GET and POST HTTP requests first, and then show how to process the response from WS. Finally, we'll discuss some common use cases.

To use WS, first add ws to your build.sbt file:

libraryDependencies ++= Seq( ws )

Now any controller or component that wants to use WS will have to declare a dependency on the WSClient :

import javax.inject.Inject import scala.concurrent.Future import scala.concurrent.duration._ import play.api.mvc._ import play.api.libs.ws._ import play.api.http.HttpEntity import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.stream.scaladsl._ import akka.util.ByteString import scala.concurrent.ExecutionContext class Application @Inject() (ws: WSClient) extends Controller { }

We've called the WSClient instance ws , all the following examples will assume this name.

To build an HTTP request, you start with ws.url() to specify the URL.

val request: WSRequest = ws.url(url)

This returns a WSRequest that you can use to specify various HTTP options, such as setting headers. You can chain calls together to construct complex requests.

val complexRequest: WSRequest = request.withHeaders("Accept" -> "application/json") .withRequestTimeout(10000.millis) .withQueryString("search" -> "play")

You end by calling a method corresponding to the HTTP method you want to use. This ends the chain, and uses all the options defined on the built request in the WSRequest .

val futureResponse: Future[WSResponse] = complexRequest.get()

This returns a Future[WSResponse] where the Response contains the data returned from the server.

If you need to use HTTP authentication, you can specify it in the builder, using a username, password, and an AuthScheme. Valid case objects for the AuthScheme are BASIC , DIGEST , KERBEROS , NTLM , and SPNEGO .

ws.url(url).withAuth(user, password, WSAuthScheme.BASIC).get()

If an HTTP call results in a 302 or a 301 redirect, you can automatically follow the redirect without having to make another call.

ws.url(url).withFollowRedirects(true).get()

Parameters can be specified as a series of key/value tuples.

ws.url(url).withQueryString("paramKey" -> "paramValue").get()

Headers can be specified as a series of key/value tuples.

ws.url(url).withHeaders("headerKey" -> "headerValue").get()

If you are sending plain text in a particular format, you may want to define the content type explicitly.

ws.url(url).withHeaders("Content-Type" -> "application/xml").post(xmlString)

A virtual host can be specified as a string.

ws.url(url).withVirtualHost("192.168.1.1").get()

If you wish to specify a request timeout, you can use withRequestTimeout to set a value. An infinite timeout can be set by passing Duration.Inf .

ws.url(url).withRequestTimeout(5000.millis).get()

To post url-form-encoded data a Map[String, Seq[String]] needs to be passed into post .

ws.url(url).post(Map("key" -> Seq("value")))

To post multipart-form-encoded data a Source[play.api.mvc.MultipartFormData.Part[Source[ByteString, Any]], Any] needs to be passed into post .

ws.url(url).post(Source.single(DataPart("key", "value")))

To upload a file you need to pass a play.api.mvc.MultipartFormData.FilePart[Source[ByteString, Any]] to the Source :

ws.url(url).post(Source(FilePart("hello