WS in Play become incredible complex for 2.6.X - scala

For Play 2.3.X the WS module is very easy to be used:
WS.url(s"http://$webEndpoint/hand/$handnumber").get()
For the such simple and strightforward usage.
While in Play 2.6.x according to the link :
https://www.playframework.com/documentation/2.6.x/JavaWS
You need to create a http client firstly.
WSClient customWSClient = play.libs.ws.ahc.AhcWSClient.create(
play.libs.ws.ahc.AhcWSClientConfigFactory.forConfig(
configuration.underlying(),
environment.classLoader()),
null, // no HTTP caching
materializer);
And what's more, you also need a materializer and an akka system to support the materializer.
String name = "wsclient";
ActorSystem system = ActorSystem.create(name);
ActorMaterializerSettings settings = ActorMaterializerSettings.create(system);
ActorMaterializer materializer = ActorMaterializer.create(settings, system, name);
// Set up AsyncHttpClient directly from config
AsyncHttpClientConfig asyncHttpClientConfig = new DefaultAsyncHttpClientConfig.Builder()
.setMaxRequestRetry(0)
.setShutdownQuietPeriod(0)
.setShutdownTimeout(0).build();
AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(asyncHttpClientConfig);
// Set up WSClient instance directly from asynchttpclient.
WSClient client = new AhcWSClient(
asyncHttpClient,
materializer
);
I knew it will add more features to the WS client, but when I just want a simple http client, the usage become unaccept complex, it's so wired.

The page you link to says:
We recommend that you get your WSClient instances using dependency injection as described above. WSClient instances created through dependency injection are simpler to use because they are automatically created when the application starts and cleaned up when the application stops.
It shouldn't then surprise you that manually creating instance of WSClient is tedious.
And the same page describes how to use an injected version of WSClient:
import javax.inject.Inject;
import play.mvc.*;
import play.libs.ws.*;
import java.util.concurrent.CompletionStage;
public class MyClient implements WSBodyReadables, WSBodyWritables {
private final WSClient ws;
#Inject
public MyClient(WSClient ws) {
this.ws = ws;
}
// ...
}
This is as simple as it's used to be in the previous versions. Actually, in previous Play versions you also could have created the custom instance of WSClient, and that used to have comparable complexity (modulo Akka stuff).

Finally I use ScalaJ-http, https://github.com/scalaj/scalaj-http
Which is very easy to use:
import scalaj.http._
...
response= Http("http://localhost:5000/health").asString
Which is simple as WS in play 2.3.6
For Play 2.6.x the framework may not create the default ws for you and see the example of https://github.com/playframework/play-scala-tls-example/blob/2.6.x/app/Main.scala

For people using Scala Play with fully DI support one solution to create WSClient instance is Play.current.injector.instanceOf[WSClient]. That also useful when updating to Scala Play 2.6 with small changes without adding DI support to all.

Related

How do I create thread pools in Play 2.5.x?

