Proposal for #FHIR JSON format change: @manifest

Apr 20, 2017

There’s a long running discussion in the FHIR community about the way the JSON format handles extensions, and operation invocations (“Parameters”) resource.  Various implementers keep proposing format changes to the JSON format around extensions, but the last time we made an attempt to change this, it was roundly quashed at ballot. The underlying problem is that there’s 2 different (though overlapping) communities that use the JSON format for FHIR:

  • the interoperability community, who value consistency and robustness
  • the app writing community who value conciseness much more

From the perspective of the second community, the current JSON format doesn’t work well for representing either extensions, or the parameters of an operation. With this in mind, and drawing on the practices of the JSON-LD community, I’d like to advance a proposal for a manifest approach to extensions and parameters in the FHIR JSON format.

The way this would work is that we start with the existing format, and add a “@manifest” property, which contains information about how extensions and parameters have been represented in the json format. Applications reading the JSON format can either read the properties directly, based on their implicit knowledge of the manifest, or read the manifest and process accordingly.

As an example, consider this example Patient resource:

{
  "resourceType": "Patient",
  "id": "ex1",
  "extension": [
    {
      "url": "http://example.org/StructureDefinition/trials",
      "valueCode": "renal"
    }
  ],
  "active": true
}

This uses an extension following as specified in FHIR Release 3. The same resource rendered using a manifest might look like this:

{
  "resourceType": "Patient",
  "id": "ex1",
  "@manifest" : {
    "trials" : {
      "extension" : "http://example.org/StructureDefinition/trials",
      "type" : "code",
      "list" : false
    }
  },
  "trials": "renal",
  "active": true
}

Note: It’s important to note that processing the JSON directly and ignoring the manifest is a convenient but fragile approach; changes in naming or type would be transparent to an application that processed via the manifest, but would likely break an application that processed using the ‘trials’ name directly. That doesn’t mean that applications should not do this; just that it should only be used where the client and server are fairly closely linked and managed.

Aside: I think of this as ‘interoperability’ vs ‘operability’. At heart, FHIR is a specification for an API between disparate systems with different designs and life cycles (and customers - see ‘drive-by interoperability’). But lots of people are using it as a client/server format for singly maintained applications (often because there’s no strong technical boundary between the internal and external use) - and it’s in that tightly managed context that the manifest approach brings the most benefit with a manageable risk.

It’s also possible to take the manifest and move it out of band:

{
  "resourceType": "Patient",
  "id": "ex1",
  "@manifest" : "http://healthintersections.com.au/patient.manifest.json",
  "trials": "renal",
  "active": true
}

And then, at http://healthintersections.com.au/patient.manifest.json:

{
  "@manifest" : {
    "trials" : {
      "extension" : "http://example.org/StructureDefinition/trials",
      "type" : "code",
      "list" : false
    }
  }
}

Of course, if the manifest is not available at the nominated address, applications that use the manifest will not be able to process the instance correctly - if at all. So that’s an obvious risk that needs to be managed.

Readers familiar with JSON-LD will have seen the obvious similarities with JSON-LD’s @context. We’re not actually using ‘@context’, though, because while what we are doing is structurally similar, we’re using it for a different purpose.

You could use the same technique with regard to parameters on an operation. Take, for example, this input to the $expand operation:

{
  "ResourceType" : "Parameters",
  "parameter" : [
    {
    "name" : "coding",
    "valueCodeableConcept" : {
      "coding" : {
        "system" : "http://loinc.org",
          "code" : "1963-8",
      "display" : "test"
      }
    }
  },
  {
    "name" : "valueSet",
    "resource": {
      "resourceType" : "ValueSet",
    [etc]
    }
  }
  ]
}

With an in-line manifest, this might look like this:

{
  "ResourceType" : "Parameters",
  "@manifest" : {
    "code" : {
      "parameter" : " http://hl7.org/fhir/OperationDefinition/ValueSet-validate-code#coding",
      "type" : "Coding",
      "list" : false
    }
    "vs" : {
      "parameter" : " http://hl7.org/fhir/OperationDefinition/ValueSet-validate-code#valueSet",
      "type" : "Resource",
      "list" : false
    }
  }
  "code" : {
    "coding" : {
      "system" : "http://loinc.org",
        "code" : "1963-8",
    "display" : "test"
    }
  },
  "vs" : {
      "resourceType" : "ValueSet",
    [etc]
    }
  }
}

Or, we could refer to a manifest defined in the specification itself:

{
  "ResourceType" : "Parameters",
  "@manifest" : "http://hl7.org/fhir/r4/validation.manifest.json",
  "code" : {
    "coding" : {
      "system" : "http://loinc.org",
        "code" : "1963-8",
    "display" : "test"
    }
  },
  "vs" : {
      "resourceType" : "ValueSet",
    [etc]
    }
  }
}

Several Questions I’ve had from the few people who’ve looked at this idea already:

  • Why not do this in XML too? Well, we could. But I don’t think it has value, because people using FHIR in tightly bound client/server type environments (where the @manifest approach is nost beneficical) are almost exclusively using JSON. So the cost/benefit is not there for XML. Also, in XML, schema validation matters more.
  • What about JSON schema then? It’s possible to generate a JSON schema for this, if the generation tooling knows what the manifest is going to say. No such tooling exists right now, but it could be written. Or else someone could easily write a convert to convert from the @manifest form to the existing normal form.
  • What about the reference implementations? They’d be enhanced to support this transparently on read, and there would be some kind of configuration to allow the user to control the manifest, and then it would write according to the manifest.
  • Would this be instead of the existing approach? I propose that it’s an additional approach: the existing extension and parameter format is still valid, and can still be used, but implementations can use the @manifest if they want - and can mix and match. e.g. some extensions represented using @manifest, and others (not known in the manifest) represented the existing way

For follow up / discussion, see fhir.chat.org, though comments here are also welcome.