Monday, February 27, 2012

Neo4J with Scala Play! 2.0 on Heroku (Part 8) :: Scala template+Arbor.js to browse Neo4J via Play 2.0


Note

This post is a continuation of this post, which is the seventh part of a blog suite that aims the use of Neo4j and Play2.0 together on Heroku.

Viewing Neo4J Model Object in Play2.0

Goal

In this post, I'll talk about some functionalities that Play2.0 offers to create web application/site.

The main goal will be to have html views that enable us to create User, Group and link them, but not only, we'll use arbor.js to view what's being created or linked in Neo4J as a... graph of course.

Basically, it will consist into one html page, containing several forms for creating model instance (or link) through AJAX call on Json controllers.

So let's begin by explaining how to define a querying and persisting controllers using Play 2.0 Form.

Controllers

In that case, we'll take basic needs for our use case, that is, to retrieve the users list stored in Neo4J or create a new group.

Get Users

Briefly, Play 2.0 as the notion of controllers to handle server request, such controllers are bound to urls using a route configuration.

So what we have to do here is to create a controller, let's say Users, with a handler named j_all for list of users rendered in Json.

Using what we've discussed in previous posts, such controller and definition are rather simple, check this out:

As we can see, we have simple call the Model persistence utility object to retrieve all defined User in Neo4J. Which we are rendering directly in Json thanks to their Formatter. And finally, we stream the result in the http response.
Mmmh, simple no ? Here we did:

  1. send a Json request to Neo4J requesting all nodes that are linked to the root using the kind users (found using the User's ClassManifest)
  2. retrieve the Json response from Neo4J and un-marshall them in a List[User] (using the User Formatter)
  3. re-render them into the expected Model Json Format (again using the Fomatter)
  4. generate the String representation
  5. append it in the response body
  6. define the content type as being Json
In one single line.

To test it, roughly, just use this url http://localhost:9000/users.json. This will return a Json encoded response.

Create Group

Now, we want to add the possibility to create a new group remotely. For that, we'll create a controller Groups which defines a create handler.

This handler expects to receive a group name. After what, it creates the group instance and persist it in Neo4J.

To recover such request parameter (in a POST since we are creating something and changing the server state), we use a Play 2.0 construction play.api.data.Form that offers a lot of helpers to parse the body into a map of values (can be embedded).

In the following example, the goup name is extracted form the request's body (url encoded) as a nonEmptyText mapped as name. This is a helper mapping for extracting String that cannot be empty.

As we can see, the Form can be directly rendered in the Model instance by giving an apply and unapply functions after the mapping definition.

Javascript Routing

Using static urls are cool... no ok, let's try to use what some calls Web 2.0, you know Ajax.

The problem comes when you have to deal with Urls within Ajax calls. How to keep track of your urls changes for instances.

Pretty hard, so let's forget about hard coded urls in your javascript and use a routes file that can be downloaded client side. This routes file contains all your controllers' url mapping that you want to be exposed in javascript (if I can say).

How it works is simple:
  1. Use Routes.javascriptRouter to define a javascript object and the controllers to be remoted
  2. For each of them, you must use the following object controllers.routes.javascript..
  3. This object is created at compile time when defining the controller in the route conf file
  4. defines a handler (in the Application controller f.i.) that return the result of the javascriptRouter as being javascript file
  5. route this new controller to what you want (like /js/routes)
Having done that, you are now ready to use the created object in the javascript part.

If we take the controller controllers.Users.j_one (returns a User base on its given id), we'll have in our javascript access to a js function playRoutes.controllers.Users.j_one(id) that can takes an id.

By using this js function, you'll have in return a js object that defines at least two useful properties:
  • url: the formatted url for the controller (having compiled the parameter in the url)
  • ajax(c): a jquery (by default) ajax function that takes a payload object, but already defines the url and the method.
So far so good, but to use all of these stuffs, let's see in a coffeescript (thanks Play 2.0) example:

In the previous example, I wrote the ajax call my-self using jQuery... so I could have simply use the ajax property. But nevermind, I love sometime to be control freak.

C'est chic! No?

Arbor.js

For browsing our model graph, I've used arbor.js as the rendering framework, because it's the best one for graph... that's it. 
Since my intent here isn't to explain it, I'll leave you alone with that part. But I recommend you to browse its site here.

So what I did is simply using Users as nodes, all linked to a central root node. Clicking one them will show you their inter-relationships.

I've also added a select box that helps you showing all users in a chosen group.

Taking that the next post will be on how to deploy the whole stuff on Heroku. I don't have at this time any instance in the wild, but if you wish you can clone (and fork) my repo on github for this posts' suite.

But here is a preview of what has been achieved.
Fun but not so cute  -> I'm not a designer... :'(


Next post, the last, will talk about how to deploy this whole thing onto the Heroku PaaS.