Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Scalaz integration for Play 2.0

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 project
Octocat-spinner-32 src
Octocat-spinner-32 .gitignore
Octocat-spinner-32 LICENSE
Octocat-spinner-32 README.md
Octocat-spinner-32 build.sbt
README.md

Scalaz integration for Play 2.0

Instalation

Add play-scalaz to your project/Build.scala file

val appDependencies = Seq(
  "eu.teamon" %% "play-scalaz" % "0.1.2-SNAPSHOT"
)

val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
  resolvers += "scalajars repo" at "http://scalajars.org/repository"
)

Features

Json deserialization

Play's default json API:

trait Reads[A] {
  def reads(js: JsValue): A
}


someJson.as[A]    // A or Exception
someJson.asOpt[A] // Option[A]

will throw exception in case of invalid json input, or when using asOpt will return Option[A] which contains no information about what went wrong.

play-scalaz provides

trait Readz[A] {
  def reads(js: JsValue): Validation[NonEmptyList[String], A]
}

case class Foo(a: Int, b: String)

implicit val FooReadz = readz2("a", "b")(Foo)


fromJson[Foo](someJson) // Validation[NonEmptyList[String], Foo]

which will return either the value or list of errors

Promise Monad

Let's say there is code like:

def authenticate(code: String): Promise[Option[Projects]] = requestAccessToken(code).flatMap { tokenOpt =>
  tokenOpt.map { token => 
    requestAccessToken(token).flatMap { userOpt =>
      userOpt.map { user =>
        requestProject(user)
      } getOrElse Promise.pure(None)
    }
  } getOrElse Promise.pure(None)
}

def requestAccessToken(code: String): Promise[Option[String]]
def requestUserInfo(accessToken: String): Promise[Option[UserInfo]]
def requestProjects(user: UserInfo): Promise[Option[Projects]]

it gets even more bloated when number of calls grows. But with Promise being Monad:

def authenticate(code: String): Promise[Option[UserInfo]] = (for {
  accessToken <- OptionT(requestAccessToken(code))
  userInfo    <- OptionT(requestUserInfo(accessToken))
  projects    <- OptionT(requestProject(userInfo))
} yield projects).run

profit!

Something went wrong with that request. Please try again.