A few initial disappointments (why I probably wouldn't use Xitrum as a web framework)

1,128 views
Skip to first unread message

Chas

unread,
Dec 23, 2011, 11:31:21 PM12/23/11
to Xitrum web framework
I've been building websites, including some big ones, in Scala for
several years, first with Lift (for which I was sort of a committer),
and later with Circumflex. And I've used all sorts of Scala toys, like
Squeryl, Scalate, etc. I've also built sites in Ruby, Javascript, PHP,
C#, Python, and even plain old HTML/CSS. I've used a lot of different
frameworks over the years.

Two choices made by the Xitrum team alarm me. I see where they come
from, but I think they are poor choices. They would prevent me from
ever using the Xitrum framwork to build an HTML website. And if that's
true for me, then it's true for others as well.

This doesn't mean that there's no place for the framework as it's
currently configured. There's room for all kinds of frameworks out
there, and everyone has his or her own favorite. Mine, currently, is
Circumflex. I find it simple, clean, elegant, and powerful. It doesn't
do magic *anything*, and that's a big plus for me. In my experience,
most "magic" starts out as an effort to avoid boilerplate, and ends up
making far more work than copying, pasting, and modifying snippets of
code ever did. Worse, I already learned how to do it the "hard" way,
and now I have to memorize a whole bunch of magic spells on top of
that. And I never really know how it's doing whatever it is it's
doing, which makes debugging harder.

My solution is to keep things as clean, simple, and elegant as
possible. I've abandoned, for example, most of the big Javascript
libraries (Ext JS, YUI, Mootools, Dojo -- I've used them all) and GWT
in favor of small bits of jQuery where needed. Things load faster, are
more robust, and are much easier to debug.

I've also been a big advocate for standards-compliance since the late
90s.

So the first thing that really disappointed me about Xitrum is that
you've thrown standards compliance out the window. The current sample
page fails to validate as XHTML Transitional for several reasons (no
xmlns in the html tag, UL elements do not belong in P elements, etc.),
but most of that is easily corrected. (And why is your sample page not
HTML5?) But the way postbacks are implemented means that I can never
use one unless I'm willing to give up completely on having valid HTML.
I'm pretty sure that the same benefit can be accomplished without
invalidating my HTML, so I can't understand why that route was chosen,
unless the developers simply don't care about valid HTML at all.

Another big disappointment was the use of encoded URLs in the
postbacks. This was the feature of Lift that I hated the most -- so
much so that I worked around it in virtually every website I made in
Lift. The one time I used it, I got bitten badly. I'd coded up an
awards nomination form for a big website. The form was complex and
some people spent a lot of time on it. Nothing in the then-sparse Lift
documentation or on the mailing lists mentioned the big danger here.
So when a good friend wrote to me to complain that he'd spent the
better part of an hour writing up a nomination only to have all his
work disappear into thin air, I was perplexed. I tested the form again
-- thoroughly -- and everything worked fine. What could be the
problem? It took me more than an hour to finally figure it out.

The problem? His session timed out as he was working on the
nomination, and when he submitted the form, the encoded URLs no longer
meant anything to the server, so the form was discarded. Now, I could
have worked around this had I thought of it ahead of time, and the
simple solution was to change the session timeout to a couple hours.
But I will never know how many nominations -- and specifically the
ones that had taken the most effort (thus the most time) to produce --
simply disappeared into thin air: a humiliating mistake for which I
still feel guilty.

Coded URLs make debugging harder, too. I just don't see that the
benefit -- if there is one -- outweighs the hassle. But maybe that's
just me.

Really, I guess the biggest disappointment with Xitrum is that it's
the same old stuff with a few new toys added. It's great that
Hazelcast and Netty and Akka, etc. are built in. And the creation of
HTML templates (really XML) in the Scala code is an interesting
approach. I've never really felt that MVC was all it's cracked up to
be, and I have a sneaking suspicion that a lot of developers secretly
agree. But then, I'm not religious about all this stuff. I have no
horse in the race. I'll use whatever language/tool is best for the
job, and when something better comes along, I never look back.

But Lift already exists, and it's a great framework for everyone who
wants to build websites that way. It has gotten much better and more
modular over time, too. I've no doubt it can be used easily with
Netty, Hazelcast, Akka (I've used it with Akka myself). So why build
another Lift? For that matter, why steal ideas from Nitrogen? Or any
other framework? Take a different approach.

It would be great to see a Scala web framework that does more with
monads and delimited continuations. I've been checking out a new
Haskell framework called Snap. That might be worth looking at. And I
remember that Seaside (a Smalltalk framework) used continuations
cleverly. Maybe that's all already in there (admittedly, I've only
spent 15 minutes looking through the code), so take all this with a
big grain of salt.

Actually, from my point of view, using OOP for websites is a big
mistake. I just don't think that most of the data I work with makes
sense as an object. Is a page an object? Is a paragraph an object? The
whole point of objects is that they are more than structs -- they
include methods. But how often do I really need objects with methods
on most websites? Almost never. An "authenticate" method in my user
objects is about as far as it goes.

I think, and maybe I'm going out on a limb here, that FP is the future
of the web. What I want to do is deal with data. I want to do things
to it. Do = verb = FP. Truth be told, some of the old procedural sites
I built in PHP a decade or so ago made much more sense to me than the
Rails or Lift sites I built later. Really, we're not dealing with
objects, we're transforming data. I am waiting for the framework that
really uses FP to do the Web right. Distributed, asynchronous,
stateless, and as immutable and idempotent as possible.

One last caution I would make: the more stuff you add, the more
potential points of failure. I would make the default always be to
*leave it out* and make people take action to add it in. Run as lean
and clean as you can. Avoid adding cool stuff for its own sake. A
robust, solid, scalable, and easily extendable framework is, IMO, the
most useful. It's why I like Circumflex so much.

Chas. Munat

ngocdaothanh

unread,
Dec 24, 2011, 6:52:05 AM12/24/11
to Xitrum web framework
Thanks a lot for the long feedback.
Let's discuss.

> The current sample page fails to validate

It will be fixed soon and HTML5 will be used by default.
By the way the next version will have WebSocket.

> postback

Postback in Xitrum is stateless by default.
The server doesn't store any state.

Xitrum was born from a real project.
It is designed to so that app developers can easily
work in both styles:
* REST: for smartphones and rich clients
* Postback: for in-house admin pages, these pages
just need to be quick (and dirty)

So if you don't like postback, just use REST.
REST is kind of 1st citizen in Xitrum,
unlike in Lift.

I'm thinking of replacing postback with
something based on Knockout.js.
Do you have any idea of how Knockout.js
should be used in Xitrum?

> why build another Lift?

Good question.
Actually that's why Xitrum was born.
At first I used Lift.
But having used Rails, Merb, Sinatra etc.
I gradually felt that the taste of of Lift
didn't suit me, because I don't like the
look of the code I write with Lift.
It's not beautiful.
You know Ruby.
I think you know what I mean by "beautiful".

May be it's just a problem of feeling,
but I wanted something with
lighter, prettier look, but richer than Scalatra.
I didn't find anything like that,
so I created Xitrum.

> Distributed, asynchronous, stateless,
> and as immutable and idempotent as possible

Totally agree.
This is the right direction.

Ngoc

Charles Munat

unread,
Dec 24, 2011, 11:30:07 AM12/24/11
to xitrum-f...@googlegroups.com
I've played around with Knockout.js. I'll give it another look and will think about it. I'm glad to hear that you'll go to HTML5 by default. Does this mean that you'll try to find a way to do the postbacks without invalidating the HTML? That would be nice.

Good point that the REST option remains open, but a shame to give up the postbacks if it isn't necessary. I think making REST a first class citizen is a very good idea. I'll play with it today.

I think you have the right approach overall. I recommend that you take a look at Circumflex (http://circumflex.ru/) and particularly look at their source code. Maybe it's just me, but I find their style quite elegant. Check out their sample application: http://circumflex.ru/projects/web/index.html IIRC, they've avoided annotations, too. A good framework to study, I think.

I'll play with this more today and will review Knockout and will get back to you.

Chas.

Charles Munat

unread,
Dec 24, 2011, 12:24:27 PM12/24/11
to xitrum-f...@googlegroups.com
If you revise Knockout to work with Xitrum, will you call it Ngocout?

ngocdaothanh

unread,
Dec 24, 2011, 6:17:16 PM12/24/11
to Xitrum web framework
> they've avoided annotations

This is a feature, not a flaw.
Without annotations, you have to have a
central place to define all routes.
Think of annotations as distributed routes.

I included this feature because I like
the idea of Rails Engines, where you
can plug an app into another app.
For example, if you have a blog engine,
you can package it as a JAR file.
Then you can plug that JAR file
into another app.

> will you call it Ngocout?

Interesting :)

Charles Munat

unread,
Dec 24, 2011, 6:28:24 PM12/24/11
to xitrum-f...@googlegroups.com
I wasn't suggesting that annotations were a flaw. But IIRC, Circumflex does not require you to define all the routes in one place, and they don't use annotations. You might take a look at how they do it, if only to see another method. But annotations or not is a matter of personal taste.

Have also been looking at Blue Eyes. They don't have a central routes file (a la Rails), but neither do they use annotations either. Another example to check out.

If you like annotations, by all means do them. Lots of people like them. I'm neutral. I just like to get the job done. I don't really care how.

Chas.

ngocdaothanh

unread,
Dec 24, 2011, 7:19:57 PM12/24/11
to Xitrum web framework
In Circumflex you have a central router like this:

class MainRouter extends RequestRouter {
// with matching
any("/users/*") => new UsersRouter
any("/posts/*") => new PostsRouter
any("/mail/*") => new MailRouter
any("/downloads/*") => new DownloadsRouter
// unconditionally
new MiscRouter
}

I think technically in Java annotation is the only way to avoid a
central router. Because Scala has compiler plugin, I'm thinking of
using it to replace annotation. Compiler plugin is more advanced, it
can make extracting parameters in URI more typesafe.

Charles Munat

unread,
Dec 25, 2011, 1:26:55 PM12/25/11
to xitrum-f...@googlegroups.com
Well, yes and no. You do need to have an entry point, so I generally do something like this in Main.scala:

class Main extends RequestRouter {
    get("/") = { ... } // home page

    new Tasks
    new Users
}

Then in Tasks.scala:

class Tasks extends RequestRouter("/tasks") {
    get("/") = { ... }  // list all tasks
    get("/:uuid") = { ... }  // list task with :uuid
    put("/:uuid") = { ... }  // create/update task with :uuid
    delete("/:uuid") = { ... }  // delete task with :uuid
}

Yes, I instantiate the various routers in the main router, but the actual routes are defined in the routers themselves, not in a central source. So, for example, I can extend the users router thus, without any changes to Main.scala:

class Users extends RequestRouter("/users") {
    get("/") = { ... }  // list all users
    get("/:uuid") = { ... }  // list user with :uuid
    put("/:uuid") = { ... }  // create/update user with :uuid
    delete("/:uuid") = { ... }  // delete user with :uuid

    get("/:uuid/tasks") = { ... }  // get all tasks for user with :uuid
    get("/:uuid/tasks/:t_id") = { ... }  // get task with :t_id for user with :uuid
    // etc.
}

In my REST sites, I have a models directory where I'd have, e.g., User.scala, and then a routers directory where I'd have Users.scala. But there's no reason I couldn't also just put the router below the model in the User.scala file (and I've done it that way in the past). That keeps the model and the router together in one file. Very useful. (I love this about Scala.)

Also, note that I don't technically have to instantiate every router in Main.scala. Maybe tasks are specific to users, so I instantiate the Tasks router in the Users router. That way if I want to turn off User for debugging, say, I just comment out "new Users" in the main router and that takes care of Tasks as well.

This seems pretty distributed to me, and no annotations.

The guys on the Circumflex list are very friendly and speak perfect English (as do you, obviously), so you might ask them their theory on that. IANAE. But I found the Circumflex method to be incredibly easy to use and understand. You might not do it the exact same way, but it's a good reference point.

Chas.

ngocdaothanh

unread,
Dec 25, 2011, 10:36:59 PM12/25/11
to Xitrum web framework
> It would be great to see a Scala web framework that does more with monads and delimited continuations

I've read about Seaside. Isn't continuation is all about stateful?

> and no annotations

Apart from "no annotations", from the usage point of view, I think the
routing feature in Xitrum is better. For example:
* No central place
* Routing should be 2 ways: routing URLs to actions and recreating
URLs from actions

See https://github.com/ngocdaothanh/xitrum-quickstart/blob/master/src/main/scala/quickstart/action/AppAction.scala

You can get URL to the CometAction in a typesafe way:
<a href={urlFor[CometAction]}>Comet chat</a>

Charles Munat

unread,
Dec 26, 2011, 5:29:03 PM12/26/11
to xitrum-f...@googlegroups.com
Depends on what you mean by state and how you implement the continuations. In the simplest sense, every connection between client and server maintains state -- in the form of an open connection -- for the duration of the exchange. If the connection "times out," you lose that state.

More commonly we are interested in maintaining state between connections. And for any site where log in is an issue, this is pretty unavoidable. Thus cookies or URL rewriting. I don't want to have to re-enter my credentials on every page, after all.

Seaside, IIRC (it's been years), uses continuations in an interesting way in which they pass a name (some sort of unique identifier) for the continuation in the URL. So you could, potentially, bookmark that URL, come back months later, and resume the process right where you left off. I see this as a valuable feature for long forms, for example, where I might partially complete the form, and then come back days or weeks later to add more. But it's overdone in Seaside IMO, and it's tricky to implement.

What I had in mind was more about using continuations on the server-side as a way of implementing a sort of asynchronous behavior. If you think about it, asynchronous behavior also requires a certain maintaining of state, generally in the form of a callback.

A friend of mine has been working on a very interesting key-value database that makes heavy use of actors and continuations. I looked around for his blog post, but couldn't find it.

No matter, it was just a thought... I will take a closer look at Xitrum routing.

Chas.

ngocdaothanh

unread,
Dec 26, 2011, 8:41:26 PM12/26/11
to Xitrum web framework
After seeing this example:
http://stackoverflow.com/questions/6062003/event-listeners-with-scala-continuations
I'm thinking of using Knockout.js and continuation like this:

override def execute {
val model1 = ...
val model2 = renderViewAndWait(model1)
...
}

But I'm not sure it's any better than this:

override def execute {
val model1 = ...
renderView(model1)
}

override def postback {
val model2 = parseRequest()
...
}

Do you have any idea?

Charles Munat

unread,
Dec 26, 2011, 10:32:05 PM12/26/11
to xitrum-f...@googlegroups.com
The first one is obviously clearer and more terse, but I'm no expert on continuations. Maybe ask on the Scala list? They're usually really good at this responding on this sort of question (it's more interesting than most).

Chas.

ngocdaothanh

unread,
Dec 28, 2011, 7:01:22 AM12/28/11
to Xitrum web framework

Charles Munat

unread,
Dec 28, 2011, 12:11:27 PM12/28/11
to xitrum-f...@googlegroups.com
Good questions. I'm very interested to see how they reply.

Chas.


ngocdaothanh

unread,
Dec 28, 2011, 4:04:36 PM12/28/11
to Xitrum web framework
About annotation, I must admit it's also used to give you declarative
caching like this:

@CachePageMinute(1)
// Or @CacheActionMinute(1) if you want to run the action's before
filter
@GET("/")
class IndexAction extends Action...

See http://ngocdaothanh.github.com/xitrum/cache.html

virtualeyes

unread,
Dec 29, 2011, 5:51:03 PM12/29/11
to Xitrum web framework
Charles, interesting, highly useful feedback.

I'm envious if Circumflex has you fulfilled in your search for the
"perfect" Scala web framework. To-date, I have explored in no
particular order: Lift, Scalatra, Circumflex, Xitrum, Bowler, Blue
Eyes, Spray, and Pinky (discontinued).

Spray kicks some serious ass but is pretty much 100% stateless REST
API, so none of the conveniences that Circumflex, Scalatra, Bowler and
Xitrum supply; namely: i18N & session/flash scope (they just added
Scalate in their snapshot build, which is the only reason they're
still in the running for me).

Circumflex is indeed well thought out, complex simplicity, the API
reads like a book, from a Russian no less (Xitrum is equally
impressive in this regard, puts native English speakers to shame).

Circumflex, Scalatra, Bowler and Xitrum will all do the trick, the
hassle for me is, JSON and ORM, these are the 2 single weakest links
in near-2012 Scala land. I have yet to see JSON transformations that
do not entail some form of painful manual conversion for complex
object graphs. Major #fail. This is a 1-liner in Groovy, for example,
regardless of depth, complexity, or types in object graph. ORMs
essentially blow chunks in Scala, the essence of not-DRY, which is not
the fault of the developers, but the need to comply to the compiler.
Rails Active Record and Grails GORM are far, far ahead of anything
comparable in Scala (though ScalaQuery has legs, will rock in time)

I'm going to run through Xitrum docs again. One thing Xitrum has over
Circumflex is developer investment. I believe Circumflex cats are
maxed out on an e-learning project and not throwing themselves at
evolving Circumflex (good as it may be) in the way that is happening
here with Xitrum (have seen you promoting the framework around the
net, Ngoc, keep the faith ;-))

Cool at least to see a lot of activity in Scala frameworks, no
shortage of options...

Charles Munat

unread,
Dec 30, 2011, 12:27:27 AM12/30/11
to xitrum-f...@googlegroups.com
Circumflex has been pretty quiet for many months now, but for most small projects, it's more than enough. I've never actually used the ORM in production -- wrote my own using BaseX XML DB instead. That was fun, but making it really robust was difficult. After a while, I gave up on objects completely and just stuck the whole site in the DB. I used one big XQuery to create and cache the pages. It was very basic, but worked well and was really fast. I'm playing around right now with a similar idea in the form of a CouchApp (with backbone.js).

In the end, Circumflex ended being used more for routing than anything else. But I still like their style.

Ngoc is slowly convincing me to take a much closer look at Xitrum. I agree that there's a ton of energy there. It's pretty exciting.

I missed Bowler and Spray -- will have to check them out. Too little time now to go into my desiderata for a web framework -- I'm not at all beholden to Scala in particular, having just finished a Rails 3.1 site and a node.js/underscore.js/backbone.js/data/js site. As I mentioned elsewhere, I'm very curious about Snap, a new Haskell framework.

I enjoyed your comments. Looks like I need to keep looking around.

Chas.

virtualeyes

unread,
Dec 30, 2011, 4:13:23 AM12/30/11
to Xitrum web framework
Chas, you are a madman ;-)

Clearly exploring the entire web framework landscape you are.

If one were to bake a cake, Xitrum has the ingredients clearly,
perhaps the most feature rich of the lean Scala frameworks.

For me, I'm looking for:
1) routing
2) i18N
3) template engine (Scalate preferred)
4) ORM for persistence, JDBC wrapper (ScalaQuery) for public read-only
queries
case class type conversion is a hassle here, much to be desired
(reflection seems limited to-date in Scala), lots of boilerplate
5) JSON conversion utility
same as above, type conversion for complex object graphs entails much
re-writing of already defined types in case class(es).
6) perhaps session/flash scope, although could go semi-stateless with
cookie + in-memory DB "session"
7) SBT build process/dependency management

