found : akka.http.scaladsl.server.StandardRoute [error] required: scala.util.Try - scala

I am new to Scala and to akka i am trying to publish endpoint. Following compilation error is occurring.
found: akka.http.scaladsl.server.StandardRoute
[error] required: scala.util.Try[Option[com.activegrid.entities.AuthSettings]] => (akka.http.scaladsl.server.RequestContext => scala.concurrent.Future[akka.http.scaladsl.server.RouteResult])
Case class
case class AuthSettings(authType:String,authLevel:String,scope:String);
Enpoint
pathPrefix("config") {
path("settings"/"auth") {
post {
entity(as[AuthSettings]) { authSettings =>
val save: Future[AuthSettings] = persistance.persistAuthSettings(authSettings)
onComplete(save) {
complete("To insert app settings")
}
}
}
}
persistAuthSettings definition
def persistAuthSettings(authSettings: AuthSettings) : Future[AuthSettings] = Future {
//Neo4j Operations
authSettings;
}
What is going wrong in my code?

onComplete extracts the value from the future, and requires a function which operates on this value:
onComplete(save) { appSettings =>
complete("To insert app settings")
}

Related

required: play.api.mvc.Request[?] => play.api.mvc.Result

I am migrating to Play 2.6 and have the following API wrapper functions that used to work:
trait API {
self: Controller =>
def api(businessLogic: Request[AnyContent] => Any): Action[AnyContent] = apiWithBody(parse.anyContent)(businessLogic)
def apiWithBody[A](bodyParser: BodyParser[A])(businessLogic: Request[A] => Any): Action[A] = Action(bodyParser) {
implicit request =>
{
val apiResult = businessLogic(request)
val start = new java.util.Date().getTime
val actionDuration = (new java.util.Date().getTime - start)
val response = resultFrom(apiResult, request, actionDuration) // Returns a Result
response
}
}
}
Called by Controller functions like:
object Accounts extends Controller with API {
def all = superUser {
implicit principal =>
api {
request =>
models.Account.all
}
}
}
Where superUser is the principal (user) type "admin".
And get the following compiler error:
[error] type mismatch;
[error] found : play.api.mvc.Action[play.api.mvc.AnyContent]
[error] required: play.api.mvc.Request[?] => play.api.mvc.Result
[error] api {
[error] ^
I'm building with sbt 1.1.5 and Scala 2.11.8.
I am guessing the [?] means the compiler doesn't know what type is required but I don't understand what is wrong. I have searched for this issue but not found the specific answer for this problem.
In addition I'm getting an error:
[error] could not find implicit value for parameter parser: play.api.mvc.BodyParser[Any]
[error] def all = superUser {
[error] ^
that I posted as a separate issue (see could not find implicit value for parameter parser: play.api.mvc.BodyParser[Any]) but might be relevant here?
def superUser[A](f: => Principal => Request[A] => Result)(implicit parser: BodyParser[A]): SecureAction[A] = {
_superUser {
user =>
implicit val principal = data.Principal(user)
Action(parser)(request => f(principal)(request))
}
}
private def _superUser[A](action: String => Action[A]) = {
play.api.mvc.Security.Authenticated(getSuperUser, onUnauthorized)(action)
}
Any help would be appreciated.
Sorry I'm little bit confused here about the architecture as:
Where is the API call? Is it within the model? Are you calling outside the current Play app? Why don't you use the Future API for it? Because then you can recover it. Which then help you with logging and error handling.
The all method get the request, and then it does not return an HTTP response. Why don't you pass on what you need from the request (e.g., the Cookie).
I think the answer to your question is to use your action composition with action. Something like:
def myMethod(queryParam: String) = myDefinedAction compose Action { ??? }
//In case you want to use the Future API, then you need to be async
def myMethod(queryParam: String) = (myDefinedAction compose Action).async {
implicit request =>
apiCall.map{
case _ => Ok("good request")
}.recover{case _ => BadRequest}
}

Scala Future strange compile error

Code below is a simplified version of the real code. We "inherited" the domain model case object FutTest and case class FutTest, which we can't modify. The actual domain models are served from a Database, so I believe the Future approach is valid, but it causes problems which I don't understand.
import org.scalatest.FunSpec
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
case object FutTest {
def create(sz: Int) = { FutTest(sz) }
}
case class FutTest(size: Int)
class FutureTest extends FunSpec {
def one(v: Int): Future[FutTest] = {
Future { FutTest.create(v) }
}
def two(t: FutTest) = {
Future { FutTest.create(t.size) }
}
def compileError1: Future[FutTest] = {
one(10).map(f => two(f))
}
def compileError2: Future[FutTest] = {
for { o <- one(10) } yield (two(o))
}
}
The error messages:
[INFO] Using incremental compilation
[INFO] Compiling 7 Scala sources and 5 .. target/test-classes...
[ERROR] domain.FutureTest.scala:25: type mismatch;
found : scala.concurrent.Future[domain.FutTest]
required: domain.FutTest
[ERROR] one(10).map(f => two(f))
[ERROR] ^
[ERROR] domain/FutureTest.scala:29: type mismatch;
found : scala.concurrent.Future[domain.FutTest]
required: domain.FutTest
[ERROR] for { o <- one(10) } yield (two(o))
I tried the above code with plain Int instead of FutTest and all is fine. Why is the compiler complaining and how can we solve this without touching the existing domain.
flatMap is what you want.
one(10).flatMap(f => two(f))
or
one(10).flatMap(two)
Using for comprehension,
for { o <- one(10); t <- two(o) } yield t
One() returns a Future and two() also returns a Future so you need to flatMap instead of map. When you map to two(), your result is Future[Future[FutTest]] and needs to be flattened.
Doing
one(10).flatMap(f => two(f))
should do the trick.

Mockito with Dependency Injection

I'm using Play Framework 2.5 and trying to test one of my DAO class based on the example here.
But my class under test has dependency injection and I wonder how to mock it.
I tried to do something but it seems a bit clumsy, and I would like help to improve it.
Here is my code :
class MyController #Inject()(val mydao: MyDAOClass) extends Controller {
def getData = Action { request =>
mydao.fetchData
}
}
class MyDAOClass #Inject()(ws: WSClient) {
def urls(): List[String] = { List("url1", "url2") }
// fetch data on different servers and should merge it.
def fetchData(): Future[List[String]] = {
val futures: List[Future[WSResponse]] = urls map { url =>
ws.url(url + "/some/data").withRequestTimeout(10000.millis).get()
}
futures map { future =>
future onComplete {
case Success(resp) => println(resp.json)
case Failure(t) => println("An error has occured: " + t.printStackTrace)
}
}
Future(List())
}
}
Here is my test code :
trait DAOTrait {
def urls: List[String]
}
class MyDAOClass extends PlaySpec with MockitoSugar {
"MyDAOClass" should {
"get a list of data" in {
Server.withRouter() {
case GET(p"/url1/some/data") => Action {
Results.Ok(Json.arr(Json.obj("name" -> "data1")))
}
} { implicit port =>
val mockMyDAOClass = mock[DAOTrait]
when(mockMyDAOClass.urls) thenReturn List("url1")
implicit val materializer = Play.current.materializer
WsTestClient.withClient { client =>
val mydao = new MyDAOClass(client) {
override def urls = mockMyDAOClass.urls
}
val result = Await.result(
mydao.fetchData(), 10.seconds)
result mustEqual List("data1")
}
}
}
}
}
The code is not finished in MyDAOClass, but it is enough to start implementing tests.
1) How to mock class that have dependency injection ?
2) When testing this code I have the following exception in MyDAOClass case Failure(t)
java.net.ConnectException: http://localhost:40183
at org.asynchttpclient.netty.channel.NettyConnectListener.onFailure(NettyConnectListener.java:137)
at org.asynchttpclient.netty.request.NettyChannelConnector$1.onFailure(NettyChannelConnector.java:106)
at org.asynchttpclient.netty.SimpleChannelFutureListener.operationComplete(SimpleChannelFutureListener.java:28)
at org.asynchttpclient.netty.SimpleChannelFutureListener.operationComplete(SimpleChannelFutureListener.java:20)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:683)
at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:604)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:564)
at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:425)
at io.netty.channel.nio.AbstractNioChannel.doClose(AbstractNioChannel.java:462)
at io.netty.channel.socket.nio.NioSocketChannel.doClose(NioSocketChannel.java:236)
at io.netty.channel.AbstractChannel$AbstractUnsafe.doClose0(AbstractChannel.java:611)
at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:590)
at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:534)
at io.netty.channel.nio.NioEventLoop.closeAll(NioEventLoop.java:576)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:361)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.nio.channels.ClosedChannelException
but it should return Result.Ok instead.
3) Any advice welcome.

