Created
May 17, 2013 09:01
-
-
Save leon/5597895 to your computer and use it in GitHub Desktop.
MongoResourceController, simplifying working with restful data using Reactive Mongo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package controllers | |
import play.api.mvc._ | |
import play.api.libs.json._ | |
import reactivemongo.bson._ | |
import models._ | |
import extensions._ | |
import extensions.JsonTransforms._ | |
import scala.concurrent.ExecutionContext.Implicits.global | |
class MongoResourceController[R](implicit format: Format[R], collection: MongoCollection[R]) extends ResourceRouter[String] { | |
def list: EssentialAction = Action { implicit request => | |
val f = collection.find() | |
Async { | |
f.map { users => | |
Ok(Json.toJson(users)) | |
} | |
} | |
} | |
def show(id: String): EssentialAction = Action { implicit request => | |
val userFuture = collection.findById(id) | |
Async { | |
userFuture.map { userOpt => | |
userOpt.map { user => | |
Ok(Json.toJson(user)) | |
} getOrElse { | |
NotFound(s"User with id: $id") | |
} | |
} | |
} | |
} | |
def create: EssentialAction = update(BSONObjectID.generate.stringify) | |
def update(id: String) = Action(parse.json) { request => | |
request.body.validate(setObjectId(id) andThen format).fold( | |
invalid = e => BadRequest(JsError.toFlatJson(e)), | |
valid = { validModel => | |
Async { | |
collection.update(id, validModel).map { lastError => | |
Created(Json.toJson(validModel)) | |
} | |
} | |
} | |
) | |
} | |
def remove(id: String): EssentialAction = Action { implicit request => | |
Async { | |
collection.remove(id).map { lastError => | |
if (lastError.ok) Ok else InternalServerError(lastError.toString) | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package controllers | |
import play.api.mvc._ | |
import play.core.Router | |
import scala.runtime.AbstractPartialFunction | |
trait ResourceController[T] extends Controller { | |
def list: EssentialAction | |
def create: EssentialAction | |
def show(id: T): EssentialAction | |
def update(id: T): EssentialAction | |
def remove(id: T): EssentialAction | |
} | |
trait Routes { | |
def routes: PartialFunction[RequestHeader, Handler] | |
def documentation: Seq[(String, String, String)] | |
def setPrefix(prefix: String) | |
def prefix: String | |
} | |
abstract class ResourceRouter[T](implicit idBindable: PathBindable[T]) extends Router.Routes with ResourceController[T] { | |
private var path: String = "" | |
def setPrefix(prefix: String) { | |
path = prefix | |
} | |
def prefix = path | |
def documentation = Nil | |
def routes = new AbstractPartialFunction[RequestHeader, Handler] { | |
private val MaybeSlash = "/?".r | |
private val Id = "/([^/]+)/?".r | |
def withId(id: String, action: T => EssentialAction) = idBindable.bind("id", id).fold(badRequest, action) | |
override def applyOrElse[A <: RequestHeader, B >: Handler](rh: A, default: A => B) = { | |
if (rh.path.startsWith(path)) { | |
(rh.method, rh.path.drop(path.length)) match { | |
case ("GET", MaybeSlash()) => list | |
case ("POST", MaybeSlash()) => create | |
case ("GET", Id(id)) => withId(id, show) | |
case ("PUT", Id(id)) => withId(id, update) | |
case ("PATCH", Id(id)) => withId(id, update) | |
case ("DELETE", Id(id)) => withId(id, remove) | |
case _ => default(rh) | |
} | |
} else { | |
default(rh) | |
} | |
} | |
def isDefinedAt(rh: RequestHeader): Boolean = { | |
if (rh.path.startsWith(path)) { | |
(rh.method, rh.path.drop(path.length)) match { | |
case ("GET", MaybeSlash()) => true | |
case ("POST", MaybeSlash()) => true | |
case ("GET", Id(id)) => true | |
case ("PUT", Id(id)) => true | |
case ("PATCH", Id(id)) => true | |
case ("DELETE", Id(id)) => true | |
case _ => false | |
} | |
} else { | |
false | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-> /api/user controllers.Users | |
GET /assets/*file controllers.Assets.at(path="/public", file) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package models | |
import play.api.libs.json._ | |
import play.api.libs.functional.syntax._ | |
import reactivemongo.bson.BSONObjectID | |
import play.modules.reactivemongo.json.BSONFormats.BSONObjectIDFormat | |
import play.api.Play.current | |
case class User( | |
email: String, | |
firstName: String, | |
lastName: String, | |
id: Option[BSONObjectID] | |
) { | |
val name = s"$firstName $lastName" | |
} | |
object User { | |
implicit val format = Json.format[User] | |
implicit object collection extends MongoCollection[User] { | |
def name = "users" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package controllers | |
import play.api.mvc._ | |
import models._ | |
object Users extends MongoResourceController[User] { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment