Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play WS standalone for 2.5.x

I want to create a Play web service client outside a Play application. For Play WS version 2.4.x it is easy to find that it is done like this:

val config = new NingAsyncHttpClientConfigBuilder().build()
val builder = new AsyncHttpClientConfig.Builder(config)
val client = new NingWSClient(builder.build)

However in 2.5.x the NingWSClient is now deprecated - instead the AhcWSClient should be used.

Unfortunately, I didn't find a complete example that explains the creation and usage of a AhcWsClient outside of Play. Currently I go with this:

import play.api.libs.ws.ahc.AhcWSClient
import akka.stream.ActorMaterializer
import akka.actor.ActorSystem

implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val ws = AhcWSClient()

val req = ws.url("http://example.com").get().map{
  resp => resp.body
}(system.dispatcher)

Is this the correct way of creating a AhcWsClient? And is there a way of creating a AhcWSClient without an ActorSystem?

like image 706
Zwackelmann Avatar asked Apr 12 '16 08:04

Zwackelmann


1 Answers

You are probably using compile time dependency injection, otherwise you would just use @Inject() (ws: WSClient), right?.
There is one example in the docs: https://www.playframework.com/documentation/2.5.x/ScalaWS#using-wsclient
So you could write something like this in your application loader:

lazy val ws = {
  import com.typesafe.config.ConfigFactory
  import play.api._
  import play.api.libs.ws._
  import play.api.libs.ws.ahc.{AhcWSClient, AhcWSClientConfig}
  import play.api.libs.ws.ahc.AhcConfigBuilder
  import org.asynchttpclient.AsyncHttpClientConfig

  val configuration = Configuration.reference ++ Configuration(ConfigFactory.parseString(
    """
      |ws.followRedirects = true
    """.stripMargin))

  val parser = new WSConfigParser(configuration, environment)
  val config = new AhcWSClientConfig(wsClientConfig = parser.parse())
  val builder = new AhcConfigBuilder(config)
  val logging = new AsyncHttpClientConfig.AdditionalChannelInitializer() {
    override def initChannel(channel: io.netty.channel.Channel): Unit = {
      channel.pipeline.addFirst("log", new io.netty.handler.logging.LoggingHandler("debug"))
    }
  }
  val ahcBuilder = builder.configure()
  ahcBuilder.setHttpAdditionalChannelInitializer(logging)
  val ahcConfig = ahcBuilder.build()
  new AhcWSClient(ahcConfig)
}
applicationLifecycle.addStopHook(() => Future.successful(ws.close))

And then inject ws to your controllers. I'm not 100% sure with this approach, I would be happy if some Play guru could validate this.
Regarding an ActorSystem, you need it only to get a thread pool for resolving that Future. You can also just import or inject the default execution context:
play.api.libs.concurrent.Execution.Implicits.defaultContext.
Or you can use your own:
implicit val wsContext: ExecutionContext = actorSystem.dispatchers.lookup("contexts.your-special-ws-config").

like image 88
icl7126 Avatar answered Sep 21 '22 04:09

icl7126