Play'R stands for: Playing with Play and ReST.
It's a simple, uniform, and introspectable way to declare ReST APIs in play.
- simple
Just implements some traits and Play'R will do the routing for you.
- uniform
Play'R defines an uniform mapping from http methods to controller methods.
- introspectable
- the declared resources capabilities can be listed and used to generate documentation or ui connectors.
See the PlayR-swagger project as an example.
Warning
Play'R is a young project and the API is subject to change.
- Uses standard Play controllers
- Map HTTP verbs to controller methods via traits implementation.
- Resource routing and dependencies defined in Scala
- Introspection API allowing you to generate content from your defined ReST API
To use Play'R in your sbt based project, you should add a resolver for the 26lights public repository:
resolvers += "26Lights releases" at "http://build.26source.org/nexus/content/repositories/public-releases"
and add Play'R to your library dependencies:
libraryDependencies ++= Seq (
"26lights" %% "playr" % "0.4.0"
)
A working version of this example is located in the samples/playr-demo
project.
Just start it with sbt run
and try it with curl
or other HTTP tools.
Let's start with a simple read only resource that manages a list of person
import play.api.mvc._
import play.api.libs.json.Json
import twentysix.playr._
import twentysix.playr.simple._
case class SimplePerson(name: String)
object SimplePersonController extends Controller
with Resource[Person]
with ResourceRead {
def name = "person"
def persons = Map(
1 -> SimplePerson("john"),
2 -> SimplePerson("jane")
)
implicit val personFormat = Json.format[SimplePerson]
def fromId(sid: String): Option[SimplePerson] = toInt(sid).flatMap(persons.get(_))
def read(person: SimplePerson) = Action { Ok(Json.toJson(person)) }
def list() = Action { Ok(Json.toJson(persons.keys)) }
}
object SimplePersonRouter extends RestResourceRouter(SimplePersonController)
First, we define a case class that represents a person.
case class SimplePerson(name: String)
Next, we define a Play controller that implements two Play'R traits.
object SimplePersonController extends Controller
with Resource[Person]
with ResourceRead
The Resource
trait extends Controller, defines basic resource capabilities and it requires you to define:
name
a name that can be used by the router to access your resource
fromId
a method to retrieve your resource instance from an identifier (given in the URL)
The ResourceRead
trait defines that there is a way to read that resource; it requires you to define two methods:
list
respond to an http GET method on the resource's path, in this case, it returns the list of available id
read
respond to an http GET method on an identified resource, in this case, it returns the person object serialized as JSON.
Finally, we define a RestResourceRouter
instance that will route incoming requests for that resource.
object SimplePersonRouter extends RestResourceRouter(SimplePersonController)
The only missing step is to reference this router in Play's routes file.
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
-> /person controllers.SimplePersonRouter
To show how the router works, let's use curl
with some url.
$ curl -f http://localhost:9000/person
[1,2]
A simple http GET on the person resource returns the list of available ids as a json list. It's the result of the controller's list
method.
$ curl -f http://localhost:9000/person/1
{"name":"john"}
If we add a valid id to the URL, we get the JSON version of that resource. It's the result of the controller's read
method.
Let's try to find what methods our resource support:
$ curl -f -XOPTIONS -i http://localhost:9000/person
HTTP/1.1 200 OK
Allow: GET
Content-Length: 0
Let's try some erroneous requests.
First, a not supported method on the resource:
$ curl -f -XPOST http://localhost:9000/person
curl: (22) The requested URL returned error: 405 Method Not Allowed
$ curl -f -XPOST http://localhost:9000/person/1
curl: (22) The requested URL returned error: 405 Method Not Allowed
Returns the expected «method not supported» code, both for the resource itself and the identified resource.
$ curl -f http://localhost:9000/person/5
curl: (22) The requested URL returned error: 404 Not Found
There are only two existing person resource, id 5 is invalid, so it returns «not found»
A more complete documentation, showing all supported HTTP methods, and more complex routing with sub-resources is available in the Play'R documentation
The associated code is in the samples/playr-tutorial
project.
Play'R can already be used to develop ReST API, but it's only a starting point and a lot more is left to do, like:
- Use objects for HTTP verbs instead of strings
- Multiple HTTP method per action
- Routing configuration DSL
- Reverse routing
- Resource type introspection
- Transactional router