The RESTful Chemical Tracking System Part 5 - Media Types

September 10, 2009

Laboratory information management systems are complex entities that evolve over time. Change takes many forms, including the support of new kinds of devices (e.g., mobile devices), new applications that make use of the underlying data, changes in data models, and additional services that need to be integrated. RESTful web services exposing narrow functionality through a uniform interface offer an approach to anticipating and effectively working with these kinds of changes.

This article is the fifth part in a series exploring the idea that the REST architectural style can be applied to scientific laboratory information management problems, specifically chemical tracking. Previously, we identified five resources and described their interrelationships. This installment takes up the important question of how clients and servers will represent these resources through media types.

All Articles in This Series:

  1. The RESTful Chemical Tracking System Part 1: Introduction
  2. The RESTful Chemical Tracking System Part 2: Resources
  3. The RESTful Chemical Tracking System Part 3: Resource Associations
  4. The RESTful Chemical Tracking System Part 4: Resources, Representations, Hypertext, and JSON
  5. The RESTful Chemical Tracking System Part 5: Media Types

Resources At a Glance

We previously defined an association diagram that depicts how each of our resources relates to the others:

Using Media Types with Hypertext-driven APIs

As previously described, media types for this chemical tracking system will be based on JSON. Because our API will be hypertext-driven, we'll need a mechanism for providing links for clients to follow. We'll do this by defining a JSON data structure called Link. A Link will communicate three things: (1) a URI; (2) a media type; (3) a human-readable name to aid in debugging and client development. The following is an example of a Link defined in JSON:

{
  "name":"human-readable description of this Link",
  "uri":"http://example.com/transfers/123",
  "media_type":"application/vnd.com.metamolecular.cts.Transfer+json"
}

When a client receives a representation containing a Link, it won't need to guess the media type to send or request from the server - it uses the media type supplied in the Link. For its part, the server can define as many media types for a given URI as it cares to without breaking any client code.

Media Type Descriptions

Everything is now in place to offer some specific media type descriptions for the chemical tracking system. They each follow the same pattern consisting of: (1) a text description of the resource; (2) a table listing attributes and Links; and (3) an example representation.

Within each attributes table, those attributes marked "[create]" can be used when creating a new resource, and those marked "[update]" can be used when updating a resource. All attributes are returned when viewing the representation.

Index [application/vnd.com.metamolecular.cts.Index+json]

A listing of resources of the same type and which supports pagination.

Field Name Type Occurs Description
create Link 1 Create a new item.
items [Link] 1 An array of Links that may be empty.
next_page Link 0..1 Next page of Links.
previous_page Link 0..1 Previous page of Links.
{
  "create": {
    "name":"create a new location",
    "uri":"http://example.com/locations",
    "media_type":"application/vnd.com.metamolecular.cts.Location+json"
  },
  "items": [
    {
      "name":"a location",
      "uri":"http://example.com/locations/991",
      "media_type":"application/vnd.com.metamolecular.cts.Location+json"
    },
    {
      "name":"a location",
      "uri":"http://example.com/locations/992",
      "media_type":"application/vnd.com.metamolecular.cts.Location+json"
    },
    {
      "name":"a location",
      "uri":"http://example.com/locations/993",
      "media_type":"application/vnd.com.metamolecular.cts.Location+json"
    }
  ],
  "next_page": {
    "name":"the next page of locations",
    "uri":"http://example.com/locations?page=3",
    "media_type":"application/vnd.com.metamolecular.cts.Index+json"
  },
  "previous_page": {
    "name":"the previous page of locations",
    "uri":"http://example.com/locations?page=1",
    "media_type":"application/vnd.com.metamolecular.cts.Index+json"
  }
}
Location [application/vnd.com.metamolecular.cts.Location+json]

The place in which a Sample resides (or once resided). This simplistic definition may work for a small lab; we can accomodate more complex arrangements by breaking Location into subordinate resources such as Building, Room, Rack, and so on.

Field Name Type Occurs Description
location:building String 1 Name of the building. [create, update]
location:room Integer 1 Room number. [create, update]
location:station_type String 1 Type of station, for example "Fume Hood." [create, update]
location:station Integer 1 Station identifier, for example "27-A". [create, update]
current_samples Link 1 Listing of Samples currently found at this Location.
transfers Link 1 Listing of Transfers associated with this Location.
update Link 0..1 Update the state of this Location.
destroy Link 0..1 Destroy this Location.
{
  "location": {
    "building":"Chemistry",
    "room":104,
    "station_type":"Fume Hood",
    "station":"27-A"
  }
  "current_samples": {
    "name":"samples currently stored at this location",
    "uri":"http://example.com/locations/123/samples",
    "media_type":"application/vnd.com.metamolecular.cts.Index+json"
  },
  "transfers": {
    "name":"transfers made to this location",
    "uri":"http://example.com/locations/123/transfers",
    "media_type":"application/vnd.com.metamolecular.cts.Index+json"
  },
  "update": {
    "name":"updates this location",
    "uri":"http://example.com/locations/123",
    "media_type":"application/vnd.com.metamolecular.cts.Location+json"
  },
  "destroy": {
    "name":"destroy this location",
    "uri":"http://example.com/locations/123",
    "media_type":"application/vnd.com.metamolecular.cts.Location+json"
  }
}
Transfer [application/vnd.com.metamolecular.cts.Transfer+json]

The act of a User moving a Sample from one Location to another. Notice that unlike other resources, a Transfer is not something we can physically interact with but instead something done to another resource. Note that the sample_reference and location_reference fields make use of URIs themselves as primary resource identifiers.

