Getting Started with RavenDB Using Pure JavaScript

RavenVsCouchYou might ask: “Why in the world would you create a pure JS app with RavenDB?”  I’m so glad we’re interested in the same things!  I’ve been toying around for a little while with CouchApp – which is a way to host applications completely within a CouchDB NoSQL database.  The idea is to greatly speed development and performance for certain application use cases by avoiding (most of) a server side middle layer.

Use Case

Let’s say you are building an application for internal use.  Assuming you are responsible on the client side, do you really need to have server side data validation?  I suppose you could find a few arguments in favor of it, but do they actually outweigh the cost of implementing a middle tier for this use case?  Really??

I’m going to pretend like you said, “No, Dave – by golly, you’re right.”

In looking at CouchApp, the first problem I ran into is that it’s hard.  Like, really hard.  I mean these guys are probably all into mod’ed out Linux distros and neckbeards and shit.  Which is cool, but the problem is that they are NOT into creating canonical, orderly, convention-based documentation/tests/examples that explain how the hell to do anything.  They are too “relaxed” I guess.  Instead you can do whatever you want, man.  For instance, they have all these different ways to do html rendering.  Half of them are outdated, and the other half are poorly demonstrated.  You get the feeling they are too smart and excited to let stuff mature for 2 months before moving on to the next shiny byte. 

(I’ll admit that last paragraph is probably unfair, but give CouchApp a few hours and see if you don’t feel the same way.)

The other problem I ran into is the sneaking suspicion that the whole thing is dead.  If you look at all the docs, posts and hubbub, it seems to center pretty tightly around 2010 and then tail off after that.  I tried to get some people from the community to give me some feedback about my last post, and all I heard were crickets.

The final straw for me on the whole CouchApp thing was that there is no easy way TO ACCESS THE DATABASE CROSS-DOMAIN.  Are you kidding me?  What the hell is the use of having a database that faces http if you can’t access the thing via http?  The solution is to install a proxy on your Apache server.  WHAT!?  I’m done.

Quoth the Raven

Enter the RavenDB.  If you compare www.RavenDB.net to www.CouchApp.org, it’s pretty glaringly obvious who has their shit together and who doesn’t.  I can hear my imaginary friend say, “Hey Dave, that’s not fair.  CouchApp is like, a side project, dude.  You should be comparing it to http://couchdb.apache.org/.”  And my friend would be right.  So go look at http://couchdb.apache.org/ then.  I guess it is better than CouchApp.org ….

And when that same friend then says –

“But Dave, RavenDB Costs Money and Shit”

– if he is truly concerned about RavenDB costing money, he should use CouchDB, MongoDB or Cassandra or some crap like that … (freeloader).  He should have fun with that.  I’m trying to get things done.  But hey … if my buddy really feels software should be free, then he should probably open source his own project.  Then he could use RavenDB for free.

Ok, maybe that’s a little harsh.  Maybe I’m being too hard on my outspoken pal.  But you know … the tone that I used was EXACTLY HOW I MEANT IT BE.

Brass Tacks

… As in it’s time to get down to them.  How the heck do you get going with RavenDB anyway?  Well the first thing to do is drive your browser over to Mr. Ayende’s shop and get yourself a build.

