We're incredibly excited to announce that Akiban has been acquired by FoundationDB. Together we are closing the gap between SQL and NoSQL in our quest to disrupt the database market.

Read more in our blog post →

Posted by .

This post will take a look at the REST API by creating a CRUD app backed by node.js.

As in GET RESTful With Python, we’ll be taking advantage of existing libraries that work out of the box. On the backend, that is the excellent request library for REST calls and express.js for application bootstrapping. The single page frontend will use jQuery and CodeMirror for JSON pretty printing and editing.

Complete code for the post can be found in the node-simple-akiban-demo repo. Each section is associated with tag. Just checkout the specified tag when starting each section to follow along at home.

Proper handling of errors, or other interesting problems, has been skipped for simplicity. If you are interacting with the demo and something isn’t working, be sure to check the console messages from the node application.

 

Prerequisites

Git Tag: pre_and_hello

The package.json specifies the mentioned libraries.

{
  "name": "simple-akiban-demo",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "express": "3.x",
    "request": "2.x"
  }
}

Assuming you already have node.js and npm installed, running install is all you should need.

$ npm install

 

Hello, World

As in Schemaless SQL, we’ll be using a DataSpace with a single entity named hopes.

On the service side, just copy and deploy the hopes DataSpace, make note of the credentials, and place them in config.js. This file is structured as a module for easy importing.

module.exports = {
  "host": "<host>",
  "port": "<port>",
  "user": "<user>",
  "pass": "<pass>"
}

The application should now start and echo that it is listening.

$ node app.js
Listening on port 3000

Navigating to http://localhost:3000 should show a simple, but functional, page.
pre-req.

Clicking the GET /version button will make an AJAX request to our node application which will then make a version request to the Akiban Server. A successful JSON response will populate the code area with something similar to below.

[
  {
    "server_name": "Akiban Server",
    "server_version": "1.6.1-SNAPSHOT.2617"
  }
]

Congrats, you’re getting restful!

 

Code Basics

Aside from a small amount of boilerplate, omitted below, the backend, found in app.js, is just a few lines.

function build_uri(endpoint) {
  return 'https://' + config.host + ':' + config.port + '/v1' + endpoint;
}

app.get('/db/version', function(req, res) { // Register a route
  request.get(build_uri('/version'))        // GET from Akiban Server
         .auth(config.user, config.pass)    // Authenticate from the config file
         .pipe(res);                        // Send results to the client
});

The basics of the frontend, contained in public/index.html, are shown below. This is the only snippet of the index file as it won’t materially change from section to section.

<!-- A button to click -->
<form>
  <button id="version">GET /version</button>
</form>
<br/>

<!-- An area to show the results -->
<label>
  <strong class="label">JSON</strong>
  <textarea id="results"></textarea>
</label>

<script>
var textArea = $('#results').get(0);                  <!-- Find the text area -->
var codeMirror = CodeMirror.fromTextArea(textArea, {  <!-- Set up CodeMirror -->
    mode: { name: "javascript", json: true },         <!-- Mark it as JSON -->
    lineNumbers: true                                 <!-- Show line numbers -->
});

$('#version').click(function(event) {                 <!-- Find the button -->
  event.preventDefault();                             <!-- Ignore default behavior -->
  $.get('/db/version', function(data) {               <!-- AJAX request to the backend -->
    var pretty = JSON.stringify(data, undefined, 2);  <!-- Turn the response into a string -->
    codeMirror.setValue(pretty);                      <!-- Hand it off to CodeMirror -->
  });
});
</script>

 

GET Entities

Git Tag: get_entities

Adding support for getting all entities is delightfully simple.

app.get('/db/:entity', function(req, res) {   // Route with a URI parameter, 'entity'
  var entity = req.params.entity;             // The entity that was specified
  request_and_pipe('/entity/' + entity, res); // Helper from before: GET, auth, and pipe
});

Assuming we’ve seeded database with a couple hopes, filling in the entity name box with hopes and clicking GET /entity/:name will fetch all existing entities.

[
  {
    "id": 1,
    "desc": "Part IV: A New Hope",
    "date": "2013-04-11 18:18:23",
    "bumpcount": 0
  },
  {
    "id": 2,
    "desc": "Another",
    "date": "2013-04-11 18:20:00",
    "bumpcount": 10
  }
]

 

POST Entities

Git Tag: post_entities

Support for creating entities is as you might guess.

app.post('/db/:entity', function(req, res) {       // Route accepting POST
  var entity = req.params.entity;
  request_and_pipe('/entity/' + entity, req, res); // Also pass req for piping the body
});

We can now fill in the JSON area with new hopes we want to create.

[
  {
    "desc": "Yet another",
    "date": "2013-04-11 18:28:24",
    "bumpcount": 0
  },
  {
    "desc": "Surely there can't be more",
    "date": "2013-04-11 18:28:53",
    "bumpcount": 5
  }
]

Click the POST /entity/:name button will send them off to node and then to the Akiban Server. The response contains the IDs assigned to the new entities as we didn’t specify them above.

[
  {
    "id": 3
  },
  {
    "id": 4
  }
]

 

PUT and DELETE

Git Tag: put_del_entities

To round out the entity interaction, this last section adds PUT and DELETE support. These deal with existing entities by specifying their IDs. The entity endpoint for GET also supports this so a route was added for that as well.

app.get('/db/:entity/:id', function(req, res) {       // Route accepting GET, enity and id params
  var entity = req.params.entity;
  var id = req.params.id
  request_and_pipe('/entity/' + entity + '/' + id, req, res);
});

app.put('/db/:entity/:id', function(req, res) {       // Similar for PUT
  var entity = req.params.entity;
  var id = req.params.id;
  request_and_pipe('/entity/' + entity + '/' + id, req, res);
});

app.delete('/db/:entity/:id', function(req, res) {    // And DELETE
  var entity = req.params.entity;
  var id = req.params.id;
  request_and_pipe('/entity/' + entity + '/' + id, req, res);
});

 

Summary

You’ll now find a full complement of entity interaction buttons on our little application. Existing entities can now be fetched (GET), created (POST), replaced (PUT) or destroyed (DELETE). These same building blocks can be used to construct a full, and robust, node.js application with Akiban Server as the underlying data store.

Interested in more? Be sure to check out our ak-pg library (GitHub, npm), which exposes the full power of SQL wih Akiban extensions like Nested SQL. Also keep an eye on node-rest-akiban, which will be a friendly wrapper for REST interaction soon.