Field Name Type Occurs Description
transfer:created_at Datetime 1 Time and date of transfer.
transfer:sample_reference URI 1 The URI of the Sample being transfered. [create]
transfer:location_reference URI 1 The URI of the Location for this transfer. [create]
user Link 1 The user initiating the transfer.
location Link 1 The location to which the transfer was made.
sample Link 1 The Sample that was transferred.
destroy Link 0..1 Destroy this Transfer.
{
  "transfer": {
    "created_at":"Fri, 04 Sep 2009 18:44:44 +0000",
    "location_reference":"http://example.com/locations/123",
    "sample_reference":"http://example.com/samples/1234"
  },
  "user": {
    "name":"the user initiating this transfer",
    "uri":"http://example.com/users/123",
    "media_type":"application/vnd.com.metamolecular.cts.User+json"
  },
  "location": {
    "name":"the location to which the transfer was made",
    "uri":"http://example.com/locations/123",
    "media_type":"application/vnd.com.metamolecular.cts.Location+json"
  },
  "sample": {
    "name":"the sample being transferred",
    "uri":"http://example.com/samples/1234",
    "media_type":"application/vnd.com.metamolecular.cts.Sample+json"
  },
  "destroy": {
    "name":"destroy this transfer",
    "uri":"http://example.com/transfers/1234",
    "media_type":"application/vnd.com.metamolecular.cts.Transfer+json"
  }
}
User [application/vnd.com.metamolecular.cts.User+json]

Any entity capable of moving a Sample from one Location to another. Depending on the equipment available in a lab, a User may or may not be a person.

Field Name Type Occurs Description
user:name String 1 This user's name. [create, update]
user:type String 1 One of (Human|Robot) [create, update]
transfers Link 1 Listing of all transfers made by this user.
update Link 0..1 Update the state of this User.
destroy Link 0..1 Destroy this User.
{
  "user": {
    "name":"Xanthus-1",
    "type":"Robot"
  },
  "transfers": {
    "name":"the transfers made by this user",
    "uri":"http://example.com/users/123/transfers",
    "media_type":"application/vnd.com.metamolecular.cts.Index+json"
  },
  "update": {
    "name":"update this user",
    "uri":"http://example.com/users/123",
    "media_type":"application/vnd.com.metamolecular.cts.User+json"
  },
  "destroy": {
    "name":"destroy this user",
    "uri":"http://example.com/users/123",
    "media_type":"application/vnd.com.metamolecular.cts.User+json"
  }
}
Sample [application/vnd.com.metamolecular.cts.Sample+json]

The physical object we want to keep track of. We'll start with something simple here. But like Location, Sample is a resource we can refine by breaking it down into smaller resources. For example, we might enable a Sample to be divided by defining a Partition resource.

Field Name Type Occurs Description
sample:mass String 1 The mass of the Sample. [create, update]
transfers Link 1 Listing of all transfers involving this Sample.
current_location Link 1 The current location of this sample.
substance Link 1 The Substance making up this Sample.
update Link 0..1 Update the state of this Sample.
destroy Link 0..1 Destroy this Sample.
{
  "sample": {
    "mass":"275 mg"
  },
  "transfers": {
    "name":"the transfers involving this sample",
    "uri":"http://example.com/samples/1143/transfers",
    "media_type":"application/vnd.com.metamolecular.cts.Index+json"
  }
  "current_location": {
    "name":"the current location this sample",
    "uri":"http://example.com/locations/42",
    "media_type":"application/vnd.com.metamolecular.cts.Location+json"
  },
  "substance": {
    "name":"the substance making up this sample",
    "uri":"http://example.com/substances/1099",
    "media_type":"application/vnd.com.metamolecular.cts.Substance+json"
  },
  "update": {
    "name":"updates this sample",
    "uri":"http://example.com/samples/1234",
    "media_type":"application/vnd.com.metamolecular.cts.Sample+json"
  },
  "destroy": {
    "name":"destroy this sample",
    "uri":"http://example.com/samples/1234",
    "media_type":"application/vnd.com.metamolecular.cts.Sample+json"
  }
}
Substance [application/vnd.com.metamolecular.cts.Substance+json]

The molecular entity (or entities) contained in a Sample. Here, we'll use a Substance ID assigned by another system (possibly by a company-wide substance registration app). If that system were RESTful (see Chemcaster), we could link to it instead.

Field Name Type Occurs Description
substance:identifier String 1 Substance ID. [create, update]
samples Link 1 The samples in which this substance appears.
update Link 0..1 Update the state of this Substance.
destroy Link 0..1 Destroy this Substance.
{
  "substance": {
    "identifer":"CB-10779751"
  },
  "samples": {
    "name":"the samples in which this substance appears",
    "uri":"http://example.com/substances/815/samples",
    "media_type":"application/vnd.com.metamolecular.cts.Index+json"
  },
  "update": {
    "name":"update this substance",
    "uri":"http://example.com/substances/123",
    "media_type":"application/vnd.com.metamolecular.cts.Substance+json"
  },
  "destroy": {
    "name":"destroy this substance",
    "uri":"http://example.com/substances/123",
    "media_type":"application/vnd.com.metamolecular.cts.Substance+json"
  }
}

Conclusions

We now have the blueprint for a RESTful chemical tracking system. Five resources with well-defined relationships can now be expressed in terms of simple media types. But how do we use these media types and resources to actually accomplish something useful? The next article in this series will offer some ideas.