Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need plain english translation of the following scala snippet

Tags:

scala

I'm new to scala and the playframework. Can somebody please translate the following snippet below into plain english? For context its found here: http://www.playframework.org/documentation/2.0.4/ScalaSecurity

/**
 * This method shows how you could wrap the withAuth method to also fetch your user
 * You will need to implement UserDAO.findOneByUsername
 */
def withUser(f: User => Request[AnyContent] => Result) = withAuth { username => implicit request =>
  UserDAO.findOneByUsername(username).map { user =>
    f(user)(request)
  }.getOrElse(onUnauthorized(request))
}
like image 736
critium Avatar asked Nov 30 '12 22:11

critium


1 Answers

Part 1: First let's address the curried syntax:

withUser is a method that takes a curried function f of type User => Request[AnyContent] => Result. It takes a User object and returns another function that takes a Request and returns a Result. Breaking it down, if f is that function then:

val g = f(user) // g is a function
val result = g(request) // returns a result
// same as:
val result = f(user)(request)

Practically speaking f is just like a function that takes two parameters but instead of calling f(a, b) you call f(a)(b).

withAuth is also a method that takes a curried function. It has almost the same type as withUser.

Part 2: Now how do you use those methods:

As explained here, play makes you defined your application logic by telling it how to transform Request objects into Result objects.

withAuth is a helper function that takes care of the authentication for you and conveniently retrieves the username. So you use it like this:

def index = withAuth { username => implicit request =>
  Ok(html.index(username))
}

It returns a function that takes a Request and returns a Result, which is what play needs. But what it takes is a curried function (that takes a username) and return a function (that takes a request). The request parameter is marked as implicit so it can be passed implicitly to any function/method call that needs an implicit request parameter. For the purpose of this explanation, just ignore the implicit keyword.

Part 3: Translation of withUser

Well, its signature is similar to withAuth and the goal is for it to be used in the same way except the first parameter will be a User instead of a String. So it has to take a User => Request => Result. The request trait takes a type parameter which indicates the type of its content. Here it is AnyContent. So the correct type for the argument of withUser is User => Request[AnyContent] => Result. That means you will be able to use it like this:

withUser { user => implicit request =>
  // do something with user and request to return a result
}

If you look at the definition of withUser, all it does is to call withAuth:

def withUser(f: User => Request[AnyContent] => Result) = withAuth { 
  // ...
}

So it will return the same type as withAuth which means it will return a function that turns a Request into a Result (see Part 2 above). Which means we will be able to use it like this:

def index = withUser { user => implicit request => 
  Ok(html.index(user))
}

What is passed as an argument of withAuth is a curried function. I introduced intermediate val so that you can follow the types:

username => // first param is the username as a String
  implicit request => // second param is the request
    // here we have to return a Result...
    // we lookup the user - we may not have one:
    val userOption: Option[User] = UserDAO.findOneByUsername(username)
    // f is the code block that will be provided inside withUser { f }
    // Part 1 explains the f(user)(request) syntax
    // We call f to get a result, in the context of the Option monad
    val resultOption: Option[Result] = userOption.map(user => f(user)(request))
    // if we have a result, return it; otherwise return an error.
    resultOption.getOrElse(onUnauthorized(request))
like image 168
huynhjl Avatar answered Sep 22 '22 15:09

huynhjl