Best way to have nested routing in scalatra?

846 views
Skip to first unread message

Isak Rickyanto

unread,
Aug 18, 2011, 10:53:00 PM8/18/11
to scalat...@googlegroups.com
Hi,

Is there any way to have nested routing in Scalatra which is like:

any("/users/*") => new UsersRouter any("/posts/*") => new PostsRouter any("/mail/*") => new MailRouter any("/downloads/*") => new DownloadsRouter

(I copied from circumflex)

I found on mailing list archive, that we can add new Servlet or use trait. But I wonder is there plan to have feature other than these solutions? Maybe similar concept like code above?
I tried to find Scalatra example code of multiple classes for routing, but couldn't find it. The example only shows 1 class for Controller which is not good way if we have a lot of routes.

--
Best regards,
Isak Rickyanto
----------------------
BeritaTeknologi.com

Carson McNeil

unread,
Aug 18, 2011, 11:37:05 PM8/18/11
to scalat...@googlegroups.com
I'm pretty new to this, but I'm pretty sure you can make multiple servlet classes, and just use the web.xml file to point different routes to different files.
Is this correct?
~Carson

Isak Rickyanto

unread,
Aug 18, 2011, 11:44:45 PM8/18/11
to scalat...@googlegroups.com
Yeah thanks Carson, but for me that solution is rather cumbersome and we must deal with xml so it is not easy as example code i paste before.

I just wish I can have better and easier solution to achieve this in Scalatra.

Leif Warner

unread,
Aug 18, 2011, 11:58:34 PM8/18/11
to scalatra-user
Good point, there's a decent amount of overlap over what you can route
in the web.xml verses what you can do in Scalatra.

Regarding nested routing, I've been looking at Spray, which pretty
much does the same thing as BlueEyes, kinda like JAX-RS:
https://github.com/spray/spray/wiki/Path-Filters

You can match against the beginning of the path, and then interior
matchers will match against the remaining parts of the path.

Sometimes, I want to have a some common functionality run for a given
sub-path, while still doing further path matching in there. Just
making more servlets/filters for those parts sounds like it'd work,
though the extra setup of more servlet classes might be annoying?

-Leif


On Aug 18, 8:37 pm, Carson McNeil <carson.mcn...@gmail.com> wrote:
> I'm pretty new to this, but I'm pretty sure you can make multiple servlet
> classes, and just use the web.xml file to point different routes to
> different files.
> Is this correct?
> ~Carson
>

Keith Irwin

unread,
Aug 18, 2011, 11:59:04 PM8/18/11
to scalat...@googlegroups.com
I run servlets via a stand alone app (with embedded jetty) so multiple servlets work well enough for me, but I'm also interested in hearing if there's another more idiomatic way to group routes in the way you're suggesting.

I'm even MORE interested in the 'any("/some/route/*")' thing you exampled.

I often have a few routes that don't require authentication, and then all the rest that do. So, I tend to have the following pattern:

  put("/context/something") { … }
  get("/context/something/else") { … }

  get("/*") {
    Auth.check
    pass
  }

  get("/context/public") { … }

Auth.check throws an exception caught by the error { } declaration. Works well enough, but the problem is that 'get("/*")' thing. I end up having to do something like the following if I have lots of verbs implemented:

  get("/*") { Auth.check ; pass }
  put("/*") { Auth.check ; pass }
  post("/*") { Auth.check ; pass }
  delete("/*") { Auth.check ; pass }

Seems kind of awkward. Using "before()" would work, but not for this particular case (when the routes can't really be disambiguated).

Anyway, surely I'm getting something wrong? But an any("/route") thing would be kind of cool.

Keith

Ross A. Baker

unread,
Aug 19, 2011, 10:18:28 AM8/19/11
to scalat...@googlegroups.com
Please open an issue for `any`, and we can add it. For now, you can
fake it. Untested, but something like:

def any(routeMatchers: RouteMatcher*)(action: => Any) = {
get(routeMatchers : _*)(action)
post(routeMatchers : _*)(action)
put(routeMatchers : _*)(action)
delete(routeMatchers : _*)(action)
}

--
Ross A. Baker
ba...@alumni.indiana.edu
Indianapolis, IN, USA

Ross A. Baker

unread,
Aug 19, 2011, 2:47:15 PM8/19/11
to scalat...@googlegroups.com
Mountable routers are definitely on our radar. Sinatra does not
provide us with a model in this case, but some of the other mentioned
frameworks do.

What exactly do want to support here? Simple prefix matching would be easy:

// Calls UserApp, strips /user off the path for prefix matching.
mount("/user", new UserRoutes)

To harness the full power of route matching is more complicated:

get("/user/*", Moon.phase == Full) { new UserRoutes with WerewolfSupport }

How exactly do we know to strip "/user" when calling UserRoutes? We
don't currently have a way to detect the "unconsumed" part of a URL,
nor even a definition of what the unconsumed part is. What do the
inner routes see if the outer matcher is "/user/*.jpg"? We'd need
some sort of (Request=>Request) decorator for the inner routes, and
detailed rules on how route matchers build up that decorator. More
powerful, but far more complicated. Worth it? I'm not sure.

Other alternatives to the multi-servlet workaround:

1) Create each set of routes as a trait, compose them: class MyApp
extends ScalatraServlet with UserRoutes with MailRoutes.. (Downside:
paths are still absolute, but reusable if they don't change from app
to app.)

