Extension for create a Rails like routes for http://spray.io/
Api doc: doc
Example: blog
Library add a resource, match0, get0, post0, delete0, put0, root
route directives.
In Build.scala
"com.github.fntzr" %% "spray-routing-ext" % "0.2.3" // For scala 2.10
"com.github.fntzr" %% "spray-routing-ext" % "0.3.3" // For scala 2.11
Also you need add into you Build.scala
file akka
, spray-can
, and
spray-routing
or spray-routing-shapeless2
for scala2.11.
Also version 0.3.3 require shapeless 2.1.0
in scope.
import com.github.fntzr.spray.routing.ext._
trait ApplicationRouteService extends Routable {
def route = ....
}
In package defined a get0
, post0
, delete0
, and put0
methods for handle request by Get, Post, Delete or Put http method.
//routes
get0[Controller]("path") ~ // GET http://example.com/path
get0[Controller]("path-name" ~> "controllerAction") ~ // GET http://example.com/path-name
delete0[Controller](("delete-path" / IntNumber) ~> "anotherAction") // DELETE http://example.com/delete-path/1
//in controller:
trait Controller {
def path = { }
def controllerAction = { ... }
^^^^
without arguments
def anotherAction(num: Int) = { ... }
^^^^^^^^^^
IntNumber
}
This is a match0
, root
and scope
methods.
math0
- used for define routes for few methods togetherroot
- just alias for `get0[Controller]("/" ~> "action")scope
- define routepath
with nested block, all url paths will be start withpath
match0[Controller]("path-name") ~ // GET example.com/path-name
match0[Controller]("another-path" ~> "action", List(GET, DELETE) ~ // GET | DELETE example.com/another-path
root[Controller]("action") // GET example.com/
scope("scope") {
get0[Controller]("get") // GET example.com/get
}
In Rails framework resource
it's a set routes (index
, show
, edit
, create
, update
, delete
, new
) which operate a Model
.
All urls will be started with /model/
. Example:
case class Model(title: String, description: String)
trait Controller {
def index = ...
def show(title: String) = ...
def edit(title: String) = ...
def create(model: Model) = ...
def update(title: String) = ...
def delete(title: String) = ...
def fresh = ... // it's a `new` path
}
//route
resource[Controller, Model](Segment)
^^^^^^^^^
define subroute, by default subroute is a IntNumber
This code generate urls:
GET example.com/model/index
GET example.com/model/post-title
GET example.com/model/post-title/edit
POST example.com/model/
PUT example.com/model/post-title
DELETE example.com/model/post-title
GET example.com/model/new
In resource
you might exclude unnecessary methods, or define nested block, and you might define own separator
Controllers it's only scala traits. When spray-routing-ext generate code inherited from you Controller, and you might use in a controller
predefined value - request: spray.http.HttpRequest
, but you might explicitly extends BaseController
, which contain one abstract method.
trait MyController extends BaseController {
def myAction = {
val headers = request.headers
...
}
}
Sometimes you need according to Accept
header send request with right Content-Type
def method = {
val accept = ... // extract from request Accept header
if accept is a html
complete ...
else if accept is a json and request with ajax
complete ...
else
reject
}
Now possible reduce the code
trait MyController extends BaseController with RespondToSupport {
def method = {
respondTo {
case `text/html` => <html><body>....</body></html>
case `application/json` if isAjax => """ { json: "ok" } """
}
}
}
Now, when we request content with Accept: text/html
will be got a <html><body>....</body></html>
response,
when we request content with Accept: application/json
with ajax, will be got """ { json: "ok" } """
,
otherwise will be got 406 Not Acceptable
Response Error.
spray-routing-ext
adds a postForm
method:
case class Model(id: Int, title: String)
postForm[Controller, Model]("action")
postForm[Controller, Model]("post-path" ~> "anotherAction", exclude("id")
// in controller
trait Controller {
def action(model: Model) = ...
^^^^^^^^^^^^^^
got a Model instance
def anotherAction(map: Map[String, Any]) = ....
^^^^^^^^^^^^^^^^^^^^^^^^
got a Map, because we excluded `id` attribute
}
Often need a pass into controllers some values (bd connection, actor path, predefined values...)
It's a simple:
trait RouteService extends Routable {
def route(db: ActorRef, render: Render) = { // method take a `db` connection and `renderer`
resource[PostController, Post]
}
}
class MyService extends Actor with RouteService {
val db = ...
val render = ....
def receive = runRoute(route(db, render))
^^^^^^^^^^^^^^^^^^^^^
pass `db` connection and `renderer`
}
trait Injection {
val db: ActorRef
val render: Render
}
//then into PostController
trait PostController extends BaseController with RespondToSupport with Injection {
^^^^^^^^^^^^
....
}
When application srart, in PostController possible use a db
and render
.
import com.github.fntzr.spray-routing-ext._
trait MyRoutes extends Routable {
val route = resource[PostController, Post] {
pathPrefixt("foo") {
get {
complete{"foo"}
}
}
} ~ get0[OtherController]("route") ~
post0[Controller0](("foo" / IntNumber) ~> "action") ~
match0[Controller0]("bar", List(GET, POST, PUT)) ~
resource[ModelController, Model] ~
root[PostController]("index")
}
trait PostController extends BaseController {
def index = {
complete("index")
}
def show(id: Int) = {
complete(s"show:$id")
}
//others...
}
My post about: spray-routing-ext: Extend spray-routing
Copyright (c) 2014-2015 fntzr [email protected]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.