Friday, October 29, 2010

Healthcare REST APIs - JSON or XML?

I have been working recently on a REST API which produces subsets of Continuity of Care Documents (CCD). This REST API is used by an iPhone application which is targeted to physicians and nurses. Since I wanted to minimize the amount of data exchange between the server and the client, I originally used JSON as my data exchange format. The motivation to use JSON was to have a compact format that offers better performance than a more complex XML representation.

For example, the request to obtain lab-results from a CCD is as following:
GET /users/<user-id>/patients/<patient-id>/lab-results?hl7v3=true&max=<max>offset=&<offset>

The resulting of this request to the API is a JSON object containing a list of lab results:
{"lab-results":{
    "list":[{"lab-result":{"entry":"...",
                           "facility":"...",
                           "normalcy":"...",
                           "orderedBy":"...",
                           "status":"...",
                           "subject":"...",
                           "urgency":"..."}},
            {"lab-result":{...}},...],
    "count":"...",
    "offset":"...",
    "remain":"..."}}

A lab result HL7 V3 entry is returned as the following JSON object:
{"entry":{
    "organizer":{
        "code":{"displayName":"..."}},
        "components":[
            {"component":{...}},
            {"component":{...}},...],
        "notes":[...]}}}

A lab-result component itself:
{"component":{
    "observation":{
        "code":{"displayName":"..."},
        "effectiveTime":{"value":""},
        "value":...,
        "interpretationCode":{"code":"..."},
        "referenceRange":{
            "observationRange":{...}},
        "notes":[...]}}}

An observation value is returned as a JSON object containing either a string value, a unit and a type, or just some text.
{"value":{"unit":"...","value":"...",type:"..."}}

{"value":"..."}

An observationRange is returned as a JSON value object containing a low and high value, or just some text.
{"observationRange":{
    "value":{
        "low":{"value":"..."},
        "high":{"value":"..."}}}}

{"observationRange":{"text":"..."}

All these JSON objects are marshalled from annotated Java POJOs using JBOSS RestEasy framework and Jackson:
XmlRootElement(name = "high")
public class HighValue {

 private String value = "";

 /**
  * Construct a new instance.
  */
 public HighValue() { }    // Empty constructor

 /**
  * Create a new {@code HighValue} during JAXB unmarshalling.
  * @param value
  *            String as value for the high value.
  */
 public HighValue(final String value) {
  if (value != null)
   this.value = value.trim();
 }

 /**
  * Get the {@code value} attribute.
  * @return {@code value} attribute value (may be {@code null}).
  */
 @XmlElement
 public String getValue() {
  return value;
 }

 /**
  * Set the {@code value} attribute.
  * @param value
  *            value to set.
  * @see #getValue()
  */
 public void setValue(final String value) {
  if (value != null)
   this.value = value.trim();
 }
}
This was fine initially since I was focusing on just lab results and I was using a specific back-end API that providing values to populate my POJOs. This solution started to become more complex when I was asked to generated a large set of CCD data types. As a result, the number of Java objects became quickly larger.

The other option I had was to use another internal API I could use which was already generated full or subset of CCD. However the resulting CCD format provided was in XML:
<component>
  <observation classCode="OBS" moodCode="EVN">
    <templateId root="2.16.840.1.113883.10.20.1.31"/>
    <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.13"/>
    <templateId root="2.16.840.1.113883.3.88.11.83.15"/>
    <id root="1"/>
      <code code="Remark" codeSystemName="L" displayName="Remark"/>
      <text>
        <reference value="#Observation_504ccbaf5ecea7b1096720"/>
      </text>
      <statusCode code="completed"/>
      <effectiveTime value="20091223231100"/>
        <value xsi:type="ST">Spec #106641063: 23 Dec 09  2311</value>
      <interpretationCode code="N" codeSystem="2.16.840.1.113883.5.83" codeSystemName="ObservationInterpretation" displayName="Normal"/>
  </observation>
</component>

I could of course just used it as it is and have my REST API return XML CCD subsets in XML:
GET /users/<user-id>/patients/<patient-id>/CCD&section=<section>

They are several issues with this:
  • As you can see XML is much more complex to understand, parse and debug than JSON
  • XML increases bandwidth consumption
  • Browsers and client application (e.g. mobile devices) can consume JSON much more efficiently than XML
For me, the best solution was to have the internal API marshalling the CCD in both XML and JSON so I will not have to unmarshall the CCDs again into POJOS.

The good news for all of us is that you can use java tools such as JAXB which has adapters to support other formats than XML such as JSON. With Java annotations, this is very easy to implement.