Category Archives: REST

The new DSTU2 Operations framework

As you probably know, FHIR lets you extend its datamodel using extensions, thus enabling you to add application and usecase specific data to the “core” datamodels. You can publish the details about these extensions on a FHIR server or repository, so people can find out what your extension means and what kind of data it allows.

In DSTU2 we introduced another extension mechanism: the Operations Framework. This framework allows you to add new operations to the FHIR REST interface, so you can add application-specific functionality that your clients can call. And just as with extensions, you can publish details about these operations on your FHIR server so others can find out how to invoke the operation.

But what exactly is an “operation” in the context of FHIR’s rest interface? In DSTU1 we were not particularly clear about this and we simply had a list of interactions, which include things like “read”, “search” and “validate”. In addition, DSTU1 offered a search parameter called “_query” that took a name of a custom “query”. Interestingly enough, the only “query” defined by the specification was the valueset expansion, which triggered amusing debates whether this actually qualified as a query. Moreover, we had the need to add operations that had side-effects and which took parameters of complex types. All of which was not possible with the “_query” extension point. This resulted in the addition of explicitly defined operations.

When you are invoking actions on a FHIR server, you are now either using the basic core “interactions”, which are just the CRUD operations, search and history. Anyhting else is an operation. The specification comes with certain pre-defined operations and it will let you define new ones by your own design.

Operations

Invoking an operation

Operations are (mostly) POSTs to a FHIR endpoint, where the name of the operations is prefixed by a “$” sign. For example:

POST http://fhir.someserver.org/fhir/Patient/1/$everything

Whenever the operation is idempotent it may be invoked using GET as well (as is the case with the example above).

Operations can be invoked on four types of FHIR endpoints:

  • The “base” FHIR service endpoint (e.g. http://fhir.someserver.org/fhir) – these are operations that operate on the full scale of the server. For example: return me all extensions known by this server.
  • A resource type (e.g. http://fhir.someserver.org/fhir/Patient) – these operations operate across all instances of the given type
  • A resource instance (e.g. http://fhir.someserver.org/fhir/Patient/1) – for operations that involve a single instance, like the $everything operation above
  • A version of a resource instance (http://fhir.someserver.org/fhir/Patient/1/_history/4) – which, as you can guess by now, is used by operations that involve a specific version of a specific instance of FHIR data. These are a bit exceptional in the sense that they should not alter instance data (since that would require creating an update) and were specifically introduced to allow manipulation of profile and tag metadata (which is allowed without creating a new version).

The body of the invocation contains a special infrastructure resource called Parameters (yes, plural). This Resource represents a collection of named parameters as <key,value> pairs, where the value may be any primitive or complex datatype or even a full Resource. In addition you may pass in strings that are formatted as the search parameter types.

On completion, the operation returns another Parameters resource, this time containing one or more (!) output “parameters”. This means that a FHIR operation can take any parameter “in” and return a set out result parameters “out”. We chose to introduce this special Parameters resource so both the body of the POST and the returned result are always a Resource. Had we not done this, we would have needed to expand the FHIR interface and FHIR serialization to allow for bodies that were just a complex datatype or primitive.

Publishing an operation’s definition

Invoking an operation is just the first part of the story. To make your new operations discoverable you will use the new OperationDefinition resource. Just like with extensions this is a computable expression of the definition of your operation, containing some metadata and details about the allowed parameters and result valies. Since the OperationDefinition is itself a resource, you can publish it in your FHIR server endpoint or a FHIR repository. Developer tools can take this definition and generate a strongly-typed API interface for it, and -just like our publication tool does– you may use it as source to generate documentation for your new operation.

The DSTU2 core specification comes with quite some pre-defined operations, and you will find some of the old DSTU1 interactions that your thought were missing in DSTU2, now showing up as an operation:

  • Validation ($validate) – this replaces (and expands on) the validation functionality of the old _validate interaction in DSTU1. You can send in a Resource (or a reference to a resource) and a reference to a StructureDefinition to get your resource validated.
  • Tag operations ($meta, $meta-add, $meta-delete) – replace the tag operations in DSTU1 to add profile, tag and security tag metadata for a resource instance.
  • The Mailbox endpoint ($mailbox) – Delivers a message to a FHIR server.

In addition, the specification now has a full set of ValueSet operations, which turn a FHIR server into a terminology server, offering limited CTS capabilities.

Finally, you can find all operations defined for a Resource on the new “Operations” tab that was added to all Resource pages

Advertisements

Content Types and Character Encodings

NOTE! Updated for FHIR 0.9

If you’re building a Fhir Client or Server, you will soon or later encouter the issue of Fhir’s (or rather Http’s) use of content types and character sets. They are easy to get wrong, and we currently have spread information about them out over (at least) two places in the Fhir spec, which does not really help.

The notions of “format”, “content type”, “content encoding”, “character encoding” and “character set” are by themselves already a source of confusion, so, at least for this blog, I’ll use “content type” to mean MIME-types like “application/pdf” and “image/jpeg”, and “character encoding” for character-to-byte encodings like “utf8” and “US-ASCII”.

Let’s take this from a Fhir client’s perspective: you are trying to get information from a Fhir server. If you are not sending any information to the server yourself (like when POSTing a new resource), you are just responsible for indicating whether you’d like to receive the server’s answer in Json or in Xml. You do this by sending, in your request to the server, an “Accept” header, which can contain the following content types:

xml json
Resource application/fhir+xml (changed!) application/fhir+json (changed!)
Bundle application/atom+xml application/fhir+json (changed!)

As you can see, you have to chose a different content type based on whether the REST operation you invoke returns a single resource (for operations like read and conformance) or a bundle (for operations like history and search). This header is optional, if you don’t send it, the server will assume the default, which is Xml.

Now, before you run off and code this into your client, there’s also the issue of character encodings to consider. To make life easy, FHIR has chosen to make UTF-8 its only acceptable character encoding. Period. If you feel you don’t need to worry about “all that”, please do read Joel Spolsky’s excellent blog on character encodings. Ofcourse, there’s a “but”: Http’s default character encoding is defined to be ISO-8859-1, so to make this work, both the client and the server must always indicate they are using UTF-8. In our case, this means we have to add “charset=utf-8” parameter to the Accept header like this:

Accept: application/fhir+xml;charset=utf-8

I assume most servers will be quite lenient about this. For example, my server accepts other common xml content types (like application/xml, text/xml) as well and will completely ignore whatever you put in the charset parameter (but will always speak to you in utf-8). Others might be strict and return you a Http 406 (Not acceptable) if you stray from the path.

If you wish, you can forget about these headers completely, and use the _format parameter in your Url. This will override whatever is in the Http headers. Acceptable values for the _format parameter are “xml”, “json” and even “application/json” or “application/fhir+xml”, but be aware to encode the “+” in your Url if you do that. We have added this to the specification explicitly so you can show Fhir in json and xml to all your friends using just a browser when you find yourself at a geek party.

When the server processes your request, it will try to reply to you in the content encoding you specified. Servers are not required to implement the Json format, so, even if you stick to the content types I have described above, the server may still return you Xml or even a 406 (Not acceptable) when you ask it for Json. I am afraid it’s up to you what to do about this if you’re a light-weight, json-only script client. Whatever the server choses, it will return your Bundle or Resource and indicate it’s type in the Content-Type header (including, again, the character encoding):

Content-Type: application/fhir+xml;charset=utf-8

There’s one more thing to be aware of as a client: if you are submitting data yourself to the server (e.g. on a create or update operation), you have to tell the server whether you are using Xml or Json using the Content-Type header. This is in addition to the Accept header as described above, so your request will contain two headers with content types. So, yes, it is possible to send the server data in Json and request it to have its response back in Xml:

Accept: application/fhir+xml;charset=utf-8
Content-Type: application/json;charset=utf-8

Whever you get confused about which header to send (which I frequently do): we added the summary table at the bottom of the http page to help you out.