2) Like above, but build calculate paths on the fly with an abstract
member. (Downside: totally untested. I just thought of it.)

trait UserRoutes { this: => ScalatraKernel
def userPrefix: String = "/users"

get(userPrefix + "/:id") { ... }
delete(userPrefix + "/:id") { ... }
}

class MyApp extends ScalatraServlet with UserRoutes {
// This is going to be a German app
val userPrefix = "/benutzer"
}

--

Keith Irwin

unread,
Aug 19, 2011, 3:14:38 PM8/19/11
to scalat...@googlegroups.com
On Aug 19, 2011, at 11:47 AM, Ross A. Baker wrote:

> Mountable routers are definitely on our radar. Sinatra does not
> provide us with a model in this case, but some of the other mentioned
> frameworks do.

*Devils' Advocate*

I used to use Restlets and it allows this kind of complexity, not to mention adding filters to various routers, etc, etc. It's a great framework and it taught me a lot about the concerns of the REST-ful style that I might otherwise have glossed over under time constraints.

The best thing about Scalatra, though, is that it's simple. It rewards "keeping it simple", encourages refactoring your design to fit within super-simple constraints, and the fact that it doesn't allow too many complicated compositions forces (or at least allows) you to realize that you're over-engineering. Scalatra resists over-abstraction, I think. Keeps the actual code reasonably simple, too.

I think having multiple servlets, each one a context, is perfectly fine and already adequate and lifts the concern out of Scalatra itself. (I use this pattern to serve static content with Jetty's resource handler, and my API via a Scalatra servlet.)

If you have lots of support methods you want to use across multiple servlets (/app/admin and /app/public, etc, etc), then a trait can help with that. The interesting side effect is that if you need to move a servlet (a collection of routes) from one app to another (for instance, to separate routes that ingest a lot of data from those that serve it for performance reasons), it's much easier to cut/copy/paste a nice little servlet class out of one project and inject it into another.

The composability should be at the container layer, not Scalatra itself, which should never encourage giant, monolithic apps.

Keith

Ross A. Baker

unread,
Aug 19, 2011, 10:51:23 PM8/19/11
to scalat...@googlegroups.com
On Fri, Aug 19, 2011 at 2:14 PM, Keith Irwin <ke...@zentrope.com> wrote:
> The best thing about Scalatra, though, is that it's simple. It rewards "keeping it simple", encourages refactoring your design to fit within super-simple constraints, and the fact that it doesn't allow too many complicated compositions forces (or at least allows) you to realize that you're over-engineering. Scalatra resists over-abstraction, I think. Keeps the actual code reasonably simple, too.

Good post. Sinatra has spread to most languages capable of imitating
its DSL because of its simplicity. It's sort of the universal web
framework, and we do well not to stray far from it.

Part of what makes the multiple servlet solution so distasteful is the
web.xml. As we decouple the routing from the servlet, it will be
possible to configure multiple applications in pure Scala code. I
prefer toward standard .war deployments, but if you start your own
embedded Jetty instance and construct the servlets yourself, you can
even configure in pure code today.

Leif Warner

unread,
Aug 19, 2011, 11:23:53 PM8/19/11
to scalatra-user
Another thing about the web.xml files: given that they are XML, it
would be trivial to programmatically generate them. We could describe
the config of servlet parts in Scala code, and then automatically turn
it into web.xml. Perhaps an SBT plugin.
-Leif

János Háber

unread,
Feb 5, 2012, 6:39:46 AM2/5/12
to scalat...@googlegroups.com
What do you thing about padrino nested routing and mounting?

Ivan Porto Carerro

unread,
Feb 5, 2012, 6:40:47 AM2/5/12
to scalat...@googlegroups.com
That's one of the features that is already implemented in scalatra-netty

http://github.com/scalatra/scalatra-netty

János Háber

unread,
Feb 5, 2012, 7:29:43 AM2/5/12
to scalat...@googlegroups.com
Can you show me scalatra-netty documentation?
Can it's work on tomcat or another servlet container?

Thanks

Ross A. Baker

unread,
Feb 5, 2012, 4:17:21 PM2/5/12
to scalat...@googlegroups.com
scalatra-netty is still in a proof-of-concept phase and still subject
to change. The source is at
http://github.com/scalatra/scalatra-netty. If it goes well, it will
be merged in and become Scalatra 3.0.

Netty is an alternative to servlets. scalatra-netty will not
currently run on a servlet container, but a servlet implementation
will be supported if and when that project gets merged into master.

--

Reply all
Reply to author
Forward
0 new messages