The RESTful Chemical Tracking System Part 5 - Media Types
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:
- The RESTful Chemical Tracking System Part 1: Introduction
- The RESTful Chemical Tracking System Part 2: Resources
- The RESTful Chemical Tracking System Part 3: Resource Associations
- The RESTful Chemical Tracking System Part 4: Resources, Representations, Hypertext, and JSON
- 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]](/articles/2009/08/28/%EF%BB%BFthe-restful-chemical-tracking-system-part-4-resources-representations-hypertext-and-json), 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.