The REST is then passed off to the rest: client-side JS handles JSON
reply, rendering accordingly in target DOM element. De-coupling the
components in this way is quite new to me, I have been server-side for
10 years, but am looking to offload some tasks to the client, making
heavy use of LESS & CoffeeScript in the process (plain javascript is a
receipe for spaghetti much like php, f-ugly-ness).

Alright, back to Xitrum and seeing what's new, has been a couple
months since I last dropped by here ;-)

Regards,
Noah

virtualeyes

unread,
Dec 30, 2011, 6:29:46 AM12/30/11
to Xitrum web framework
Just ran through the Xitrum docs in-depth.

Wow, this is a really impressive body of work, arguably the most
complete Scala framework outside of Lift (but much easier to use)

Xitrum is truly a full stack web framework, all the bases are covered,
including wtf-am-I-on-the-moon extras like Etags, static file cache
identifiers & auto-gzip compression. Tack on built-in JSON converter,
before/around/after interceptors, request/session/cookie/flash scopes,
integrated validation (server & client-side, nice), built-in cache
layer (HazleCast), i18N a la GNU gettext, Netty (with Nginx, hello
blazing fast), etc. and you have, wow.

Now, some aspects require an adjustment.
1) Routing
rather than taking the single regex route file approach that every
other framework on the planet implements, Xitrum goes for the
annotated controller-action approach. Since each controller-action is
responsible for rendering the view snippet, it does make sense to
break these into separate files (as things would get rather unwieldy
with all view-actions under a single controller).

