Note
This post is a continuation of this post, which is the fifth part of a blog suite that aims the use of Neo4j and Play2.0 together on Heroku.Using Neo4J in Play 2.0
In this post, we'll create a Dispatch Handler that handles Neo4J Rest Json calls in Play's Json object.Having this in our hands, we'll be able to create a really simple service for dispatching Neo4J operations and use them in Play's views.
I've compiled the Play app on github, fork me.
NB: we'll use Dispatch but in case you wish to, you could use the Play's WS feature that might help you a lot (check this out).
Declare Dispatch deps
First of all, we have to update our Play app with the Dispatch dependency. For that, we have to update the sbt configuration file in order to add the related line.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sbt._ | |
import Keys._ | |
import PlayProject._ | |
object ApplicationBuild extends Build { | |
val appName = "Play20WithNeo4J" | |
val appVersion = "1.0" | |
val sbtIdeaRepo = "sbt-idea-repo" at "http://mpeltonen.github.com/maven/" | |
val appDependencies = Seq( | |
// Add your project dependencies here, | |
"net.databinder" %% "dispatch-http" % "0.8.7" withSources | |
) | |
val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings( | |
resolvers ++= Seq( | |
sbtIdeaRepo | |
) | |
) | |
} |
Now, that we have updated the project, let update the application by reloading the configuration (if you're already in sbt console) and rebuild our IDEA project.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Play20WithNeo4J] $ reload | |
[Play20WithNeo4J] $ idea |
Play's Json Handler
Our goal is to use the Neo4J Rest Api that returns responses Json encoded.So here, I'll show how we could have such response directly unmarshalled in Json object. In further posts, we'll use such handling feature to get Model instances directly (which is far more interesting).
What is necessary for that is to create a piece of code that is capable to take a subject and convert it to a JsValue. And since we love functional programming, let us have this method taking a continuation that accepts a JsValue.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dispatch._ | |
import play.api.libs.json._ | |
import play.api.libs.json.Json._ | |
class PlayJsonHandlers(subject: HandlerVerbs) { | |
/**Process response as JsValue in block */ | |
def > => T) = subject >- { | |
(str) => | |
block(parse(str)) | |
} | |
} |
Finally, we use the continuation applied to the parsed result.
Neo4J Service
Let's gather some utility urls to retrieve node, relations. In other words, urls for common usages. This service is left simple for further enhancements (next post).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dispatch._ | |
import models.Model | |
import dispatch.HttpExecutor | |
import utils.dispatch.PlayJsonDispatchHttp._ | |
trait Neo4JRestService { | |
val neoRest = :/("localhost", 7474) | |
val neoRestBase = neoRest / "db" / "data" | |
val neoRestNode = neoRestBase / "node" | |
val neoRestRel = neoRestBase / "relationship" | |
val neoRestCypher = neoRestBase / "cypher" | |
def selfRestUriToId(uri: String) = uri.substring(uri.lastIndexOf('/') + 1).toInt | |
def neoRestNodeIndex(indexName: String) = neoRestBase / "index" / "node" / indexName | |
def neoRestNodeById(id: Int) = neoRestNode / id.toString | |
def neoRestRelById(id: Int) = neoRestRel / id.toString | |
lazy val root:{val id:Int } = Http(neoRestBase <:< Map("Accept" -> "application/json") >! { | |
jsValue => new { | |
val id = selfRestUriToId((jsValue \ "reference_node").as[String]) | |
} | |
}) | |
} |
A Controller To Rule Them All
For the sake of this basic usage of our Handler with Neo4J, here are some examples of such requests. (full controller here).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Neo4J extends Controller { | |
object neo extends Neo4JRestService | |
def createNodeWithProperties = Action { | |
val props = toJson(Map("prop1" -> "value1", "prop2" -> "value2")) | |
val (node, data: JsObject) = Http( | |
(neo.neoRestNode <<(stringify(props), "application/json")) | |
<:< Map("Accept" -> "application/json") | |
>! { | |
jsValue => | |
((jsValue \ "self").as[String], (jsValue \ "data").as[JsObject]) | |
}) | |
Ok("" + node + " -- " + data.toString) | |
} | |
def relationship(id: Int) = Action { | |
val (rel, start, end) = Http(neo.neoRestRelById(id) <:< Map("Accept" -> "application/json") >! { | |
jsValue => | |
((jsValue \ "self").as[String], | |
(jsValue \ "start").as[String], | |
(jsValue \ "end").as[String]) | |
}) | |
Ok("" + start + " - [" + rel + "] - " + end) | |
} | |
} |
Okay, it's repetitive and the Json traversal is not shared. Let's us put this aside until the next post.
And before going ahead, I've created a pretty simple and naive view and url mapping. So check the sources on github, play it and tests the /rest et al. urls.
Next post: Enhance the handler and service to manage Domain Object.
No comments:
Post a Comment