How to write an API for PouchDB

In our forum someone has asked how he can use PouchDB in DukeScript. In case you don’t know PouchDB this is the description from their website:

“PouchDB is an in-browser database that allows applications to save data locally, so that users can enjoy all the features of an app even when they’re offline. Plus, the data is synchronized between clients, so users can stay up-to-date wherever they go.”

Maybe this is a nice chance for a blog post on writing a Java API for a JavaScript library. I’ve started by creating a little application “pouchdbdemo” based on the Knockout4j Archetype. Don’t bother doing this now, I’ve published the sources on Github for your convenience. The App does nothing fancy except creating a DB, storing one item and logging a message on success, but it might help you to see the ideas behind creating a simple API.

To create a Java API you only need to know two annotations: @JavaScriptBody and @JavaScriptRessource. The API Doc has some further info how to use them.

@JavaScriptRessource

The purpose of @JavaScriptRessource is simple. It allows you to load a JavaSript Library. Why is there an Annotation for this? You could also simply put a reference to it in your HTML-Page…

The reason is that it gives you a way to version the library. Others can then reference it via a Maven Dependency. And you can bundle it with your Java API. I’ve downloaded the latest version of PouchDB and put it into the “pouchdbdemo JavaScript Libraries” module. Now I create a class with this annotation:

import net.java.html.js.JavaScriptResource;

@JavaScriptResource(value = "pouchdb-3.6.0.min.js")
public class PouchDB {
    
}

NetBeans will complain that there needs to be at least one method with a @JavaScriptBody Annotation. We’ll fix that now:

@JavaScriptBody

Methods annotated with @JavaScriptBody can be used to execute JavaScript code from Java. In addition it makes it really easy to pass arguments to the JavaScriptCode. This is the code to create a pouchdb instance in JavaScript:

var db = new PouchDB('todos');

In order to wrap this call I can do this:

@JavaScriptBody(args = { "name" },body = "return new PouchDB(name)")
public static native Object createImpl(String name);

So instead of needing to construct the JavaScript String via some String operations, I can simply pass the name as an argument. In addition we’ve also made the method call type save. You can only pass in Strings.

Still the method isn’t very nice, because it would return some odd JavaScript Object to the user of your API. Java Developers don’t want to deal with that. The best strategy to make a nice API is to wrap this object and keep it out of sight. It’s enough that you as an API developer has to deal with ugly JavaScript:

@JavaScriptResource(value = "pouchdb-3.6.0.min.js")
public class PouchDB {


    private final Object pouch;

    private PouchDB(Object wrapped) {
        pouch = wrapped;
    }

    public static PouchDB create(String name) {
        return new PouchDB(createImpl(name));
    }

    @JavaScriptBody(args = { "name" },body = "return new PouchDB(name)")
    private static native Object createImpl(String name);
}

Much nicer. The user of your API can now create a new PouchDB and will receive a beautiful type save Java Object:

PouchDB db = PouchDB.create("todos");

Not only are we able to use the JavaScript Library, we’ve also made it better. The user of the API immediately knows what he will get back from the call, a PouchDB. And also the IDE knows what it will get, and can offer methods you can call on this Object (we’ll create some soon). And also the compiler knows what this is.

All that JavaScript users get is a “var” with no further clues on how to use it. It could be anything from an int to a function.

So let’s see what else the PouchDB API has… The tutorial stores a message like this:

function addTodo(text) {
  var todo = {
    _id: new Date().toISOString(),
    title: text,
    completed: false
  };
  db.put(todo, function callback(err, result) {
    if (!err) {
      console.log('Successfully posted a todo!');
    }
  });
}

Let’s convert it to a Java API:

public void addTodo(String todo) {   
        addTodoImpl(pouch, todo);
    }

    @JavaScriptBody(args = {"pouch", "text"}, body = "console.log('Posting a todo '+text);\n"
            + "console.log(pouch.adapter);\n"
            + "var todo = {\n"
            + "    _id: new Date().toISOString(),\n"
            + "    title: text,\n"
            + "    completed: false\n"
            + "  };\n"
            + "  pouch.put(todo, function callback(err, result) {\n"
            + "    if (!err) {\n"
            + "      console.log('Successfully posted a todo!');\n"
            + "    }\n"
            + "    if (err) {\n"
            + "      console.log('Error '+err);\n"
            + "    }\n"
         
            + "  });")
    public static native void addTodoImpl(Object pouch, String text);

I mainly left the JS code unchanged, but added some logging. Notice how the public API method only requires you to pass the string. We then get the wrapped JavaScript “pouch” and pass it to the implementation. I usually follow this pattern in all my APIs.

You can now call the API like this:

PouchDB pouchDB = PouchDB.create("todos");
pouchDB.addTodo("Buy milk!");

So instead of a bunch of letters in a bag (aka JavaScript) you have a nice and type save API. Let’s stop here for now, as this should be the most important concepts you need for writing an API.

If you’re interested in having such an API or helping, let us know. This is a great chance to get some in depth knowledge about DukeScript. And in case you need this right now, but have no time, be a sponsor and bribe us to put it on top of our todo list ;-).

If you just want to play with it, do so here.