Personally, Xitrum would be Scala framework Nirvana if Scalate were an
option; i.e. implement annotated METHODS under a single controller and
have the actions delegate to the Scalate template engine (where you
can benefit from Jade, LESS, and CoffeeScript). In this way you have
the front controller of Circumflex, but without having to define
routes in a separate file (since Xitrum creates route file on startup
via route-method annotation discovery). That would be unbelievably
awesome ;-)

2) Postback
I am on the fence here, but not because I don't like the concept, but
more because I am unsure of potential drawbacks to this approach? It
does unfortunately seem that separate controller-action files are
needed with postback given that CRUD actions require a dedicated
"override def postback {...} block". I would again prefer annotated
route-methods of a single controller file vs separate annotated class-
action files. This is common in Spring, for example, and gives a ton
of fine grained control.

Basically I prefer the skinny controller approach, and in Xitrum
controller-actions do everything. If we could offload view rendering
to Scalate, and implement single controller annotated route-methods,
Xitrum would be de facto best Scala web framework 2012 ;-)

Thoughts appreciated, inspired by the potential here...

Regards,
Noah

ngocdaothanh

unread,
Dec 30, 2011, 7:36:15 AM12/30/11
to Xitrum web framework
Noah,
Thanks for the feedback.

1) Scalate

I'm thinking of adding Scalate back too (early version of Xitrum once
had it), but since Scala's XML feature is too convenient, I wonder if
Scala's XML + Scala Enhanced String (http://jrudolph.github.com/scala-
enhanced-strings/Overview.scala.html) combination is enough.

2) Postback

You only need a separate action if you want. Even in that case, Scala
lets you put multiple classes in one file.

The benefit of the current implementation is you have automatic
validation for both client side and server side.

With this code:
{<input type="text" name="username" /> :: MinLength(5) ::
MaxLength(10)}
The length is automatically validated on the server side when the data
is posted back.

I'm thinking of improving/replacing the current implementation with
Knockout.js + Scala delimited continuation, may be based on Akka
dataflow (http://akka.io/docs/akka/1.3-RC5/scala/dataflow.html).

Please try the Todo sample:
https://github.com/ngocdaothanh/xitrum-quickstart/blob/master/src/main/scala/quickstart/action/TodoAction.scala
in the latest Quickstart.

It's still in early stage, please feedback. The final version may look
like this:

val model1 = MyModel(...) <-- a case class
val model2 = renderViewAndWait(model1) <-- automatically converted to
JSON for Knockout.js and converted back
val model3 = validate(model2)

So basically you don't have to mess with params manually, you can work
entirely only with Scala case classes in the serial, typesafe way
style.

The downside is it's not SEO-friendly because templating is done on
the browser side. I'm afraid many people will not be happy.

Ngoc

virtualeyes

unread,
Dec 30, 2011, 10:05:14 AM12/30/11
to Xitrum web framework
Ngoc, thanks

1) I think for the future of your framework, adding Scalate back in
would be a very, very good idea. Pretty much everything James Strachan
produces turns to gold (well, Groovy is TBD). Spray, Scalatra,
Circumflex, & Bowler all provide Scalate, and the reason why is clear:
you not only have a clean separation between code/logic and view/
display, you can use, for example, Jade syntax to generate DOM
elements with amazing concision; the same goes for css (via built-in
LESS compiler) and javascript (via CoffeeScript compiler).

Scalate just makes sense, it's type safe and the leanest possible
server-side view implementation around. Major thumbs up for this
component.

2) Automated validation
I love the server-side to client-side validation mirroring, nobody
else is doing this. However, would it not make more sense for
validation to be defined at the (case) class level?

For example:
case class User(age: Int, email: String, name: String, birthDate:
java.util.Date) {
require(age > 99 , t("you're not dead yet?"))
require(isEmail(email), t("please provide a valid email address"))
require(!empty(name), t("name field cannot be blank"))
require(birthDate.isInstanceOf[java.util.Date], t("please select
your birth date"))

def beforeValidate(u: User) {
// for example, convert string birtDate to java.util.Date
prior to create/validate case class
}
}

In this way validation is tied directly to the model (where imo, it
belongs) which makes it impossible to do Person(100,
"invalidemail@.com", "REST API let me through, heh, heh"). I like
this approach, Grails employs it nicely with their ORM, which leads me
to my next point

3) Controller-action files
I'm converting a moderately complex Grails application to Scala. Have
about 40 controllers with @same number of domain/entity classes. Most
of the controllers do basic CRUD, so 4 or more actions per
controller. In Xitrum that either means 160+ controller-action files,
or as you say, embed grouped controller-action classes into a single
file. That could be doable, but not nearly as DRY as one would like.

Outside of the headaches in implementing, what is the problem with
single controller/annotated method approach??
class UserController {

@GET("/user/:id")
def show(id: Long) {
val user = User.find(id)
renderView(user) // by convention Scalate user/show.ext is
called here
}

@GET("/user")
def list() {
List users = User.list()
renderJson(users) // JSON reply to the excellent js DataTables
plugin for example
}

@GET("/user/create")
def create() {
// render form in Scalate WITH validation inferred from case
class and auto-added to jQuery validate
renderView // again, Scalate user/create.ext template called
here by convention
}

@POST("/user")
def save() {
var msg = "user created"

def user = validate(User)
if(!user.errors.get) {
user.save()
}
else msg = "uh oh, problems occurred: " // +
user.errors.toString() not sure how t() deals with runtime
renderView(t(msg))
}
}

I should point out that Xitrum has the most potential to be Rails-
next, which is to say, a blazing fast strongly typed convention-based
web framework. Circumflex guys are working their asses off on other
things; Scalatra just follows Sinatra; Spray guys are all about
stateless REST API for now; Bowler is, I'm not sure what, difficult to
follow it seems. Lift is monolithic, radical context switch to-be-
avoided framework. That leaves Xitrum with a HUGE opening to strike
while the iron is hot ;-)

Oh yes, there is Play, and TypeSafe is backing them so uhhh, the
gorilla is around the corner. I like the complete package that Xitrum
offers more than Play, however. It seems like the Xitrum user base is
small enough at this point for the framework to adapt/evolve.

My vote is clear, bring back Scalate and consider more convention-
based single controller with annotated router methods. I'm sold on
the rest, rocking framework ;-)

Regards,
Noah

On Dec 30, 1:36 pm, ngocdaothanh <ngocdaoth...@gmail.com> wrote:
> Noah,
> Thanks for the feedback.
>
> 1) Scalate
>
> I'm thinking of adding Scalate back too (early version of Xitrum once
> had it), but since Scala's XML feature is too convenient, I wonder if
> Scala's XML + Scala Enhanced String (http://jrudolph.github.com/scala-
> enhanced-strings/Overview.scala.html) combination is enough.
>
> 2) Postback
>
> You only need a separate action if you want. Even in that case, Scala
> lets you put multiple classes in one file.
>
> The benefit of the current implementation is you have automatic
> validation for both client side and server side.
>
> With this code:
> {<input type="text" name="username" /> :: MinLength(5) ::
> MaxLength(10)}
> The length is automatically validated on the server side when the data
> is posted back.
>
> I'm thinking of improving/replacing the current implementation with
> Knockout.js + Scala delimited continuation, may be based on Akka
> dataflow (http://akka.io/docs/akka/1.3-RC5/scala/dataflow.html).
>
> Please try the Todo sample:https://github.com/ngocdaothanh/xitrum-quickstart/blob/master/src/mai...

ngocdaothanh

unread,
Dec 30, 2011, 10:47:57 AM12/30/11
to Xitrum web framework
1) Scalate

OK. I'm adding Scalate back right now.

2) Automated validation

Very sexy API.
In fact I copied the postback and validation idea from Nitrogen:
http://nitrogenproject.com/demos

3) Controller-action files

Coming from Rails, I really want to do that.
But routing should be 2 ways: routing URLs to actions and recreating
URLs from actions.

If each action is a class, I can do like this (the current API):
urlFor[UserShowAction]("id" -> 123)

I don't know how to recreate URL in a typesafe way if action is not a
class (OK, somewhat typesafe like above). Do you have any idea how to
solve this problem?

I've thought about making each controller an object, and each action a
function.

object UserController {
@GET("/user/:id")
def show(env: ActionEnv, id: Long) {
}
}

In this case:
urlFor[UserController.show]("id" -> 123)

But because UserController is an object, I cannot extend it anymore.
And there's the ugly env in the parameter list of all the actions.

Ngoc

Charles Munat

unread,
Dec 30, 2011, 12:14:29 PM12/30/11
to xitrum-f...@googlegroups.com
Holy crap! I look away for five minutes, come back, and I've got War and Peace to read.

Well, this is all very exciting. Doubly so, because as I play around with Xitrum I am more and more convinced that Ngoc is as much a madman as I am. Maybe even more so.

I used Scalate back when James was first putting it together, but then wandered off to work with Vaadin (via Scala -- bleah). I'm pretty soured on GWT stuff at this point. Maybe it's time to give Scalate another look. And how nice that Ngoc, seemingly in ten seconds, has added it back in to his impressive framework.

I have to reread all this, but an immediate comment is this: it ain't gonna be perfect. Everything has tradeoffs, so centralized routes are nice for having everything all in one place, while distributed routing is better for modularity. I'm big on composition, so I'd probably stick with anything that lets me decouple things. But another question is, does it have to be one or the other? If the framework is nicely modularized, why not a centralized routing option and a distributed routing option? Nice if I could swap them out, too.

That way, if I'm building a simple website (which is most of what I build, frankly), I can just have all my routes in one file where it's easy to see them at a glance. That's the benefit of routes.rb, right? It's all right there. But then if I'm finally building that perfect CMS I've been dreaming about for more than a decade now, I can use distributed routing and allow easy plugins. Maybe I'm talking out my ass here as I haven't actually looked at the source code yet, but that's a nice 20k foot view for me.

I was just looking to build a web crawler, but now that I've spent some time playing around in the code, I'm thinking about using Xitrum for one of the sites I'm currently working on. There's really no justification for this much power for the tiny crap I'm currently engaged with -- like rebuilding a website for my aunt's ski lodge -- but, hey, you never know when Vermont is suddenly going to become the hot skiing destination and Hazelcast will become a lifesaver!

Actually, I'm also building a site for a cocktail book that I'm writing (I have no life), so maybe I should just assume NYT bestseller status and use Xitrum for it...

I should also mention that perhaps the biggest seller for me on Xitrum right now is the incredible openness to new ideas and the remarkable responsiveness of Ngoc: keep it up, sir. Great ideas often die for lack of a community, so building a list is at least as important as the framework itself. I think that what made Lift grow so quickly was in large part David's excellent responsiveness on the Lift list.

More after I get some time to reread and digest the above...

Golly, I feel like a kid in a candy store.

Chas.

virtualeyes

unread,
Dec 30, 2011, 12:50:45 PM12/30/11
to Xitrum web framework
Great, re: bringing Scalate back ;-)

Automated validation as is works, but domain/entity class should be
the validation source, vs. at controller layer where it is now. Since
user-input is validated to persist-to/query-from some data repository,
defining validation at the controller layer creates a disconnect
between domain/entity property definitions and their validation.

By defining validation rules at the domain layer, client-side
validation could, ideally, be transparent to field representation
(i.e. a given form field would not need a "MinLength" or "Required"
attribute as that would be passed on to client-side validation
framework automatically when a form of type Foo entity was created).
Basically define validation rules once and then any form that uses the
entity would implicitly have client-side validation included.

As for controller/routes, one reason Xitrum may not be attracting the
number of users that it could have (given the awesome feature set of
the framework) is the non-conventional approach to routing and
invoking controller methods. Everyone copies Rails, from PHP
(Symphony) to Python (Django somewhat) to Groovy (Grails) to Java/
Scala (Play), and there's a reason for it, the conventions are crystal
clear, powerful and DRY (some road blocks, but overall the Rails "way"
makes perfect sense for web devel).

So, a new user coming to Xitrum with a background in any Rails
inspired framework is going to say, huh, why is the routing/controller
layer like that? This is the impression that I had when I found (and
moved on from) Xitrum a couple of months ago. Again, what you have
works, it's just a different approach. Overall the complete package is
competitive, and without doubt, pretty damn fast ;-)

As for how to bring implement type safe annotated methods that are
reverse routable, honestly, not sure, have yet to look at Xitrum
source. In the big picture though, this is, IMO, a tail wags the dog
approach. Certainly there is a way to achieve it, but deciding on the
overall application flow (route > controller > method > render) would
seem to be the priority.

Noah

virtualeyes

unread,
Dec 30, 2011, 1:40:24 PM12/30/11
to Xitrum web framework
Chris, great post ;-)

Well, feel free to send some of that fine Vermont "green" over here to
rainy SW France (from Cambrdige, MA, btw)

I would agree that now is a good time to jump on the Xitrum train as
Ngoc is clearly on a manic developer spree -- Riding the Ngails

My use case for Xitrum is ambitious from the start. My primary client
runs a hockey scouting service (covering impoverished New England
boarding schools) which given the demographic, rakes in some decent
cake. It's a LAMP stack app that I wrote years ago, but have never had
time to re-do on a sexier platform, until this year that is. I spent
the better part of 6 months diving into Groovy (attempting a hand
rolled Groovlet framework) followed by 3 months grinding through the
Grails (bugs), prototyping the new version of the site.

While Grails disappointed in the end, I took so much from the
experience in terms of pure MVC goodness and domain modelling that my
Scala web framework search has been influenced by this. I'm glad I
revisited Xitrum as I've been trying to square-peg-round-hole Spray
into an MVC which it is not.

So, Xitrum impresses, and part of that has to do with what I would
ironically like to see changed. The whole annotated class-method
approach to routing was new to me. What benefit do you get with a
centralized routing file when the application compiles the routes for
you at startup? In other words, with annotated routes you define at
the class level what a given URI can or cannot do. Very cool, both
ways work, but was refreshing to see a different approach.

Now, I am frankly not a fan of:
@GET("/user/:id")
class UserShow {

}

I am however, a fan of method level annotations. Why, well for a
number of reasons, but the primary benefit is consolidating
functionality. In a User controller all actions share one thing in
common: users! So, if I want to enrich UserController with some
trait(s), then I only have to do it once vs. in each UserAction class
as is currently implemented in Xitrum.

// can still use class level annotations here as applicable
class UserController extends Role with Auth {

@GET("/user/:id")
def show(id: Long) {
val u = User.find(id)
renderJson(u) // client-side slurps up the response and does some
js magic
}

@GET("/user/create")
def create() {
// Nirvana, scaffold form fields & client-side validation based
on
// User property types and validation rules
renderForm(User)
}

@POST("/user")
def save() {
// bind params to case class domain
// use beforeValidate interceptor at domain layer to convert
// things like string date to Date, string int to Int, etc.
def u = bind(User, paramso)
if(!u.errors.get) u.save()
...
}
}

Anyway, it's pretty clear the direction I'd like to see things go,
which is to say, Ngails ;-)

Noah

Charles Munat

unread,
Dec 30, 2011, 2:16:25 PM12/30/11
to xitrum-f...@googlegroups.com
Doesn't Jersey do exactly this sort of annotated-method routing? I don't recall having any kind of centralized routes file.

As for centralized routing and the "Rails way," I have to say, fuck that. I am so sick to death of Rails clones. Surely we can has many different routes (pun intended) to the same goal? (Or maybe somewhat different goals.) I'm not saying that centralized routes are, per se, bad. I'm saying that things should be done for good reasons, NOT because a lot of current and former Rails users are comfortable with that method. If we do that, how do we advance? Even Rails ended up essentially tossing their own code out and embracing MERB in the end.

So centralized routing has its benefits, and distributing routing has its benefits as well. And who gives a damn how Rails does it?

IMHO, of course.

Chas.

virtualeyes

unread,
Dec 30, 2011, 2:59:52 PM12/30/11
to Xitrum web framework
Jersey does method level routing and I am advocating just that (Ngoc
will do as he pleases of course, Xitrum is his baby after all).

Obviously no need to clone Rails, god forbid, then Xitrum turns into
something unwieldy and bloated.

Scalate was a great re-addition, IMO, that was a bit of a deal breaker
only having the Lift-view-snippet-in-controller approach.

Ngoc will sort out the routing, he's clearly open to shaking things
up.

We already have i18N, Jerkson JSON, session/flash/cookie, before/after
filters, caching, etc., etc. Everything is there...except ORM. Xitrum
is ORM agnostic, which is probably why validation rules are controller-
based instead of case class-based.

No Scala web framework I have explored (all of them, as have you Chas)
offers anything close to Grails' GORM and Rails' Active Record. The
state of ORM in planet Scala is kind of sad, lots of catching up to
do. At any rate, sure roll your own, or plug-in one of the existing
(I'll be going with ScalaQuery for JDBC wrapper and then patch
something together for persistence).

Fun to see Xitrum on the move, other projects are moving at a snails
pace in comparison...

Regards,
Noah

ngocdaothanh

unread,
Dec 30, 2011, 3:31:34 PM12/30/11
to Xitrum web framework
> why not a centralized routing option and a distributed routing option?

Actually there's always a central place inside Xitrum to store routes.
I've just exposed APIs for routing and action/page caching, for cases
you don't want to use annotation.

See:
https://github.com/ngocdaothanh/xitrum/blob/master/doc/sphinx/restful.rst
https://github.com/ngocdaothanh/xitrum/blob/master/doc/sphinx/cache.rst
https://github.com/ngocdaothanh/xitrum/blob/master/src/main/scala/xitrum/routing/Routes.scala

Please advise if you the APIs can be improved.

Ngoc

Charles Munat

unread,
Dec 30, 2011, 3:44:48 PM12/30/11
to xitrum-f...@googlegroups.com
Actually, what I want to do is give up on OOP entirely in my web framework, and find a pure FP approach. Then I'd use an RDBMS directly when it was the right place to persist my data (i.e., the data was set-oriented or tabular), but I'd use, say, a DB like HypergraphDB when I needed to work with graphs. Or something like BaseX (which is GREAT) when I wanted to just store HTML (well, XHTML, obviously) and maybe manipulate it a little. BaseX is not too bad for trees, either, and it has a great little GUI client. Or maybe use a document database for trees... ah, my cup runneth over.

ORMs suck. They've gotten a lot better, but they are the answer to a question that no one should have asked: We've got a DB that only understands shades of red, and a business layer that only understands shades of blue. What do we do? Build a blue-red converter is not a good answer in my book. All this complexity, for what? For most of the sites on which I've used ActiveRecord or Hibernate, I have never once taken advantage of any of the real benefits of a relational database. It's just overly-complex storage for tree- or graph-like objects.

But as I said elsewhere here, I really don't see the value of objects at all WRT most web sites. There are data, and there is manipulation of those data. Where are the objects? The typical website seems much more suited to FP than OOP, but maybe that's just me. With immutability, pattern matching, continuations, for comprehensions, and a good type system, who needs objects?

(And I say this having been a OO programmer for most of my near 20 year career in programming.)

Now off to relearn Scalate... sigh.

Chas.

Charles Munat