I am currently on Play 2.4.2 and have successfully created thread pools using the following below:
package threads
import scala.concurrent.ExecutionContext
import play.api.libs.concurrent.Akka
import play.api.Play.current
object Contexts {
implicit val db: ExecutionContext = Akka.system.dispatchers.lookup("contexts.db-context")
implicit val pdf: ExecutionContext = Akka.system.dispatchers.lookup("contexts.pdf-context")
implicit val email: ExecutionContext = Akka.system.dispatchers.lookup("contexts.email-context")
}
and then in the code with...
Future{....}(threads.Contexts.db)
We are ready to upgrade to Play 2.5 and having trouble understanding the documentation. The documentation for 2.4.2 uses Akka.system.dispatchers.lookup, which we use without issue. The documentation for 2.5.x uses app.actorSystem.dispatchers.lookup. As far as I know, I have to inject the app into a Class, not an Object. Yet the documentation clearly uses an Object for the example!
Has anyone successfully created thread pools in Play 2.5.x that can help out? Is it as simple as changing Contexts to a class, then injecting it wherever I would like to use this threading? Seems odd since to use the default ExecutionContext I just have to make an implicit import.
Also, we are using Play scala.
If you simply change your Contexts to a class, then you will have to deal with how to get an instance of that class.
In my opinion, if you have a number of thread pools that you want to make use of, named bindings are the way to go. In the below example, I will show you how you could accomplish this with guice.
Note that guice injects depedencies at runtime, but it is also possible to inject dependencies at compile time.
I'm going to show it with the db context as an example. First, this is how you will be using it:
class MyService #Inject() (#Named("db") dbCtx: ExecutionContext) {
// make db access here
}
And here's how you could define the binding:
bind[ExecutionContext].qualifiedWith("db").toProvider[DbExecutionContextProvider]
And somewhere define the provider:
class DbExecutionContextProvider #Inject() (actorSystem: ActorSystem) extends Provider[ExecutionContext] {
override def get(): ExecutionContext = actorSystem.dispatchers.lookup("contexts.db-context")
}
You will have to do this for each of your contexts. I understand this may be a little cumbersome and there may actually be more elegant ways to define the bindings in guice.
Note that I have not tried this out. One issue you might stumble upon could be that you'll end up with conflicts, because play already defines a binding for the ExecutionContext in their BuiltinModule. You may need to override the binding to work around that.

Alternative to using Akka.system inside an object

I am learning the Play Framework together with Scala, and I looked at the reactive-stocks tutorial that comes with activator for learning more about the framework.
In the learning project that I am creating (a simple chat) I want to have something similar to this snippet taken out from the tutorial:
object StocksActor {
lazy val stocksActor: ActorRef = Akka.system.actorOf(Props(classOf[StocksActor]))
}
That is, an actor that will only be instanciated one time on the application. But I found out that Akka.system is deprecated, so I should use dependency injection to get the ActorSystem. How would I do dependency injection in an Object?
object ChatRoomsActor #Inject() (actorSystem: ActorSystem) {
lazy val ref: ActorRef = actorSystem.actorOf(Props(classOf[ChatRoomsActor]))
}
I tried this code, but it doesn't work.

Scala and Slick: DatabaseConfigProvider in standalone application

