Getting Scala, HATEOAS, and JSON to work together

I’ve been working with Scala for the last few months on a new project, and I’ll confess that it’s starting to grow on me (this is in stark contrast to Java, which I’m liking less the more I learn about it).

My current project has me creating a REST API using Scalatra along with a front-end built with Coffeescript and Backbone.js.  This definitely has a different feel to it than a typical web application built using one of the uber-frameworks like Rails.  The lack of tight integration between back-end and front-end has its advantages, but also introduces a few issues that must be sorted out.  One of these issues that I’ve recently happened upon involves controlling how a user may interact with resources on the server based on his or her access level (or ‘role’).  For example, if I have a database table called ‘people’, each containing a record for a member of an organization, I probably want to control who can do what with said records.  Perhaps standard users are only allowed to view these people records, managers are allowed to edit them, and Administrators may delete or create a new records.

This is a trivial problem with a traditional web app, but in the case of a REST API, consider this:  I request a list of people records from my server by issuing a GET request to http://myserver.com/api/persons.  The server checks my credentials, and returns a list of 20 records of people in, say, the accounting department.  The client (whether it be a web app, mobile app, etc.) renders a nice, spiffy table full of people records.  The client interface also has several buttons that allow me to manipulate the data.  Buttons with such labels as ‘View Record’, ‘Edit Record’, ‘Delete Record’, etc.

Now we have an issue.  Let’s say I’m the manager of 6 people in the accounting department, but the other 14 belong to other managers.  It has been decided that managers should be able to view the records of other personnel in the organization, but should only be able to edit records for their own.  Further, only Administrators (let’s say HR folks) can delete a record. No problem, you might say, just have the server check the user’s role regarding a person record before executing a request to update or delete a record.  We can make this easy by adding a ‘manager_id’ field to the ‘person’ table identifying each person’s manager.

Of course, that would work fine.  The problem, however, is not in ‘correctness’ of the application, but in the user-friendliness of the client interface.  The client has no way of knowing your permissions in regards to each person record so it displays buttons for every possible action that can be taken for each and every one, relying on the server to sort things out on the back-end and return an error if you try to do something illegal.  It would be better if we could have the server send down a list of actions the authenticated user is allowed to take for each record, then we could simply not display (or grey-out) the related interface elements (buttons, drop-down items, etc.) for non-specified actions, giving the user an instant visual cue regarding what he’s allowed to do.  While we’re at it, why not send down a link to the REST call for each of the allowed actions as well?

This is where HATEOAS (Hypermedia as the engine of application state) comes in.  For a more thorough explanation, go to the Wikipedia page.  Basically, a HATEOAS compliant REST service requires the server to, along with the resource data itself, send a list of actions (and links) that may be performed on or with that resource.  It’s probably easier explained via example.

First, here’s a plain JSON object returned from a non-HATEOAS compliant service:

{
  "id":35,
  "employeeId":"7",
  "lastName":"NewGuy",
  "firstName":"Steve",
  "middleName":"",
  "email":"steve@acme.com",
  "title":"Clerk",
  "hireDate":"01/02/2013",
  "dateOfBirth":"01/01/1980"
}

Just a bag of data — no information regarding what I should, or what I’m allowed to do with it. Well, how about this:

{
  "_links": 
  { 
    "self": {"href":"/api/persons/35","method":"GET"},
    "update":{"href":"/api/persons/35","method":"PUT"},
    "delete":{"href":"/api/persons/35","method":"DELETE"}
  },
  "id":35,
  "employeeId":"7",
  "lastName":"NewGuy",
  "firstName":"Steve",
  "middleName":"",
  "email":"steve@acme.com",
  "title":"Clerk",
  "hireDate":"01/02/2013",
  "dateOfBirth":"01/01/1980"
}

The _links section of this object tells me that I’m allowed to update AND delete this record, and provides links to the REST calls necessary to perform those actions. It also includes a link to itself. By the way, there are several “standard” formats out there for returning these links, I’m attempting to follow HAL. For more fun, you could also include the MIME-type for the data that each action would return (JSON, HTML, PDF, whatever).

The concept is rather simple, and definitely beats the hackish ideas I initially had for solving this issue. However, and this could just be my relative new-ness to Scala, it did take a bit of effort to figure out how to get the server to spit out correctly formatted JSON for the HAL links (I didn’t want my _links section to be sent as an array, for example, or the myraid other ways the Jackson default serializer decided to do it before I sorted it out). I eventually came up with something like this (ok, exactly this):

//package object full o' utility functions for creating some HAL-style HATEOAS links
package object Hateoas{
  //could add an additional field specifying MIME-type, for example
  case class Link(href: String, method: String)
  type HateoasLinks = Map[String, Link]
  //case class for a response containing a Collection of items
  case class ListResponse(_links: HateoasLinks, _embedded: Map[String, List[Any]])
  object HateoasLinkFactory{
    //could (should) add a function for generating a "custom" action link
    def createSelfLink(uri: String) = {
      ("self" -> new Link(uri, "GET")) 
    }
    //create Create!
    def createCreateLink(uri: String) = {
      ("create" -> new Link(uri, "POST")) 
    }

    def createUpdateLink(uri: String) = {
      ("update" -> new Link(uri, "PUT"))
    }

    def createDeleteLink(uri: String) = {
      ("delete" -> new Link(uri, "DELETE"))
    }
  }
}

I use this code to generate each object’s _link section before pushing it down to the client. It’s not by any means a fully-realized HAL implementation, but it solves my main issue for now, and I can easily add more functionality as needed.

2 thoughts on “Getting Scala, HATEOAS, and JSON to work together

  1. Hi,

    From where did you get the “method”:”DELETE” idea ? It seems really interesting but it is not part of the JSON HAL draft (at least i did not found anything about it)

    Like

  2. DELETE is just one of the standard HTTP Methods. There are a lot of APIs out there that get by with using only GET and POST (sometimes for compatibility with older browsers or other perfectly good reasons), but if possible I like to use the others.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: