FHIR searching

In this post I’m going to talk a little about searching using the REST paradigm within FHIR. This is a large topic, and I certainly won’t cover it in detail, but my intention is to provide enough detail for you to get started. (For the full details of searching (or queries) refer to the specification).

We’re going to focus on searching for a single type of resource – e.g. find a patient – how to specify the search parameters and how FHIR returns the results.

Each resource has a list of pre-defined search parameters that are defined in the specification for that resource. These are at the bottom of the page that describes each resource – for example here are the patient search parameters. Note that there is no requirement on a FHIR server that it must support all of these search parameters – and a server is also able to define their own searches – these are simply the list of parameters that the committee that defined the resource believes are the most common, or most obvious search parameters.

A FHIR server can indicate which parameters it supports for each resource in its conformance resource.

The format for this basic searching uses the GET method as follows:

GET [base]/[type]?[parameters] &_format=[mime-type]

or

GET [base]/[type]/_search?[parameters] &_format=[mime-type]

Where:

  • Base is the base URL to the server
  • Type is the resource type (like ‘Patient’)
  • Parameters are the search parameters you wish to use (and there can be more than one)
  • Format is the format (xml or json) you want the results in. (HTTP headers are the more elegant way to specify this, but it might not always be possible to easily set the headers, which is why this format is supported – in fact, it also applies to simple resource retrieval as well)

The parameters are expressed in name/value pairs, eg

http://hl7connect.healthintersections.com.au/svc/fhir/Patient?name=eve

would return all patients whose name contains the word ‘eve’

http://hl7connect.healthintersections.com.au/svc/fhir/Patient?name=eve&_format=json

is the same search, but specifying that the result should be in a json format rather than the default XML format.

Each resource parameter has a type that defines how it behaves – e.g. whether it is text, a number or part of a code set (a token). In most cases this is reasonably straightforward (though there are subtleties in some cases) – The one that causes the most difficulty at first is where one of the parameters is a resource reference – e.g. you want all the conditions for a particular patient. (In fact, this particular scenario has a specific solution – the compartment – that I’ll cover in a separate post, so bear with me for the moment).

The following search:

http://hl7connect.healthintersections.com.au/svc/fhir/condition?subject=351

will return all conditions where the ID of the subject (which is a patient) is 351 (The assumption is that you have previously performed a search on the patient to locate that ID). It is possible to get more complicated than that – for example you can chain query parameters to get, say, all conditions for patients whose name is david. Go look at the spec if that functionality is important in your use case. (Note: the format of this type of query has changed recently and not all servers may support it yet)

So we’ve talked about how to find resources based on matching their properties to some value, how to find resources based on their link to some other resource but we haven’t talked about the format that the results are returned in. It can’t just be the resource – as there will likely be more then one that matches – it has to be a set of some sort.

In fact, FHIR uses the Atom format to return the results of any search – regardless of how many resources matched the search – and we call this a bundle. Bundles are, in fact, used in a number of parts of FHIR – they form the basis of FHIR Documents and FHIR Messages, as well as the ability to batch multiple commands into a single transaction, but lets stay focussed on search for now.

If you look at the definition of the bundle, you’ll see it’s made up of a feed element, which contains any number of entry elements. Considering first the feed:

  • The root element is  <feed> – and it’s in the atom namespace. This means that any Atom reader can consume FHIR bundles – which raises a number of interesting possibilities that will likely be the subject of future posts! (Grahame, for example, uses this to monitor activity against his server, and it could be the basis for server replication). It also places some constraints on what we can do with bundles – it must remain compliant with the Atom spec.
  • There is a <title> element on both the feed and each entry within the feed. This is required by the Atom spec, but is not treated specially by FHIR. In particular, the contents should not be used for any automated processing.
  • Every feed has an <id> that must be a unique URI. In theory, a server could use this as the basis of an audit log, although that is not required by FHIR.
  • The feed has a number of <link> elements used for purposes such as pagination, as well as an element for the number of total number of results that matched the query (not just in this feed). These are optional.
  • An <updated> element that indicates the instant that the feed was created.
  • The <author> of the feed. Atom requires this – FHIR doesn’t care.
  • An optional <category> that contains tags associated with the feed. I’ll cover tags in a separate post – they’re used for things like security & privacy.
  • A <Signature> element that can be used for digital signatures.