Ok, on another side note, does this guy Ayende or Oren or Auryn or whatever his name is kick ass or what?  I mean, I know he’s been putting out awesomeness for something like a decade now, but who decides one day that, “Hey, I think I’ll build a NoSQL database by myself.  Oh, and while I’m at it, I’ll make it the best one available on the market.  I’ll actually make it work well, have good documentation, be a (C#) developer’s dream to use, be easily distributable and you know what else?  If somebody sends a message to my mailing list, I’ll respond in less than 5 minutes even if I don’t know them AT ALL.”  Too bad he has a problem with run-on sentences.  Oh wait, that’s me.

Go over to http://ravendb.net/download and pick your poison.  Usually I prefer all things NuGet, but in this case, I didn’t want to find out whether or not the server is in there.  I just downloaded the zipped build.  Unfortunately, the most current build I found (960) had a bug with posting new documents using $.ajax.  This struck me as so egregious that I nearly didn’t write all those nice things above about Ayende, but stumbled in despair back to Couchappland.  Fortunately, the “unstable” build 2063 works … even if it does have some weird ass shit going on with a system database being the default and going completely paisley if you try to do the advanced database creation stuff …. It is labeled “unstable” after all, but I digress … again.

Once you’ve done the dance of unblocking the zip file and extracting it and all that, you can go to the Server subdirectory and type

raven.server /install

Congratulations.  You now have a running RavenDB service.  Beats the hell out of installing SQL Server doesn’t it?  You might also want to compare this process to that of CouchApp in my last post.

Oh wait, do I need to install a management studio?  No, it’s there already.  Just go to http://localhost:8080 if you don’t believe me.  Oh ok, do I need to install some configuration app?  No, you can just hack the config file.  And while we’re talking about it, why don’t we do some configuration file hacking?

Configuring RavenDB

You will find raven.server.exe.config in that same Server directory.  Open it with your favorite text editor and you will see something like this:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <appSettings>
    <add key=”Raven/Port” value=”8080″/>
    <add key=”Raven/DataDir” value=”~\Data”/>
    <add key=”Raven/AnonymousAccess” value=”Get”/>  </appSettings>
    <runtime>
        <loadFromRemoteSources enabled=”true”/>
        <assemblyBinding xmlns=”urn:schemas-microsoft-com:asm.v1″>
            <probing privatePath=”Analyzers”/>
        </assemblyBinding>
    </runtime>
</configuration>

 

Ok, I was actually a little surprised that port 8080 was available on my machine, so I changed that right away.  Also, I don’t want to fiddle with security right now.  Because I’m behind my firewall, I’m going to enable anon access on all interactions, and I’m going to leave Cross Domain Access wide open.  So now I have:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <appSettings>
    <add key=”Raven/Port” value=”49589″/>
    <add key=”Raven/DataDir” value=”~\Data”/>
    <add key=”Raven/AnonymousAccess” value=”All”/>
    <add key=”Raven/AccessControlAllowOrigin” value=”*” />
  </appSettings>
    <runtime>
        <loadFromRemoteSources enabled=”true”/>
        <assemblyBinding xmlns=”urn:schemas-microsoft-com:asm.v1″>
            <probing privatePath=”Analyzers”/>
        </assemblyBinding>
    </runtime>
</configuration>

 

Restart your service.  It’s in the Windows service.msc app or you can just type Raven.Server /restart from the command line in the Server directory.

Let’s Write Some JavaScript Already

Break open your favorite IDE/text editor, and because they all support NuGet, get yourself the QUnit-MVC package.  Or maybe they don’t, and you can get QUnit at www.qunitjs.com.  It’s hidden away down there at the bottom of the page for some stupid reason.

Now we need a test page.  Create an html file, and put this in it:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”
http://www.w3.org/1999/xhtml”>
<head>
    <title>QUnit Test Page</title>
    <link rel=”stylesheet” href=”qunit.css” type=”text/css” />
    <script src=jquery-1.7.1.min.js” type=”text/javascript”> </script>
    <script type=”text/javascript” src=”qunit.js”></script>
         <!– App code goes here –>
    <script src=”app.js” type=”text/javascript”></script>
    <!– Unit test code goes here –> 
    <script src=”appTests.js” type=”text/javascript”></script>
</head>
<body>
    <h1 id=”qunit-header”>Intertwyne QUnit Test</h1>
    <h2 id=”qunit-banner”></h2>
    <h2 id=”qunit-userAgent”></h2>
    <ol id=”qunit-tests”></ol>
</body>
</html>

In a nutshell, this is what QUnit wants in order to display your test results  Obviously it might be better to put these scripts into special directories according to whatever conventions to which you subscribe.  If you actually did get qunit from NuGet, then you’ll need to square up your script and CSS URLs to match the Visual Studio conventions (duh).

Ok, now open up a new file called app.js.  In it, you’ll need to put something like this:

story = window.story || {};

story.url = “http://localhost:49589/docs”;

story.basicInsert = function (insertData, requestorCallback) {
    $.ajax({
        cache:false,
        type: ‘POST’,
        url: story.url,
        dataType: ‘json’,
        contentType: “application/json”,
        data: JSON.stringify( insertData),
        success: function (data) {
            requestorCallback(data);
        }
    });
};

story.basicGet = function (collectionAndKey, requestorCallback) {
    $.ajax({
        url: story.url + ‘/’ + collectionAndKey,
        dataType: ‘jsonp’,
        jsonp: ‘jsonp’,
        success: function (data, textStatus, jqxhr) {
            requestorCallback(data, textStatus);
        }
    });
};

These are a couple of JavaScript functions to write some JSON in and out of your RavenDB database.  I am using a POST rather than a PUT because I didn’t feel like finding a time sequential UUID generator for my IDs.  RavenDB will do that for me if I POST, sending back the results as JSON. 

The GET is requesting the results as JSONP so that my browser doesn’t freak out about cross-domain request results.  If you don’t know what that means, then Google it or ignore it because I took care of it for you.  This blog is already getting epic in length.

The other thing I do for both of these is pass in a callback parameter so our consuming functions can get the asynchronous results.  If you don’t know what a callback is, then consider a different vocation/hobby.

Ok, now onto the tests!!

Open yourself an appTests.js file and put something like this in it:

module(“TheRedCircuit’s tests for to show the good people”,  {
    setup: function () {
        // you can do some setup type stuff here
    }
});

test(“basicInsert testStory insertsIt”, 1, function () {
    stop(1000);
    var insertData = {name:”some title”,body:”some test body”};
    story.basicInsert(insertData, function (insertedData) {
        var key = insertedData.Key;
        story.basicGet(key, function (results, textStatus) {
            equal(textStatus, “success”);
            start();
        });
    });
});

Ok, so I’m cheating pretty badly here on the unit testing front.  I’m testing two functions at once, but seriously, how would you do it?  The chicken has to come before the omelet right?

When testing asynchronous functions, you have to tell QUnit to hold its horses while you go off across http land and do your thing.  That’s what the stop (and timeout after 1000 milliseconds) function is for.

Then I’ve nested all the calls so that we can only pass the equal function assertion if everything behaves nicely and gives us a “success” result.  Then the start function tells QUnit it can have the reins back.

Summary

I’ve done some whining about how hard CouchApp is.  I’ve verbally abused my imaginary friend.  Then I told you RavenDB is a lot easier because it is.  Then I showed you how brain-dead easy it is to get a RavenDB server going.  Lastly I did some POST and GET data access using jQuery.  Oh, and I showed you how to do some JavaScript unit testing with QUnit.

Because I know you are just falling all over yourself to know more, I’ll probably post a more complete version of this application next time, exploring RavenDB’s HTTP API some more … kind of like I did with CouchApp.