I have an Play 2.5.3 application which uses Slick for reading an object from DB.
The service classes are built in the following way:
class SomeModelRepo #Inject()(protected val dbConfigProvider: DatabaseConfigProvider) {
val dbConfig = dbConfigProvider.get[JdbcProfile]
import dbConfig.driver.api._
val db = dbConfig.db
...
Now I need some standalone Scala scripts to perform some operations in the background. I need to connect to the DB within them and I would like to reuse my existing service classes to read objects from DB.
To instantiate a SomeModelRepo class' object I need to pass some DatabaseConfigProvider as a parameter. I tried to run:
object SomeParser extends App {
object testDbProvider extends DatabaseConfigProvider {
def get[P <: BasicProfile]: DatabaseConfig[P] = {
DatabaseConfigProvider.get("default")(Play.current)
}
}
...
val someRepo = new SomeModelRepo(testDbProvider)
however I have an error: "There is no started application" in the line with "(Play.current)". Moreover the method current in object Play is deprecated and should be replaced with DI.
Is there any way to initialize my SomeModelRepo class' object within the standalone object SomeParser?
Best regards
When you start your Play application, the PlaySlick module handles the Slick configurations for you. With it you have two choices:
inject DatabaseConfigProvider and get the driver from there, or
do a global lookup via DatabaseConfigProvider.get[JdbcProfile](Play.current), which is not preferred.
Either way, you must have your Play app running! Since this is not the case with your standalone scripts you get the error: "There is no started application".
So, you will have to use Slick's default approach, by instantiating db directly from config:
val db = Database.forConfig("default")
You have lot's of examples at Lightbend's templates.
EDIT: Sorry, I didn't read the whole question. Do you really need to have it as another application? You can run your background operations when your app starts, like here. In this example, InitialData class is instantiated as eager singleton, so it's insert() method is run immediately when app starts.

akka-http with multiple route configurations

Quick Background
I am running through some examples learning the Akka HTTP stack for creating a new REST project (completely non-UI). I have been using and augmenting the Akka HTTP Microservice Example to work through a bunch of use cases and configurations and have been pleasantly surprised by how well Scala & Akka HTTP work.
Current Setup
Currently I have a configuration like this:
object AkkaHttpMicroservice extends App with Service {
override implicit val system = ActorSystem()
override implicit val executor = system.dispatcher
override implicit val materializer = ActorMaterializer()
override val config = ConfigFactory.load()
override val logger = Logging(system, getClass)
Http().bindAndHandle(routes, config.getString("http.interface"), config.getInt("http.port"))
}
The routes parameter is just a simple value that has the typical data within it using path, pathPrefix, etc.
The Problem
Is there any way to set up routing in multiple Scala files or an example somewhere out there?
I would really like to be able to define a set of classes that separate the concerns and deal with Actor setup and processing to deal with different areas of the application and just leave the marshaling to the root App extension.
This might be me thinking too much in terms of how I did things in Java using annotations like #javax.ws.rs.Path("/whatever") on my classes. If that is the case, please feel free to point out the change in mindset.
I tried searching for a few different set of keywords but believe I am asking the wrong question (eg, 1, 2).
Problem 1 - combine routes in multiple files
You can combine routes from multiple files quite easy.
FooRouter.scala
object FooRouter {
val route = path("foo") {
complete {
Ok -> "foo"
}
}
}
BarRouter.scala
object BarRouter {
val route = path("bar") {
complete {
Ok -> "bar"
}
}
}
MainRouter.scala
import FooRouter
import BarRouter
import akka.http.scaladsl.server.Directives._
import ...
object MainRouter {
val routes = FooRouter.route ~ BarRouter.route
}
object AkkaHttpMicroservice extends App with Service {
...
Http().bindAndHandle(MainRouter.routes, config.getString("http.interface"), config.getInt("http.port"))
}
Here you have have some docs :
http://doc.akka.io/docs/akka-http/current/scala/http/routing-dsl/overview.html
http://doc.akka.io/docs/akka-http/current/scala/http/routing-dsl/routes.html
Problem 2 - seprate routing, marshalling, etc
Yes, you can separate routing, marshalling and application logic. Here you have activator example: https://github.com/theiterators/reactive-microservices
Problem 3 - handle routes using annotations
I don't know any lib that allow you to use annotion to define routing in akka-http. Try to learn more about DSL routing. This represents a different approach to http routing but it is convenient tool too.

How to reference to the standard ActorSystem of play framework 2?

I wish to use the scheduler of akka, the examples are saying:
system.scheduler.scheduleOnce()
but there is no real information where the "system" should come from. The documentation is a little bit superficial and there was a lot of change (akka moved out of core scala).
If I write
val system = akka.actor.ActorSystem("system")
I will have a ActorSystem, but it will be a new independent ActorSystem with around 8 new threads. I think, that this is an overkill for a small scheduler and not really recommended.
How can I just re-use the existing system of play framework 2 ?
Thanks
To get hands on the default actor system defined by Play you have to import the play.api.libs.concurrent.Akka helper.
Akka.system will be a reference to the default actor system, and then you can do everything with it as you would do with an actor system created by yourself:
import play.api.libs.concurrent.Akka
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")
Akka.system.scheduler.scheduleOnce(...)
update:
The above static methods became deprecated in Play 2.5 and was removed in 2.6, so now you have to use dependency injection.
In Scala:
class MyComponent #Inject() (system: ActorSystem) {
}
In Java:
public class MyComponent {
private final ActorSystem system;
#Inject
public MyComponent(ActorSystem system) {
this.system = system;
}
}
When you use play.api.libs.concurrent.Akka you are using the actor system created by play. In fact that is the way encouraged.
You can read that in the documentation.