I came across this issue already a couple of times and I wonder what the Lift-way is to perform such an action. Of course I could do my own error handling etc. but basically I wonder how I can turn a Box[Elem] into a LiftResponse. Ideally an XmlResponse of course.
The scenario is that I am using the RestHelper for an API and I have a function that returns me a Box[Elem]. I would like to make use of the async support.
The error I get is that Box[Elem] (or Box[NodeSeq], Box[Node]) cannot be converted to LiftResponse. However the exact same code without using RestContinuation works.
Note: I do not want Lift to do any template processing logic. Just output the XML the same way it would happen without using RestContinuation.
val userId = S.param("userId") map { _.toInt }
RestContinuation.async {
reply => {
reply(
for {
user <- userRepo.select(userId) ?~ "No such user." ~> 404
} yield {
<user>
<name>{user.name}</name>
</user>
}
)
}
}
I think there is an implicit declaration missing. You can bring this implicit (implicit def canNodeToResponse(in: Box[Seq[Node]]): LiftResponse in scope by mixing-in the trait XMLApiHelper in the surrounding class.
Related
I'm still learning scala so this might be a question with an easy answer, but I've been stuck on writing a single method over and over for almost a day, unable to get this code to compile.
I'm playing with the Play Framework and a reactive mongo template to learn how Scala and Play work.
I have a controller with a few methods, endpoints for a REST service.
The issue is about the following method, which accepts a list of json objects and updates those objects using the mongo reactive driver. The class has one member, citiesFuture which is of type Future[JSONCollection].
The original class code which I'm adding this method to can be found here for context: CityController on github
def updateAll() = Action.async(parse.json) { request =>
Json.fromJson[List[City]](request.body) match {
case JsSuccess(givenCities, _) =>
citiesFuture onComplete[Future[Result]] { cities =>
val updateFutures: List[Future[UpdateWriteResult]] = for {
city <- givenCities
} yield cities.get.update(City.getUniqueQuery(city), Json.obj("$set" -> city))
val promise: Promise[Result] = Promise[Result] {
Future.sequence(updateFutures) onComplete[Result] {
case s#Success(_) =>
var count = 0
for {
updateWriteResult <- s.value
} yield count += updateWriteResult.n
promise success Ok(s"Updated $count cities")
case Failure(_) =>
promise success InternalServerError("Error updating cities")
}
}
promise.future
}
case JsError(errors) =>
Future.successful(BadRequest("Could not build a city from the json provided. " + Errors.show(errors)))
}
}
I've managed to get this far with alot of trial and error, but I'm starting to understand how some of the mechanics of scala and Futures work, I think :) I think I'm close, but my IDE still gives me a single Inspection error just at the single closing curly brace above the line promise.future.
The error reads: Expression of type Unit doesn't conform to expected type Nothing.
I've checked the expected return values for the Promise and onComplete code blocks, but I don't believe they expect Nothing as a return type.
Could somebody please explain to me what I'm missing, and also, I'm sure this can be done better, so let me know if you have any tips I can learn from!
You're kinda on the right track but as #cchantep said, once you're operating in Future-land, it would be very unusual to need to create your own with Promise.future.
In addition, it's actually quite unusual to see onComplete being used - idiomatic Scala generally favors the "higher-level" abstraction of mapping over Futures. I'll attempt to demonstrate how I'd write your function in a Play controller:
Firstly, the "endpoint" just takes care of one thing - interfacing with the outside world - i.e. the JSON-parsing part. If everything converts OK, it calls a private method (performUpdateAll) that actually does the work:
def updateAll() = Action.async(parse.json) { request =>
Json.fromJson[List[City]](request.body) match {
case JsSuccess(givenCities, _) =>
performUpdateAll(givenCities)
case JsError(errors) =>
Future.successful(BadRequest("Could not build a city from the json provided. "))
}
}
Next, we have the private function that performs the update of multiple cities. Again, trying to abide by the Single Responsibility Principle (in a functional sense - one function should do one thing), I've extracted out updateCity which knows how to update exactly one city and returns a Future[UpdateWriteResult]. A nice side-effect of this is code-reuse; you may find you'll be able to use such a function elsewhere.
private def performUpdateAll(givenCities:List[City]):Future[Result] = {
val updateFutures = givenCities.map { city =>
updateCity(city)
}
Future.sequence(updateFutures).map { listOfResults =>
if (listOfResults.forall(_.ok)) {
val count = listOfResults.map(_.n).sum
Ok(s"Updated $count cities")
} else {
InternalServerError("Error updating cities")
}
}
}
As far as I can tell, this will work in exactly the same way as you intended yours to work. But by using Future.map instead of its lower-level counterpart Future.onComplete and matching on Success and Failure you get much more succinct code where (in my opinion) it's much easier to see the intent because there's less boilerplate around it.
We still check that every update worked, with this:
if (listOfResults.forall(_.ok))
which I would argue reads pretty well - all the results have to be OK!
The other little trick I did to tidy up was replace your "counting" logic which used a mutable variable, with a one-liner:
var count = 0
for {
updateWriteResult <- s.value
} yield count += updateWriteResult.n
Becomes:
val count = listOfResults.map(_.n).sum
i.e. convert the list of results to a list of integers (the n in the UpdateWriteResult) and then use the built-in sum function available on lists to do the rest.
As I am gathering experiences with Spray.io I see that there is more ways how to solve the task. I found a various opinions which were sometimes contradictory. So I would like to ask more experienced users to share their view.
Essentially having a REST api and separated services layer all assembled via cake pattern as follows:
object Main extends App with BootedCore with ServiceActors with RestApi with Web
ServiceActors are holding an ActorRefs to various services and RestApi holds Spray-routes. Service actors replies with case classes.
The question is how to connect those two layers?
** Possibility 1 - Use akka ask pattern**
import scala.concurrent.ExecutionContext.Implicits.global
//TODO: Excecution context - this is not scalable
val adServiceRoute: Route = {
path("service" / "import" / "status") {
get {
respondWithMediaType(`text/plain`) {
complete {
adImporterService.ask(GetImportStatus)(1 second).mapTo[StatusOfImport]
}
}
}
}
}
implicit val importStatusMarshaller: Marshaller[StatusOfImport] =
Marshaller.of[StatusOfImport](ContentTypes.`text/plain`) { (value, contentType, ctx) =>
val string = "Hello marshalled status"
ctx.marshalTo(HttpEntity(contentType, string))
}
I have found some Cons to this solution which I would like to get clarified.
- various blogs clams that ask pattern is best to avoid if possible, some example reasoning: e.g. it hides underlying errors etc.
- not sure on which ExcecutionContext to run. Import global is definitively the correct one. What I have available is ActorSystem. Is it common to configure separated dispatcher just for this purpose?
Possibility 2 - use tell
I tried to rewrite the previous one but wasn't able to make it work
val adServiceRoute: Route = {
path("service" / "ad" / "import" / "status") {
get {
respondWithMediaType(`text/plain`) (getServiceStatus)
}
}
}
implicit val importStatusMarshaller: Marshaller[StatusOfImport] =
Marshaller.of[StatusOfImport](ContentTypes.`text/plain`) { (value, contentType, ctx) =>
val string = "Hello marshalled status"
ctx.marshalTo(HttpEntity(contentType, string))
}
def getServiceStatus(ctx: RequestContext): Unit = {
adImporterService.tell(GetImportStatus , ctx.responder)
}
The issue here is that adImporterService's response is StatusOfImport which responder doesn't know how to handle. Creating an actor-per-request just for handling the response in order to transform it to HttpResponse seems to me as overkill.
I am clearly missing something important here.
Could someone more experienced clarify ?
I think you can use spray's onComplete directive. For example:
onComplete(adImporterService.ask(GetImportStatus).mapTo[StatusOfImport]) {
case Success(v) => complete(v)
case Failure(e) => ...
}
I find myself repeating simple try/catch blocks that should, IMO, be 1-liners.
For example, let's say I need to convert a uri string date in yyyymmdd format to Joda-Time. With a standard try/catch block the conversion method looks like:
def ymd2Date(ymd: Option[String]) = ymd match {
case Some(date) =>
try { Right( ymdFormat.parseDateTime(date) ) }
catch { case e =>
log.info(e.getMessage)
Left(None)
}
case None =>
Left(None) // no uri date param
}
val ymdFormat = DateTimeFormat.forPattern("yyyyMMdd")
Works well enough, intent is clear, but when I do this kind of try/catch logging for all non-critical events, then I seek a way to DRY it out. The search led me to this SO post on scala.util.control.Exception. Helpful, but it's still a bit difficult to grok/make it work in the way I'd like it to. In plain English I just want to say, "catch some-action get-result log-error-type".
So, I hacked this out based on the part of control.Exception I'm interested in (or understand to be useful):
class Catcher[T](f: => T) {
type Logger = (=> Any) => Unit
def either[T]( logger: => Logger ) = {
try { Right(f) }
catch { case e =>
logger(e.getMessage)
Left(None)
}
}
}
def catching[T](f: => T) = new Catcher(f)
And then use in place of try/catch like so:
catching( ymdFormat.parseDateTime(date) ) either log.info
Can add on option, a msg prefix, etc., but...it would probably be better to find a way to get control.Exception to work like the above, as the TypeSafe crew is going to produce code worlds better than I'll ever imagine writing.
Does anyone know how to create this kind of syntax using control.Exception where one can pass in a logger function by-name to be used in the catch block?
Would be great if there was a "use cases" for control.Exception, but I get the feeling this utility is for more advanced Scala devs
This should do what you want:
import scala.util.control.Exception
def log(logger: => Logger)(e: Throwable) = {
logger(e.getMessage)
None
}
Exception.allCatch withApply log(logger) apply Some(ymdFormat.parseDateTime(date))
But this kind of stuff is better handled by Scalaz Validation, in my opinion.
A quick example:
import scala.util.control.Exception._
def throwingStuff {
throw new Exception("Hello World!")
}
catching(classOf[Exception]).withApply{err => println(err.toString); None}.apply(Some(throwingStuff))
You can use withApply to override the application logic of the Catch class to do something such as writing to a log.
I've read about and experimented with the Scala 2.9 try...catch feature, and it has me thinking about possibilities. What would I actually use it for other than saving a couple of lines of code?
Scala 2.9 Final Release Notes
The use case is to be able to have generic error handling throughout your application. Let's say you want to handle all FileNotFoundExceptions in your application by sending an e-mail to an administrator. Previously, you'd have to do it like this:
// Globally
val fileNotFound: PartialFunction[Throwable, Unit] = {
case e: FileNotFoundException =>
// Create report and send the e-mail
}
// On each try-catch-block
try {
// Open file
}
catch {
case fnf: FileNotFoundException => fileNotFound(fnf)
}
Now you just do:
try {
// Open file
} catch fileNotFound
This also has the nice advantage that you can link several such exception handlers using the orElse method on partial functions:
val fileErrors = fileNotFound orElse endOfFile orElse invalidFormat
And then just use that everywhere where you need file exception handling. Such an error handler can be dynamically combined based on the configuration file for the application, for example. This is much less cumbersome than pattern matching everywhere and calling the correct handler.
One useful thing which could be pimped on top of partial functions is the andAlso operator, which acts as a sequencing operator on two partial functions. This would be useful when you want to do some error handling specific to a particular try-catch block after having done the generic error handling.
implicit def pf2ops(pf: PartialFunction[Throwable, Unit]) = new {
def andAlso(localpf: PartialFunction[Throwable, Unit]) = new PartialFunction[Throwable, Unit] {
def apply(t: Throwable) = {
if (pf.isDefinedAt(t)) pf(t)
localpf(t)
}
def isDefinedAt(t: Throwable) = pf.isDefinedAt(t) || localpf.isDefinedAt(t)
}
}
And then you can do this:
scala> try {
| throw new java.io.FileNotFoundException
| } catch fnf andAlso {
| case e: Exception => println("I don't know, but something is specific to this particular block.")
| }
I don't know, but something is specific to this particular block.
I guess you could play further with the exact semantics and the meaning (and the name) of andAlso.
Good answer by axel22, but I think the real reason for its introduction is something else. The try/catch/finally handling introduced a special case. You used a partial function literal, but you could not actually replace that with a partial function. Now, catch just receive a partial function, and one more special case in the language is gone.
As far as I know, we can't do this in Java. Can we do this in scala?
Suppose there is a method as following:
def insert(name:String, age:Int) {
// insert new user
}
Is it possible to get the parameter names name and age in scala?
UPDATE
I want to do this, because I want to bind the parameters of methods automaticlly.
For example, this is a web app, it has some actions defined as:
class UsersController extends Controller {
def create(name: String, age: Int) {
// insert the user
}
}
A client clicked the submit button of a creating-user form. The url will be /users/create and with some parameters sending.
On the server side, when we get a url named /users/create, we will find a method create in the controller UsersController, found one now. Then I have to get the parameter names of that method, then we can get the values of them:
val params = getParamsFromRequest()
val method = findMethodFromUrl("/users/create")
val paramNames = getParamNamesOfMethod(method)
val paramValues = getValues(params, paramNames)
// then invoke
method.invoke(controller, paramValues)
Now, the key is how to get the parameter names of a method?
It's still very much a work in progress, but you should be able to:
import scalaj.reflect._
for {
clazz <- Mirror.ofClass[UsersController].toSeq
method <- clazz.allDefs.find(_.name == "insert").toSeq
params <- method.flatParams
} yield params
Sorry about the toSeqs, they're to work around a known issue using Options in a for-comprehension.
Please don't push it too hard, it's still very young and fragile. I'm certainly not at the stage yet where I'd accept bug reports :)
UPDATE
Well... I know that I said I'm not accepting bug reports, but this one seemed so useful that I've pushed it up to github anyway.
To do the job dynamically (from a String class name):
import scalaj.reflect._
for {
clazz <- Option(Class forName "x.y.UsersController")
mirror <- Mirror.ofClass(clazz).toSeq
method <- mirror.allDefs.find(_.name == "insert").toSeq
params <- method.flatParams
} yield params
This question has some insight on how it is done in Java: Is there a way to obtain names of method parameters in Java?
Why not just using different method names (to reflect the parameters that may be passed)? Like, craeteWithNameAndAgeAndGender (pretty standard approach). You won't anyways be able to have multiple methods with the same names(/arity/parameter types and order) and just different parameter names - method overloading doesn't work this way.