Play Scala Framework : type mismatch scala.concurrent.Future[Object] [error] required: scala.concurrent.Future[play.api.mvc.Result]

I have one compilation error that I cannot solved yet. It's about an action adding a new patient into mongo if he is not already in the database. First the model :
case class PatientData(id : String)
object PatientData {
implicit val PatientDataFormat = Json.format[PatientData]
}
The function searching the patient in mongo :
def findPatientById(mode : String, id : String) : Future[Option[PatientData]] = {
val collection = getPatientCollection(mode)
collection.find(Json.obj("id" -> id)).one[PatientData]
}
The Play action :
def create(patientId: String) = Action.async(parse.json) { request =>
val token = "dummy"
isAuthorized(token) match { // always return Some(thing)
case None => Future.successful(Unauthorized("Invalid token " + token))
case Some(_) =>
request.body.validate[PatientData] map {
patientData =>
findPatientById(mode,patientId) map { finded =>
finded match {
case Some(_) => Future.successful(NotAcceptable("The patient is already exist."))
case None =>
Logger.info("Create the patient .. ")
Future.successful(Created)
}
}
} getOrElse {
Future.successful(BadRequest)
}
}
I know that I can solve this problem using a call to Await.result in the function findPatientById but I want avoid this solution and let the Future doing his job. The problem is that I get a compilation error :
[error] /home/afk/git/bioserenity/bioserenity-backend/app/controllers/MedataController.scala:90: type mismatch;
[error] found : scala.concurrent.Future[Object]
[error] required: scala.concurrent.Future[play.api.mvc.Result]
[error] } getOrElse {
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
Anyone have an idea to solve this issue ?
You should probably try to use
findPatientById(mode,patientId) flatMap { ...
instead of original line. Here, the map call is replaced by flatMap so that the instance returned by that block of code is Future[Something] rather than Future[Future[Something]].

Scala Compilation Error on Vert.x

I'm not a Scala Expert. I just want to run a simple example Verticle on Vert.x.
class ScalaServer extends Verticle {
override def start() {
vertx.setPeriodic(1000, { timerId: Long =>
vertx.eventBus.publish("news-feed", "News from Scala")
})
}
}
But when I run this code on Vert.x the compiler complains with the following message:
error: type mismatch;
found : scala.Long => org.vertx.java.core.eventbus.EventBus
required: org.vertx.java.core.Handler[java.lang.Long]
vertx.setPeriodic(1000, { timerId: Long =>
^
Maybe there is someone out there who sees the error right away.
found : scala.Long => org.vertx.java.core.eventbus.EventBus
required: org.vertx.java.core.Handler[java.lang.Long]
Try follow:
class ScalaServer extends Verticle {
override def start() {
vertx.setPeriodic(1000, new Handler[java.lang.Long]() {
def handle(timerID: java.lang.Long) = {
vertx.eventBus.publish("news-feed", "News from Scala")
}
});
}
}