unread,
Dec 30, 2011, 3:52:20 PM12/30/11
to xitrum-f...@googlegroups.com
In fact !! (I guess I'm not quite done bitching yet) I have had to work around the OOP part whenever I wanted to do something the RDBMS was really good at. For example, on one project I did many years ago in Rails, I had to run through big datasets and do some manipulation involving just one or two fields in a fairly complex object. The whole server would blog down. Of course, the problem was that I was inflating 50,000 objects just to manipulate one field. So of course I used the ActiveRecord facility for manipulating the data directly. But that's my point... the more I thought about it, the more I realized that 90% of the time, the objects gave me no real benefit. For one thing, most of my "objects" were little more than hashes. Probably 90% didn't have a single class-specific method in them. They just held data. So why not just work with the data directly? And isn't that what FP does?

OK, this time I'm done for real. Er, I mean, I think so...

Chas.

virtualeyes

unread,
Dec 30, 2011, 5:23:08 PM12/30/11
to Xitrum web framework
API is clear/fine (github code/layout reads well too)

Cache options are wonderful, btw ;-)


On Dec 30, 9:31 pm, ngocdaothanh <ngocdaoth...@gmail.com> wrote:
> > why not a centralized routing option and a distributed routing option?
>
> Actually there's always a central place inside Xitrum to store routes.
> I've just exposed APIs for routing and action/page caching, for cases
> you don't want to use annotation.
>
> See:https://github.com/ngocdaothanh/xitrum/blob/master/doc/sphinx/restful...https://github.com/ngocdaothanh/xitrum/blob/master/doc/sphinx/cache.rsthttps://github.com/ngocdaothanh/xitrum/blob/master/src/main/scala/xit...

virtualeyes

unread,
Dec 30, 2011, 5:50:08 PM12/30/11
to Xitrum web framework
Chas,

I do not deny that ORMs are an abomination, but for back end CRUD
operations and schema generation, there is nothing better. Generated
SQL is generally horrendous, but for persisting data, sure, why bother
typing insert/update/delete statements by hand? If the data to be
persisted passes validation, let a separate component handle the task.
It's like converting an object to JSON. If possible I'd prefer to say
Foo('blah', blee).asJson() vs writing an implicit conversion to let
JSON convertsion utility know the property types of my object.

On the public facing side of the fence, go for speed of course,
efficient read only queries against RDBMS and/or in-memory DB sans
ORM. ScalaQuery would fit nicely here.

And yes, if there is DB specific work to be done, at application level
there will likely be a performance penalty (although I bet you'd hit
it less with Scala vs Ruby ;-))

As for pure FP, sure, Mongo and friends would be a nice match; queries
return a JSON result, so no conversion from db result to object to
JSON needs to occur, just pass on to the client.

Would be incredible if MySQL, Postgres or any viable RDBMS could
return JSON result set!

Noah

On Dec 30, 9:44 pm, Charles Munat <charles.mu...@gmail.com> wrote:
> Actually, what I want to do is give up on OOP entirely in my web framework,
> and find a pure FP approach. Then I'd use an RDBMS directly when it was the
> right place to persist my data (i.e., the data was set-oriented or
> tabular), but I'd use, say, a DB like HypergraphDB when I needed to work
> with graphs. Or something like BaseX (which is GREAT) when I wanted to just
> store HTML (well, XHTML, obviously) and maybe manipulate it a little. BaseX
> is not too bad for trees, either, and it has a great little GUI client. Or
> maybe use a document database for trees... ah, my cup runneth over.
>
> ORMs suck. They've gotten a lot better, but they are the answer to a
> question that no one should have asked: We've got a DB that only
> understands shades of red, and a business layer that only understands
> shades of blue. What do we do? Build a blue-red converter is not a good
> answer in my book. All this complexity, for what? For most of the sites on
> which I've used ActiveRecord or Hibernate, I have never once taken
> advantage of any of the real benefits of a *relational* database. It's just
> ...
>
> read more »

ngocdaothanh

unread,
Dec 31, 2011, 2:17:00 PM12/31/11
to Xitrum web framework
Noah,

I've added your catchy lines to README:
https://github.com/ngocdaothanh/xitrum/blob/master/README.rst

Hope that you don't mind.
Ngoc

virtualeyes

unread,
Dec 31, 2011, 3:42:37 PM12/31/11
to Xitrum web framework
Ngoc, sure, not a problem, testimonials always help and, well, my
father worked in marketing for many years, so I guess some of that
rubbed off on me ;-)

What's your feel for going Jersey-style method level route
annotations? Are you considering that, or too much of a hassle to
implement?

Saw the Scalata docs, cool re-addition to the framework.

and hey, everyone, Happy New Year! (2012 is 2 hours away here in
France, heading out...)

Best, Noah

ngocdaothanh

unread,
Dec 31, 2011, 11:01:08 PM12/31/11
to Xitrum web framework
Noah,
Bonne année.

Thanks.

With Scalate views, actions are left too lonely.

With the observation that Scala "object" is just a Java class, and
normally you don't
put actions in parent classes of controllers, I think Jersey-style
method-level annotated
routes can be implemented without sacrificing reverse routing feature.

I'm exploring this direction.

Ngoc

virtualeyes

unread,
Jan 1, 2012, 7:20:25 AM1/1/12
to Xitrum web framework
Ngoc,

yes, if you check out Play 2.0 controller documentation
https://github.com/playframework/Play20/wiki/ScalaControllers

you see that they use a singleton object as well, perhaps to overcome
the reverse routing issue that you mention.

Current Xitrum controller approach is a bit more on the Lift side of
the fence, where view snippets are generated and sent directly to the
response. Scalate creator James Strachan said that while JSP-style
template engines run the risk of having too much code in the view
(i.e. embedding application logic in the view), the Lift approach runs
the risk of too much view in the code.

Personally lean controllers are preferred, they handle routes, perform
pure business logic (or delegate complex operations to a service/
helper class), grab domain data to pass off to the view or render
directly to the response for ajax/json requests, etc.

Jersey-style method level annotations would be awesome, nobody is
doing that in Scala, and the idea of compiling routes file at compile-
time is brilliant. Why go looking elsewhere (in a separate route file)
to troubleshoot why, say, a given param is not getting passed through
to target controller method? The annotation describes programmer
intent right at the source.

Now, the only drawback I see in not having a dedicated routes file
comes when dealing with default REST operations; e.g. where GET("/
foo") always invokes Foo.list(), GET("/foo/:id") always invokes
Foo.show(id: Long) and so on. Annotating methods for controllers that
share common CRUD actions in this case becomes a boilerplate of sorts,
a bit less DRY than one would like. I wonder if a class level
annotation would help here, something like:

@CRUD
object Foo {
def show(id: Long) {} @GET("/foo/:id") implied
def list() {} @GET("/foo") implied
def create() {} @GET("/foo/create") implied
def save() {} @POST("/foo") implied
}

The common CRUD methods would be compile-time enforced (so show, list,
create, etc. methods must all be defined). For controllers with unique
routing requirements, then use default Jersey-style method level
annotation.

I am liking Xitrum potential in 2012 ;-)

Regards,
Noah

Charles Munat

unread,
Jan 1, 2012, 2:50:13 PM1/1/12
to xitrum-f...@googlegroups.com
Hmm. I'm not too keen on an @CRUD annotation, though I guess if that's what most people like, then why should I deny them. As long as no one forces me to use it. But I disagree strongly with the way REST is typically done, namely, that a POST is used for creation. That's not idempotent, and I don't see any benefit to that and a lot of drawbacks. I prefer to use PUT for both creation and modification. So the way you'll probably do @CRUD will prevent me from every using it.

If you use UUIDs for your keys -- and I really, really do not get why this is so unpopular with some people -- it's a simple matter to generate a new UUID and send that with the PUT. Then, the back end simply puts it. If there's nothing there, then now there is. If there's something there, it gets overwritten. Very simple, and totally idempotent. I can click on that create button all day -- I'll never make an accidental duplicate.

And with UUIDs, no one ever guesses the ID of an object that they have no business looking at. It's a nice extra measure of security. And merging tables is never a problem! And each ID in the database is UNIQUE, not just unique to that table. This should be a no-brainer from my perspective. Why isn't it? No idea.

It's no problem to create a UUID generator and source all your UUIDs from it, so you reduce (eliminate, really) the chances of a collision. So if my object is a User, then my REST routes might look like this:

GET    users         // return all users
GET    users/<uuid>  // return user #<uuid>
PUT    users/<uuid>  // create or update user #<uuid>
DELETE users/<uuid>  // delete user #<uuid>

So if @CRUD is going to automatically create a POST route, it's of no use to me.

Note that the typical /users/new and /users/edit routes are not really part of REST. REST is how one does the CRUD. New and Edit are how the website displays the HTML forms for interacting with the REST interface, they're not part of the REST interface. So would they be created by @CRUD? What if I'm only doing the web service, and I don't need forms?

This is what I mean by too much magic. It's what I hate about Rails and a lot of other frameworks. Granted, I don't have to use the magic, but really, time spent making magic spells is time not available for adding other, more useful (IMO) features.

But note that the new/edit form can be combined easily if you're using the above strategy. When the form webpage is requested, if it has a UUID, it uses that. If it doesn't, it gets one and redirects (or you could use AJAX to get one slyly). If the record exists, it displays it for editing. If not, it displays a blank form.

So, in other words, when I display a page with a link to the new form, I fill it in with an unused UUID thus: /user_form/<uuid>. Calling user_form/<uuid> means the server checks for a user at that UUID. If it finds one, the edit form is displayed. If not, the new form is displayed. Either way, it's very simple.

If the user goes to /user_form without a UUID, the server simply generates one and redirects to /user_form/<uuid>.

I find this a much more robust, stable, and DRY way to go about this than the currently popular, Rails-inspired method.

This is what I like most about the Circumflex way of doing this. When I subclass a router to create my CRUD methods for a given object, then I can provide the base URL as a parameter to the router:

class Users extends Router("/users")

then my method calls are my routes. This seems much more robust to me. I can't "forget" the annotation, or get the annotation out of sync with the route:

get("")          = // gets all users (GET /users)
get("/:uuid")    = // gets user #<uuid>
put("/:uuid")    = // creates or updates user #<uuid>
delete("/:uuid") = // deletes user #<uuid>

(I've added a helper method to look for :uuid in a string and replace it with a regex for UUIDs, but that could be built-in as well.)

Although this method makes the creation/update of an object idempotent -- repeated identical puts do not change anything -- the response is not the same, of course. If a new object was created, then the response should be a 201. If the object was updated, then a 200. If nothing changed, then a 304. (There's some room for disagreement here, but the response should at least be consistent.) As for getting subsets of users from /users, that's what the Range header is for, is it not? Similarly, a successful delete gets a 200, a repeated attempt gets a 404. For asynchronous requests, maybe a 202 is appropriate.

Generally, that's it. I run this application as a web service, though it generally requires log-in to use, so some state is involved.

For my web forms, I build a separate application. So I have a CRUD web service, and a separate administrative interface. So if my domain is zzz.com, I might put the REST app at rest.zzz.com. Then I can use simpler, non-REST routes in my administrative application. So now the user form is at:

GET http://zzz.com/user         // creates a new UUID and redirects to below
GET http://zzz.com/user/<uuid>  // provides a blank form or fills form with user #<uuid>

The form does a PUT (via AJAX, usually, or using a workaround because browsers are still stupid) to


Since the REST part of this is now drop-dead simple, I can create a "BaseRouter" and just inherit from that:

class BaseRouter[T](url: String) extends RequestRouter(url) {
  response.contentType("application/json")

  get("") =           // return all objects of type T
  get(":/uuid") =     // return T #<uuid>
  put(":/uuid") =     // create or update T #<uuid>
  delete(":/uuid") =  // delete T #<uuid>
}

Here is where I build in the 200, 201, 202, 304, 404, etc. responses. And note that it's type safe.

Now my Users router looks like this:

class Users extends BaseRouter[User]("/users") { }

Distributed routes. DRY as hell. Separation of concerns between the REST web application and the HTML administrative interface. No need for annotations. And I can easily override individual routes in the appropriate router to add, for example, property access:

  get(":/uuid/email") =  // returns { "email":"s...@zzz.com" }
                         // or maybe { "user_id":"<uuid>", "email":"s...@zzz.com" }

Or I can filter appropriately:

Instead of

/posts?user_id=<uuid>

I can do:

GET /users/<uuid>/likes

// In Users.scala:
  get("/:uuid/likes") =  // returns all likes for user #<uuid>

I might also have /likes/<uuid>/users as a route, but I can add a canonical header to set the preferred route. Nice.

I am not suggesting that this is the only way to do it, but it's the best way I've found after many, many REST sites. If it's not the preferred way to do it in Xitrum, I'd still like it to be a possible way to do it, albeit with annotations if I must.

Chas.

P.S. Note that if I don't want to make the REST part a separate app, then I can still package those routes separately, and inherit from a RestRouter("/rest"), so now all the REST routes are under /rest (e.g. /rest/users/<uuid> is the interface for user #<uuid>, and /users/<uuid> is the HTML interface for user #<uuid>).

virtualeyes

unread,
Jan 1, 2012, 3:55:08 PM1/1/12
to Xitrum web framework
Chas, awesome reply!

Thanks for the REST/UUID primer, that is an incredibly concise
implementation you are describing.

What limitations have you encountered with this approach? You
mentioned that, "browsers are still stupid"; I assume there is some
minor road block to be worked around.

UUID implementation truly sounds "perfect" for new applications, but
I'm wondering about existing applications that do not rely on UUIDs
(despite the fact that maybe they should ;-)). Off the top of my
head, rewriting/redirecting existing URIs to new UUID-enabled URIs for
search engines sounds like a fair bit of work, as well as
restructuring the DB itself.

I'm going to have to research the UUID issue, had never considered an
application-wide UUID site.

Circumflex subroutes are indeed very cool, that really grabbed my
attention when I was comparing Scalatra and Circumflex.

Ok, back to recovering from too much good wine in the New Year
celebrations. Too much of a good thing is indeed very bad, or at
least the next day is ;-)

Noah

On Jan 1, 8:50 pm, Charles Munat <charles.mu...@gmail.com> wrote:
> Hmm. I'm not too keen on an @CRUD annotation, though I guess if that's what
> most people like, then why should I deny them. As long as no one forces me
> to use it. But I disagree strongly with the way REST is typically done,
> namely, that a POST is used for creation. That's not idempotent, and I
> don't see any benefit to that and a lot of drawbacks. I prefer to use PUT
> for both creation and modification. So the way you'll probably do @CRUD
> will prevent me from every using it.
>
> If you use UUIDs for your keys -- and I really, really do not get why this
> is so unpopular with some people -- it's a simple matter to generate a new
> UUID and send that with the PUT. Then, the back end simply *puts *it. If
> there's nothing there, then now there is. If there's something there, it
> gets overwritten. Very simple, and totally idempotent. I can click on that
> create button all day -- I'll never make an accidental duplicate.
>
> And with UUIDs, no one ever guesses the ID of an object that they have no
> business looking at. It's a nice extra measure of security. And merging
> tables is never a problem! And each ID in the database is UNIQUE, not just
> unique to that table. This should be a no-brainer from my perspective. Why
> isn't it? No idea.
>
> It's no problem to create a UUID generator and source all your UUIDs from
> it, so you reduce (eliminate, really) the chances of a collision. So if my
> object is a User, then my REST routes might look like this:
>
> GET    users         // return all users
> GET    users/<uuid>  // return user #<uuid>
> PUT    users/<uuid>  // create or update user #<uuid>
> DELETE users/<uuid>  // delete user #<uuid>
>
> So if @CRUD is going to automatically create a POST route, it's of no use
> to me.
>
> Note that the typical /users/new and /users/edit routes are not really part
> of REST. REST is how one does the CRUD. New and Edit are how the website
> displays the HTML forms for interacting with the REST interface, they're *not
> part of* the REST interface. So would they be created by @CRUD? What if I'm
> only doing the web service, and I don't need forms?
>
> This is what I mean by *too much magic*. It's what I hate about Rails and a
> lot of other frameworks. Granted, I don't have to use the magic, but
> really, time spent making magic spells is time not available for adding
> other, more useful (IMO) features.
>
> But note that the new/edit form can be combined easily if you're using the
> above strategy. When the form webpage is requested, if it has a UUID, it
> uses that. If it doesn't, it gets one and redirects (or you could use AJAX
> to get one slyly). If the record exists, it displays it for editing. If
> not, it displays a blank form.
>
> So, in other words, when I display a page with a link to the new form, I
> fill it in with an unused UUID thus: /user_form/<uuid>. Calling
> user_form/<uuid> means the server checks for a user at that UUID. If it
> finds one, the edit form is displayed. If not, the new form is displayed.
> Either way, it's very simple.
>
> If the user goes to /user_form without a UUID, the server simply generates
> one and redirects to /user_form/<uuid>.
>
> I find this a much more robust, stable, and DRY way to go about this than
> the currently popular, Rails-inspired method.
>
> This is what I like most about the Circumflex way of doing this. When I
> subclass a router to create my CRUD methods for a given object, then I can
> provide the base URL as a parameter to the router:
>
> class Users extends Router("/users")
>
> then my method calls *are* my routes. This seems much more robust to me. I
> can't "forget" the annotation, or get the annotation out of sync with the
> route:
>
> get("")          = // gets all users (GET /users)
> get("/:uuid")    = // gets user #<uuid>
> put("/:uuid")    = // creates or updates user #<uuid>
> delete("/:uuid") = // deletes user #<uuid>
>
> (I've added a helper method to look for :uuid in a string and replace it
> with a regex for UUIDs, but that could be built-in as well.)
>
> Although this method makes the creation/update of an object idempotent --
> repeated identical puts do not change anything -- the response is not the
> same, of course. If a new object was created, then the response should be a
> 201. If the object was updated, then a 200. If nothing changed, then a 304.
> (There's some room for disagreement here, but the response should at least
> be consistent.) As for getting subsets of users from /users, that's what
> the Range header is for, is it not? Similarly, a successful delete gets a
> 200, a repeated attempt gets a 404. For asynchronous requests, maybe a 202
> is appropriate.
>
> Generally, that's it. I run this application as a web service, though it
> generally requires log-in to use, so some state is involved.
>
> For my web forms, I build a separate application. So I have a CRUD web
> service, and a separate administrative interface. So if my domain is zzz.com,
> I might put the REST app at rest.zzz.com. Then I can use simpler, non-REST
> routes in my administrative application. So now the user form is at:
>
> GEThttp://zzz.com/user        // creates a new UUID and redirects to below
> GEThttp://zzz.com/user/<uuid>  // provides a blank form or fills form with
> way I've found after many, many REST sites. If it's not the *preferred* way
> to do it in Xitrum, I'd still like it to be a *possible *way to do it,
> > > I'm exploring this direction....
>
> read more »

Charles Munat

unread,
Jan 1, 2012, 5:00:15 PM1/1/12
to xitrum-f...@googlegroups.com
The "browsers are still stupid comment" refers to the sad fact that most (if not all) browsers still limit the method in a form to either GET or POST, so web frameworks (such as Rails) try to work around this by adding a  { "_method":"PUT" } field to the form. You can also get around it by submitting the form with AJAX. But come on, folks! It's 2012 now! Can I please has HEAD, PUT, and DELETE in my HTML forms?

As for legacy sites, I would say you're mostly doomed. If it were me, I'd either stick with the current method, or I'd write a new site the way I suggest, then write a program that went through the legacy database and converted it to UUIDs. Then I'd have to schedule a brief downtime (not always possible, but, for example, Christmas day might be a good one) to do the changeover.

But adding some middle layer to do the conversion on each request? No way.

Although there IS one option, now that you mention it, and I've used it before when dealing with PITA ORMs that insist on using serial integers as the PK (for example, that was true on Circumflex's ORM, though not sure it still is). The solution is to simply add a "code" field for the UUID and let the ORM manage the actual PK. One benefit of this is you're no longer exposing the real PK. Now you set that UUID field to UNIQUE and do your lookups on that field rather than the PK. If you're using a lot of ORM magic, then that might be a pain. But for simple setups it works very well.

BTW, you can make the create/update drop dead simple, too, whether you do it this way or with the UUID as the PK. Simply try to create a new record with the PUT, then catch the error and resubmit it as an update instead. This is better than always doing a lookup to see if the record already exists because with a create it simply does it. If you didn't care about DB agnosticism, you could even write a procedure into your DB that converts failed creates to updates automatically. I've done that before, too. And if you're using NoSQL, it's even easier.

If you're using an ORM with a simple "save" method, you can even skip that step sometimes, and just check the response of the save method to determine whether it was a create or an update (or you can check other parameters, for example in Hibernate, to see if the object is persisted already or not). That way you can see which HTTP response code to send.

I'm not very smart, so I like things as simple and foolproof as possible.

Chas.

virtualeyes

unread,
Jan 2, 2012, 6:28:59 AM1/2/12
to Xitrum web framework
ah, ok, the browser GET/POST limitation explains why GET/PUT/DELETE is
not a web framework standard.

Not an issue for me, however, all form "posts" are ajax'd in the apps
I develop.

UUID is not going to happen for the legacy project I'm intending to
use with Xitrum. Too many headaches involved in converting the entire
system, and UUIDs would appear to throw pretty URIs out the window
(i.e. yes, security-wise, impossible to guess, but then again also
impossible to remember). I still need to research the use of UUIDs in
web applications, obviously it's being done, I'm just wondering about
the use cases, perhaps more geared to REST APIs? Anyway, on the code-
end, UUIDs seem to be the tightest CRUD implementation possible, so
very coder friendly.

Try/Catch'ing create/update is a nice idea as well; Rails may be doing
this behind the scenes on find_by_or_create.

I'm not going to stress the REST, I have more pressing concerns, like
finding a Scala ORM that doesn't suck ;-) Dynamic languages afford a
lot of freedom (and yes, room for error), so the ORM DSLs in A-R and
GORM, for example, are elegant and concise; not the case to-date in
Scala, and even with the added boilerplate of defining "fat" case
classes (where you must specify type and property name in triplicate),
there is no, say, LINQ-to-SQL or Entity Framework equivalent where the
boilerplate is auto-generated based on an existing DB schema.
Basically Scala ORMs and JDBC wrappers are not yet mature enough to
provide the full set of tools to quickly get up & running,
particularly with legacy applications.

Looks like ScalaQuery, who, like Play, has been adopted by TypeSafe,
will be coming out with their LINQ-to-SQL inspired version in Q3, so
probably a GA in 9 months. Not much appealing otherwise (QueryDSL,
Squeryl, DaoMapper, etc. all leave something to be desired). Might
have to get a standalone GORM running and hack persistence together
that way. Then use ScalaQuery for front end queries. Blah,
everything but DB related tasks looks great in Scala, drag...


On Jan 1, 11:00 pm, Charles Munat <charles.mu...@gmail.com> wrote:
> The "browsers are still stupid comment" refers to the sad fact that most
> (if not all) browsers still limit the method in a form to either GET or
> POST, so web frameworks (such as Rails) try to work around this by adding a
>  { "_method":"PUT" } field to the form. You can also get around it by
> submitting the form with AJAX. But come on, folks! It's 2012 now! Can I
> please has HEAD, PUT, and DELETE in my HTML forms?
>
> As for legacy sites, I would say you're mostly doomed. If it were me, I'd
> either stick with the current method, or I'd write a new site the way I
> suggest, then write a program that went through the legacy database and
> converted it to UUIDs. Then I'd have to schedule a brief downtime (not
> always possible, but, for example, Christmas day might be a good one) to do
> the changeover.
>
> But adding some middle layer to do the conversion on each request? No way.
>
> Although there IS one option, now that you mention it, and I've used it
> before when dealing with PITA ORMs that *insist *on using serial integers
> ...
>
> read more »

Charles Munat

unread,
Jan 2, 2012, 1:51:33 PM1/2/12
to xitrum-f...@googlegroups.com
I think that the use of OOP in web sites has gotten people all confused. They start thinking of objects, and suddenly everything is an object.

But for a regular web site, almost everything is a document of some sort, and pages are ordered collections of documents (arrays), and sites are collections of pages (sets). And REST is perfectly appropriate for use with documents, but cares nothing about UUIDs or serial IDs. It's about URIs. And URIs for anything with which humans interact should be readable and descriptive.

You might check out this site I'm just getting ready to debut for my mother. It's my first Rails site in a long time (it seemed to fit Rails, my brother is a Rails developer, and I needed to get caught up on the latest Rails tricks, but it will probably be my only Rails site for a while).


If you look at the various pages and check the URLs, you'll see that they are all descriptive, e.g. /excerpts_from_the_book. If you look at the source, you'll see I've very carefully included metadata, including the canonical link for each page. (Note also that I'm very careful to make sure my pages validate as HTML5.) These pages are being served through a Rails controller, and the paths are set in routes.rb and are virtual -- they have nothing to do with the file system. But the URL should make perfect sense to a user bookmarking the page or typing it in, and they will also help with SEO. And the structure of the site -- in this instance pretty much flat -- is mirrored in the virtual URLs.

I use UUIDs when I'm dealing with CRUD for a large database with thousands or millions of rows of data: in other words, when the individual "objects" are not pages. Creating individual, descriptive, unique URLs for each is just not possible. As for readability of the URL with a UUID, does anyone really type into a CRUD interface a URL such as /users/72543 ? I doubt it. You go to the page and find the user by name or email address and click on the row in the table and then you see that user. A URL such as /users/0c471cc668fb1bd15933e82b1cd6a376 can be bookmarked just as easily, and that's they way most people would come back to a specific record. In these instances, I care little about readability, and everything about security. A UUID is optimal.

People hand type URLs when they are going to documents on the web, usually. That's where a URL like /excerpts_from_the_book really helps. For me, if a resource accessed via a REST interface is immutable, i.e., I'm only allowing GETs, then a human readable URI is the probably way to go. But if I'm allowing PUTs and DELETEs, even behind a log in, I prefer to have unguessable URIs, thus UUIDs. It's just too easy for me to forget to check for authorization one time, and to have some dork guessing at URIs and making a mess of my DB. Lawsuit time. No thanks.

On the other hand, I'm strongly opposed to the sort of URL encrypting that Lift does and Xitrum seems to do, too, where the encrypted URLs are good only for the session. I think I mentioned in another post here how I got screwed on that little trick. Plus, it's extra state I don't want to have to worry about. OK, maybe they would be acceptable (thought they destroy bookmarking) if they were permanent until the user manually logged out -- meaning that a time out would leave them intact. But I digress.

If you're coding a blog or some kind of document-oriented site (a news site, for example, or an online magazine), and you're storing the documents in a database, then it should be no problem to create one (or more) "path" parameters to store a unique path for that document, generally a virtual path involving dates. For example: /posts/2012/01/02/when_to_use_rest. Because you are using dates, it's easy to automatically create understandable file names ("when_to_use_rest") that are unique within that date. In contrast, when you dump all the documents into a single folder, then it gets hard to autogenerate unique but descriptive names. Too many collisions, and you end up with crap like "when_to_use_rest_3," which defeats the readability somewhat.

But you can still use the UUID for the PK here -- it's just doing it's work behind the scenes. And that's what I would do.

Note that if you have another unique attribute in your object, you can always use that in your URL, e.g., /users/joe_example.com (it's more readable to replace the @ with a _ than use %40, but that may be more trouble than you think it's worth). Or if you have unique usernames: /users/chasm. And you can still use the UUIDs for the REST API. But you give up the security of the unguessable ID. In those cases, I might provide a GET /users/chasm. But for the PUT and DELETE, I would insist on the UUID: PUT /users/0c471cc668fb1bd15933e82b1cd6a376. Hope that makes sense: readability is fine for GETs, not so good for PUTs and DELETEs, where I want the URI unguessable.

OK, I'm rambling. But this is all very workable. Still, I would be very hesitant to try to back fit this onto a legacy system. Too much work; too many potential disasters. And changing URIs is usually a bad idea. But on any new project, I insist on doing it this way.

Chas.

virtualeyes

unread,
Jan 2, 2012, 4:10:05 PM1/2/12
to Xitrum web framework
Chas,

nice Rails site -- your dad, some of those pics, I swear it's Ram
Dass! (AKA Richard Alpert, the Harvard Professor who, along with his
cohort, Tim Leary, sent a generation into LSD oblivion)

Anyway, like the site, what did you use theme-wise, anything Rails gem
related, or do you roll the front end yourself?

I agree re: document orientation of sites; it would be worlds easier
if I could get away with MongoDB for this project, and thereby
circumflex, errrr, circumvent verbosity of Scala type system (i.e.
Mongo result set returns JSON, so send that directly to client-side JS
and avoid the whole map-to-scala-object-then-to-json-then-to-client-
side mess). Unfortunately, NoSQL is a no-opt, the relations are too
complex, RDBMS it must be, so I have to find a way to get SQL result
sets mapped to case classes and then converted to JSON. Play's ANORM
may be the best fit here (the "MAGIC" option magically converts an SQL
result set to case object without your having to specify case class
property types ad nauseum)

I know the feeling re: getting burned with encrypted or session
dependent URIs. It truly sucks when a client loses data they spent
40+ minutes working on. This is one of several reasons that all my
forms are AJAX-only; that way, if session has expired, the user has
not gone anywhere, their data is still there; I just display a modal
login window and then they can submit the form again.

More & more I'm trying to offload application tasks to client-side.
Ideally a strongly typed non-java javascript generator will arise
(Fantom I belive is doing this), leaving server-side to generate the
client-side app, deliver data and perhaps handle state.

For now, server-side still rules...

Noah
> are not *pages*. Creating individual, descriptive, unique URLs for each is
> just not possible. As for readability of the URL with a UUID, does anyone
> really type into a CRUD interface a URL such as /users/72543 ? I doubt it.
> You go to the page and find the user by name or email address and click on
> the row in the table and then you see that user. A URL such as
> /users/0c471cc668fb1bd15933e82b1cd6a376 can be bookmarked just as easily,
> and that's they way most people would come back to a specific record. In
> these instances, I care little about readability, and everything about
> security. A UUID is optimal.
>
> People hand type URLs when they are going to *documents* on the web,
> usually. That's where a URL like /excerpts_from_the_book really helps. For
> me, if a resource accessed via a REST interface is immutable, i.e., I'm
> only allowing GETs, then a human readable URI is the probably way to go.
> But if I'm allowing PUTs and DELETEs, even behind a log in, I prefer to
> have unguessable URIs, thus UUIDs. It's just too easy for me to forget to
> check for authorization one time, and to have some dork guessing at URIs
> and making a mess of my DB. Lawsuit time. No thanks.
>
> On the other hand, I'm strongly opposed to the sort of URL encrypting that
> Lift does and Xitrum seems to do, too, where the encrypted URLs are good
> only for the session. I think I mentioned in another post here how I got
> screwed on that little trick. Plus, it's extra state I don't want to have
> to worry about. OK, maybe they would be acceptable (thought they destroy
> bookmarking) if they were permanent until the user *manually* logged out --
> meaning that a time out would leave them intact. But I digress.
>
> If you're coding a blog or some kind of document-oriented site (a news
> site, for example, or an online magazine), and you're storing the documents
> in a database, then it should be no problem to create one (or more) "path"
> parameters to store a unique path for that document, generally a virtual
> path involving dates. For example: /posts/2012/01/02/when_to_use_rest.
> Because you are using dates, it's easy to automatically create
> understandable file names ("when_to_use_rest") that are unique *within that
> date*. In contrast, when you dump all the documents into a single folder,
> then it gets hard to autogenerate unique but descriptive names. Too many
> collisions, and you end up with crap like "when_to_use_rest_3," which
> defeats the readability somewhat.
>
> But you can still use the UUID for the PK here -- it's just doing it's work
> behind the scenes. And that's what I would do.
>
> Note that if you have another unique attribute in your object, you can
> always use that in your URL, e.g., /users/joe_example.com (it's more
> readable to replace the @ with a _ than use %40, but that may be more
> trouble than you think it's worth). Or if you have unique usernames:
> /users/chasm. And you can still use the UUIDs for the REST API. But you
> give up the security of the unguessable ID. In those cases, I might provide
> a GET /users/chasm. But for the PUT and DELETE, I would insist on the UUID:
> PUT /users/0c471cc668fb1bd15933e82b1cd6a376. Hope that makes sense:
> readability is fine for GETs, not so good for PUTs and DELETEs, where I
> want the URI unguessable.
>
> OK, I'm rambling. But this is all very workable. Still, I would be very
> hesitant to try to back fit this onto a legacy system. Too much work; too
> many potential disasters. And changing URIs is usually a bad idea. But on
> any new project, I *insist *on doing it this way.
> ...
>
> read more »

Charles Munat

unread,
Jan 2, 2012, 7:10:49 PM1/2/12
to xitrum-f...@googlegroups.com
Ha, ha. Ram Dass. My brother's gonna love that. I'm pretty sure he thinks that our father was Ram Dass. Actually, I think he was, too, in a way, though definitely not during the acid phase. But the difference is that my brother likes Ram Dass. I am a lot more critical of him (though not for the drug thing). This has been a point of contention, so it's funny that you make the comparison. I'll have to tell him. I'm old enough to remember Ram Dass from when he was still Dr. Alpert, or at least Baba Ram Dass.

My last site used node.js, underscore.js, backbone.js, and data.js. Backed transparently by CouchDB. Data.js is an in-the-brower graph DB. The whole site is essentially one page. The data gets loaded into the browser memory (AJAX as necessary), and the "pages" then change instantly with the URLs rewritten using Javascript. It looks like you're changing pages, and there are no fragment identifiers in the URLs, but there's no trip to the server. I think it's the future of websites. Everything is still bookmarkable (you can enter on any "page"), but it's extremely fast and you can work offline and then merge things when you go back online. It also uses now.js so other users updates are pushed immediately to your browser. Very nice.

It's a node.js back end, but it could be done in Scala pretty easily.

Chas.

ngocdaothanh

unread,
Jan 3, 2012, 3:11:19 AM1/3/12
to Xitrum web framework
I've been exploring routing without annotations, the result so far is
very good. Controller and its actions look like below. I'm cleaning up
Xitrum, updating the Quickstart and doc. The new version may be
released this week.

Thanks for insisting on adding Scalate, removing annotations, and
putting related actions together into controller. They're new features
of the new version.

class Articles extends AppController {
pathPrefix("articles")

val index = GET() {
renderView()
}

val show = GET(":id") {
renderView()
}

val niw = first.GET("new") {
renderView()
}

val create = POST() {
renderView(niw)
}

val edit = GET(":id/edit") {
renderView()
}

val update = PUT(":id") {
renderView(edit)
}

val destroy = DELETE(":id") {
redirectTo(index)
}
}

Ngoc

virtualeyes

unread,
Jan 3, 2012, 10:38:56 AM1/3/12
to Xitrum web framework
The pics say something about your father's "state", the Ram Dass
reference was a solid complement.

re: single page js, I ran across an english newspaper site the other
day with this kind of implementation. Pretty cool stuff for sure, but
for some reason my cpu cranked up when clicking around the "pages".
That tends to happen with js heavy implementations I guess, the client
has to do more work.

Xitrum is shaping up, Ngoc is amazing!

Noah

On Jan 3, 1:10 am, Charles Munat <charles.mu...@gmail.com> wrote:
> Ha, ha. Ram Dass. My brother's gonna love that. I'm pretty sure he thinks
> that our father *was* Ram Dass. Actually, I think he was, too, in a way,
> though definitely not during the acid phase. But the difference is that my
> brother *likes* Ram Dass. I am a lot more critical of him (though not for
> the drug thing). This has been a point of contention, so it's funny that
> you make the comparison. I'll have to tell him. I'm old enough to remember
> Ram Dass from when he was still Dr. Alpert, or at least *Baba* Ram Dass.
> ...
>
> read more »

Charles Munat

unread,
Jan 3, 2012, 10:51:52 AM1/3/12
to xitrum-f...@googlegroups.com
No worries. I recognize compliments when given them. :-)

The news site must have been doing something complicated. The site I built is extremely fast, showing the spinner only when loading data, and then usually only for a split second. Once data is loaded, page changes are essentially instantaneous. It uses ejs templates. I'd show it to you, but it's behind a log in.

I agree about Ngoc and Xitrum. I am very curious to try this new version. I was able to substitute a Ruby version of the crawler I was building (I'd built it as proof of concept) so I have given myself more time for the conversion to Scala. Hopefully, Xitrum will be a good fit. Or maybe Blue Eyes for that and Xitrum for one of the other sites I'm building.

Very exciting times.

Chas.

virtualeyes

unread,
Jan 3, 2012, 11:56:21 AM1/3/12
to Xitrum web framework
Awesome stuff, Ngoc!

Now with domain-specific actions grouped under a single controller,
one can mixin behavior without duplication. The new route
implementation is getting quite DRY, nice work.

Question:
val show = GET(":id") {
renderView()
}

what type is param("id") in this case? I assume String and then we
convert to desired type (e.g. Long). I ask because I'm working on a
simple domain conversion utility to handle repetitive tasks

object simpleConverters {
import java.util.Date
implicit def parseInt(s:String) = Integer.parseInt(s)
implicit def str2Date(s:String) = ...
}

and then when binding params to case class(es), rather than getting a
type conversion error, the utility automatically converts missing
types accordingly (or tries to). One can of course convert manually
prior to binding as well. I was looking for something akin to Groovy
proxy interceptors in Scala, looks like implicits are just that.

Regards,
Noah

ngocdaothanh

unread,
Jan 3, 2012, 1:11:51 PM1/3/12
to Xitrum web framework
> val show = GET(":id") {
>   renderView()
> }
>
> what type is param("id") in this case?

param("id") is a String.

Please see "convertText":
https://github.com/ngocdaothanh/xitrum/blob/master/src/main/scala/xitrum/scope/request/ParamAccess.scala

It lets you write param[Long]("id") to get a Long.

Do you have idea to integrate your conversion utility with
convertText, or change convertText to make the conversion more
convenient?

I've been exploring typesafe extracting of params in route URL with
partial function and unapply/unapplySeq without much success.

Any solution should meet both requirements:
1. Typesafe extracting params in route URL
2. Allow reconstructing URL

Ngoc

virtualeyes

unread,
Jan 3, 2012, 2:34:10 PM1/3/12
to Xitrum web framework
Ngoc,

the simple type converter I was intending to use for domain objects
(i.e. creating case class instances bound to params map where string
value types are fine, just needed to know what value type to expect).

I am not sure how other frameworks handle the automatic conversion of
URI, "/foo/:id" to show(id: Long) {...}. There must be implicit
conversions at work along with reflection to determine the type that a
given method expects. Reflection, it should be said, is painful in
Scala, particularly with case classes. Hope that improves with new
Scala reflection API in 2.10.

I do not see anything wrong with param[Long]("id"), actually seems
like a nice implementation. Unless the method can take type(s):

val show = GET[Long](":id") {...}

How could the framework predict the value type that the developer
wants?

Noah

On Jan 3, 7:11 pm, ngocdaothanh <ngocdaoth...@gmail.com> wrote:
> > val show = GET(":id") {
> >   renderView()
> > }
>
> > what type is param("id") in this case?
>
> param("id") is a String.
>
> Please see "convertText":https://github.com/ngocdaothanh/xitrum/blob/master/src/main/scala/xit...

ngocdaothanh

unread,
Jan 3, 2012, 3:54:06 PM1/3/12
to Xitrum web framework
The new Xitrum is in usable form.
I've published 1.8-SNAPSHOT.
Because of a lot of changes, the next version may be called 2.0.

Please try the new Quickstart (not completed yet, but works):
https://github.com/ngocdaothanh/xitrum-quickstart

If you are updating Quickstart, please remove existing routes.sclasner
file because it may prevent recollecting new routes in the new Xitrum.

Ngoc

ngocdaothanh

unread,
Jan 3, 2012, 8:49:32 PM1/3/12
to Xitrum web framework

Ngoc Dao

unread,
Jan 3, 2012, 8:53:16 PM1/3/12
to Xitrum web framework
Reply all
Reply to author
Forward
0 new messages