Now lets’ look at the <entry> elements. Each entry element represents a single resource (in this case that matched the search/query) and has the following characteristics:

  • A <title> element (just like on the feed).
  • An <id> element. This is a URI that refers to the resource that is contained in the entry. It is NOT a version specific URI – it will refer to the most recent version of the resource on the server.
  • A <link rel=’self’> element that IS a version specific URI. This is not required (as not all servers will support versioning) but is recommended
  • An <updated> element. This is the date that the resource was last updated on the server – not when it was retrieved from the server. (There is a <published> element that states when it was copied into the feed – I’m not sure how useful this really is – maybe if you’re using the feed for server replication).
  • The <author> of the entry. If used, this will be the person who created the resource.
  • Any number of <category> elements. As in the feed, this is used to indicate the tags associated with the resource, and is much more useful when applied to a resource.
  • A <content> element that has the actual resource. This is what you are after as the result from the search. This will be the standard representation of the resource, with the resource type as the parent element, and the remaining properties as children (at least in XML – the format in JSON is in flux at the moment)
  • A <summary> element – this should be the same content as the text element within the resource, and is used to support the ability to display a feed using an XSLT transform – without needing to understand the FHIR resource structure.

And, of course, a bundle – and its contents – can be expressed in json as well as XML.

So, to summarize, a search in RESTful FHIR is quite simple

  1. Send a GET request with the desired parameters as name/value pairs in the URL
  2. Iterate over the <entry> elements in the response to get the results (or just use an XSLT transform displaying the title & summary elements if all you are doing is displaying it to the user or similar simple processing)

(you can even do this from a browser, though Graham will wrap the response in a UI if you do this – so the POSTman type approach I used in the previous post gives a result closer to the spec.).

Has a final note, it is also possible to use a POST to specify a search: as the query page states:  “or as an x-multi-part-form submission for a POST”, though this does seem to break the rules of REST as POST is not an idempotent operation, and in general is used to update a servers associated data store rather than query against it.

About David Hay
I'm an independent contractor working with a number of Organizations in the health IT space. I'm an HL7 Fellow, Chair Emeritus of HL7 New Zealand and a co-chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the FHIR standard. I'm the author of a FHIR training and design tool - clinFHIR - which is sponsored by InterSystems Ltd.

13 Responses to FHIR searching

  1. FHIR Starter says:

    If the atom result includes the full content of each matched resource then this could be a lot of data. Would it be possible to return only the metadata? Perhaps you could include the values of all available query parameters with the resource identifier.

    • David Hay says:

      An interesting thought. As currently specified, the full contents of each matching resource is included in the bundle – though there is a reference to a ‘resource summary’ for specific resources that are likely to be large. The server can, of course, use the paging mechanisms (http://www.hl7.org/implement/standards/fhir/http.html#paging) to limit individual responses. It is also possible to include more details (rather than less), for example to expand references like including the patient details when querying for dispensing data using the _include option (http://www.hl7.org/implement/standards/fhir/query.html#include).
      I suspect that underlying this philosophy is that resources need to be treated as an atomic entity, rather than as columns in a table, so returning only parts of them is thought to be unwise. However, having said that, things may well change as implementers start using FHIR and have real-world experience with querying & searching.

    • You can use the _summary parameter (&_summary=true) to get a subset of the resource. But after the DSTU is done, we are going to work on being able to request an odata table for getting summary search results.

  2. No SMOHK without ... says:

    Perhaps I’ve done too much database programming with cursors, but I like the idea of the content element pointing to the resource (URI in the src attribute), with the summary element conveying other useful metadata.

  3. Pingback: Using FHIR to expose a Patient Identity Registry lookup service – part 2 | Hay on FHIR

  4. basav says:

    When search query executes successfully and returns no elements, i.e., returns list with zero elements,

    In this case, rest response should be 2xx or 4xx or 5xx

    • Lloyd McKenzie says:

      An empty search is not a failure, so the HTTP response would be HTTP 200. On the other hand, doing a GET on a specific resource that doesn’t exist which would give you either a 404 (not found) or 410 (gone), depending on whether the resource was never there or has been deleted.

  5. If no matching records are found for given search criteria, then response should be 2xx or 4xx or 5xx ?

  6. Stef says:

    Question:
    Are search query parameters case-sensitive or always lowercase?

    This example implementation server returns an error message for this search query:
    http://fhirtest.uhn.ca/baseDstu2/Patient?namE=Meier

    Is there a Fhir specification/definition which describes this ?

  7. mitmash says:

    My concern with using HTTP GET is that is that patient name and other identifiers get stored on server logs like, IIS logs. These logs are typically non-encrypted text files, easily readable and will be hard to trace if stolen. This could cause possible HIPAA violations in the US

Leave a Reply

%d bloggers like this: