Category Archives: Implementation

#FHIR Paradigms

Many of the FHIR tutorials show this diagram:

The goal of this diagram is to show that FHIR defines 3 different ways to exchange FHIR resources:

  • Using the RESTful interface – the most high profile way to exchange data
  • Packaging the resources in messages, and pushing them between systems (similar architecture as HL7 v2)
  • Packaging the resources in documents, with a managed presentation (similar architecture as CDA)

Also, what this diagram is intending to show is that in addition to the 3 ways defined by the FHIR specification itself, there’s other ways to exchange resources. Since the most common alternative method is to use some enterprise web services framework (say. some kind of SOAPy thing) – we called it ‘services’.

But that’s misleading; a ‘service’ is some orchestration of exchange of FHIR resources, and most implementation projects build their services using some combination of RESTful interfaces, messages, and documents, along with other methods of transfer. And that’s a combination that the FHIR community thinks is perfectly valid. So calling the 4th ‘other’ category “services” is… misleading… to say the least.

However there’s something beyond that missing from this diagram. In the last year or so, the FHIR community has gradually become more focused on what is emerging as a distinct 4th paradigm: using persistent data stores of some kind or other to exchange data between systems. Classically, this is associated with analytics – but it doesn’t actually need to be. The typical pattern is:

  • Create some kind of persistent store (can be an SQL database, a nosql db, a big data repository, an RDF triple store)
  • Applications generating data commit resources to the store
  • Applications using the data to the store find and retrieve data from the store at a later time

We haven’t really acknowledged this paradigm of exchange in the specification – but it’s what the RDF serialization is really about. And all the uses I’ve seen have one uniting characteristic: there’s a need to reconcile the data when it is committed, or later, to help with subsequent data analysis. There’s 2 kinds of reconciliation that matter:

  • detecting, preventing or repairing duplicate records
  • matching references (e.g. resolving URLs to their target identity in the database, and storing the native link)

One of the subjects I’d like to discuss in New Orleans next month is to gather the various disparate strands of work in the community around a ‘storage paradigm’ into a single coherent whole – if that’s possible. It’s something that we’ve been slow to take up, mainly because HL7 classically agrees to focus on the ‘interface’ and keep away from vendor design. But that’s happening in the community now has moved past this.

In particular, there’s really interesting and energetic work using new databases (or new features of old databases) to store FHIR resources directly in the database, and performing the analysis directly on the resources. Google presented some really interesting work around this at DevDays in Amsterdam a couple of weeks ago, and we’re working towards hosting a publicly usable example of this.

Clearly, we’ll need a new diagram to keep up with all these changes

Sharing Information with a Patient Case Manager

Sharing Information with a Patient Case Manager

This post (which is co-authored with Josh Mandel, thanks) describes a general pattern for a clinician to initiate sharing of a clinical record between an EHR (or more generally, a clinical records system – can be more than just an EHR) and some other clinical information service. These might be one the following:

  • Patient assistance organizations like Medic Alert
  • Patient networks such as ‘PatientsLikeMe
  • Voluntary/professional Clinical case registries (e.g. Vermont Oxford network)
  • Social support services
  • Government and Private Preventative/Management Programs(?)

During the clinical workflow, the clinician with consent from the patient, agrees to ‘refer’ the patient’s case to some kind of case manager, and continue to share information about the patient with the case manager. At some stage, either the clinician or the patient may wish to stop further sharing.

Notes:

  • This is not the same as a formal clinical referral, though there’s some similarities – that’ll be a separate post.
  • There’s a spread of balance between clinical and patient interest here – some of them are ‘what the clinician wants, with consent of the patient’ while others are ‘helpful suggestions from the clinician that the patient might want to run with’. The balance of these may influence which parts of the interaction pattern are more applicable
  • There’s other kinds of case manager registries where the patient doesn’t get consulted. Typically, this is for mandatory public health reporting; this is a different problem for which this particular pattern is not applicable, though parts of it would no doubt be useful

Interaction pattern

Up till now, this kind of sharing has been very difficult to organize in practice, because it has needed vendor support one way or another, and vendors just don’t have time for the never-ending stream of requests for this. That translates into the fact that each individual project cannot afford the development. But FHIR, SMART on FHIR, and CDS Hooks change that.

This blog describes a general pattern for using the Argonaut profile and current EHR development to organize this sharing without needing any special arrangements. I’m publishing this because the overall pattern isn’t evident to many participants.

This pattern describes:

  1. How the case manager service can suggest to the clinician that they should initiate the referral
  2. How the case manager service can provide an application that initiates the sharing
  3. How the sharing can be maintained in an ongoing fashion

Pre-requisites

In order to support this pattern, the clinician must be using an EHR that supports the following:

  • Required: Registering and Running SMART on FHIR applications
  • Recommended: An internet facing provider portal (preferred) or patient portal
  • Optional: Registering and using CDS Hooks service for patient-view hooks

Setting up the pattern includes registering the case manager service with the EHR, and vice versa, and probably exchanging public keys. This step is not standardized by the FHIR/SMART on FHIR/CDS Hooks specifications, but it needs to be done.

Interaction

#1 Prompting the clinician to register the patient

The EHR notifies the case manager service that a patient is being viewed. The case manager service uses the local patient id, and patient information – if provided – to determine whether the patient is already registered, or could or should be registered, and, if it wants, can prompt the user to run the registration app.

This part of the pattern is optional: the clinician can always choose to run the registration app (step #2) without being prompted – this just makes the process easier.

Details:

  • EHR calls CDS Hooks Service. Information provided includes something like:
    • hook :  “patient-view”
    • hookInstance : random UUID,
    • patient: {local patient id}
    • context: none
    • prefetch: patient resource, list of patient’s medications, allergies etc (all optional, and case manager service specific)
  • CDS Hooks Service returns a card that says
    •  patient is or is not (or might be) registered with case manager service (based on recognising local id, or matching patient details (if provided)
    •  patient is not registered with case manager service
    •  if prefetch was passed, and patient is not registered with case manager service, and patient meets criteria, a link to a SMART App to register the patient with the case manager service
    • card includes a link the case manager smart app (see #2)

#2 Registering a patient with the case manager service

The user runs the SMART on FHIR application for the case manager, which gathers information from the EHR (as authorized by the user/institution) and then prompts the user for any additional information needed by the case manager service, and then submits all the information to the case manager service.

Note that each case manager service provides their own application that does what they want, though there is likely to be a (or several) general open source frameworks that do most of what is entailed here.

Details:

  1. User runs the registration app. Either as prompted by CDS Hooks Service above, or by a manual app launch
  2. SMART app loads patient details
  3. SMART app loads medications, problems, allergies, subset of lab results as appropriate for case service
  4. SMART app connects to case manager service, and prompt user for additional information as required (typically, this would include patient consent information and reason for referral at least)
  5. user fills out additional information and submits  (As an optional best practice, the information can be submitted as is submitted to register as a FHIR Bundle, including ServiceRequest, practitioner resource, provenance resource, and gathered data, as appropriate)
  6. Case Management Service stores all required information within its own database.

Note that FHIR provides the Questionnaire/QuestionnaireResponse resources. In this case, the app would retrieve a blank Questionnaire from the case manager service, prompt the user to fill out any information that cannot be automatically determined, and then save a QuestionnaireResponse as part of its registration Bundle (see the SDC implementation guide for details on this)

#3 Ongoing sharing of the clinical record

This part of the pattern is optional – there might not be any utility in ongoing sharing, or it might not be appropriate to ask (either clinician or patient), or it might not be consented to. Note that there’s a marked difference between consenting to share ‘this set of information’ and ‘what ever arises in the future’.

How ongoing sharing works depends on whether the provider API end-point (used by the application in #2) is publicly available or not, and whether the ongoing sharing should be patient or provider managed. If it’s not public, the patient API end-point can be used. If the sharing should be managed by the patient, the patient API should be used. If there’s no patient or provider API publicly available, then there’s no way to orchestrate on-going sharing; records can only be shared as a one-time process in step #2 when the clinician chooses to (usually during a referral). (note: whether the provider portal is publicly accessible, or the URL of the patient portal need to be shared with the application at configuration time).

Ongoing sharing uses the SMART on FHIR protocol as profiled in Sync for Science (S4S) until access is revoked. Access to the S4S interface requires a bearer token  – this pattern relates to acquiring the token.

Provider Portal:

If the provider portal is publicly available, then the application (during step #2) shares its bearer token with the case manager service. How this works:

  • The application asks for an access token with offline scope
  • It shares the token with the case manager service
  • The case manager service uses the token to update the patient’s record periodically

Note that it might be useful for the case manager service to have a different token from the case manager application that runs locally and interactively. The application could use the draft IETF token exchange spec for that, though this is not part of the eco-system now.

Patient Portal:

If there is no provider portal, or if ongoing sharing should be managed by the patient, the patient portal can be used instead. The way this works generally is:

  • The case manager service emails the patient a link (email gathered during registration)
  • patient follows the link and logs in or registers etc
  • patient gets redirected to OAuth login on patient’s portal
  • Patient chooses to authorise the case manager service to access patient data. Scopes could include a broad permission like “patient/*.read”, or granular permissions like “patient/AllergyIntolerance.read”, “patient/MedicationStatement.read”, “patient/MedicationOrder.read”, “patient/Medication.read”, “patient/Condition.read”, “patient/Observation.read”, etc.
  • Case manager service uses the bearer token as described above

If there is no Internet-accessible FHIR API endpoint for the EHR’s data, then there’s another solution: to run a service within the hospital’s internal network that hosts SMART on FHIR apps that can have access to the provider portal. That’s, well, possible, but there’s a series of challenges around administration.

Note:

This pattern is for managing this task using the FHIR/SMART on FHIR/CDS Hooks framework alone. There are other patterns – using the Consent resource – that come into play if the EHRs implement a patient managed consent framework (directly or using UMA), or if the EHR vendor is able/willing to do integration work.

#FHIR and Bulk Data Access Proposal

ONC have asked the FHIR community to add new capabilities to the FHIR specification to increase support for API-based access and push of data for large number of patients in support of provider-based exchange, analytics and other value-based services.

The background to this requirement is that while FHIR allows for access to data from multiple patients at a time, the Argonaut implementations are generally constrained to a single patient access, and requires human mediated login on a regular basis. This is mainly because the use case on which the Argonaut community focused was patient portal access. If this work is going to be extended to provide support for API based access to a large number of patients in support of provider based exchange, the following questions (among others) need to be answered:

  • how does a business client (a backend service, not a human) get access to the service? How are authorizations handled?
  • How do the client and server agree about which patients are being accessed, and which data is available?
  • What format is the data made available in?
  • How is the request made on a RESTful API?
  • How would the client and server most efficiently ensure the client gets the data it asks for, without sending all data every time?

The last few questions are important because the data could be pretty large – potentially >100000000 resources, and we’ve been focused on highly granular exchanges so far. Our existing solutions don’t scale well.

In response to some of these problems, the SMART team had drafted an initial strawman proposal, which a group of us (FHIR editors, ONC staff, EHR & other vendors) met to discuss further late one night at the San Diego WGM last week. Discussion was – as expected – vigorous. Between us, we hammered out the following refined proposal:


Summary

This proposal describes a way of granting an application access to data on a set of patients. The application can request a copy of all pertinent (clinical) access to the patients in a single download. Note: We expect that this data will be pretty large.

High-level Use Case Description – FHIR-enabled Population Services (this section provided by ONC)

  • Ecosystem outcome expected to enable many specific use case/business needs: Providers and organizations accountable for managing the health of populations can efficiently access to large volumes of informationon a specified group of individuals without having to access one record at a time. This population-level access would enable these stakeholders to: assess the value of the care provided, conduct population analyses, identify at-risk populations, and track progress on quality improvement.
  • Technical Expectations: There would be a standardized method built into the FHIR standard to support access to and transfer of a large amount of data on a specified group of patients and that such method could be reused for any number of specific business purposes.
  • Policy Expectations: All existing legal requirements for accessing identifiable patient information via other bulk methods (e.g., ETL) used today would continue to apply (e.g., through HIPAA BAAs/contracts, Data Use Agreements, etc).

Authorizing Access

Access to the data is granted by using the SMART backend services spec.

Note: We discussed this at length, but we didn’t see a need for Group/* or Launch/* kind of scopes – System/*.read will do fine. (or User/*.*, for interactive processes, though interactive processes are out of scope for this work). This means that a user cannot restrict Authorization down to just a group, but in this context, users will trust their agents.

Accessing Data

The application can do either of the following queries:

 GET [base]/Patient/$everything?start=[date-time]&_type=[type,type]
 GET [base]/Group/[id]/$everything?start=[date-time]&_type=[type,type]

Notes:

  • The first query returns all data on all patients that the client’s account has access to, since the starting date time provided.
  • The second query provides access to all data on all patients in the nominated group. The point of this is that applications can request data on a subset of all their patients without needing a new access account provisioned (exactly how the Group resource is created/identified/defined/managed is out of scope for now – the question of whether we need to do sort this out has been referred to ONC for consideration).
  • The start date/time means only records since the nominated time. In the absence of the parameter, it means all data ever
  • The _type parameter is used to specify which resource types are part of the focal query – e.g. what kind of resources are returned in the main set. The _type parameter has no impact on which related resources are included) (e.g. practitioner details for clinical resources). In the absence of this parameter, all types are included.
  • The data that is available for return includes at least the CCDS (we referred the question of exactly what the data should cover back to the ONC)
  • The FHIR specification will be modified to allow Patient/$everything to cross patients, and to add $everything to Group
  • Group will be added as a compartment type in the base Specification

Asynchronous Query

Generally, this is expected to result in quite a lot of data. The client is expected to request this asynchronously, per rfc 7240. To do this, the client uses the Prefer header:

Prefer: respond-async

When the server sees this return header, instead of generating the response, and then returning it, the server returns a 202 Accepted header, and a Content-Location at which the client can use to access the response.

The client then queries this content location using GET content-location (no prefixing). The response can be one of 3 outcomes:

  • a 202 Accepted that indicates that processing is still happening. This may have an “X-Progress header” that provides some indication of progress to the user (displayed as is to the user – no format restrictions but should be <100 characters in length). The client repeats this request periodically until it gets either a 200 or a 5xx
  • a 5xx Error that indicates that preparing the response has failed. The body is an OperationOutcome describing the error
  • a 200 OK with the response for the original request. This response has one or more Link: headers (see rfc 5988) that list the files that are available for download as a result of servicing the request. The response can also carry a X-Available-Until header to indicate when the response will no longer be available

Notes:

  • This asynchronous protocol will be added as a general feature to the FHIR spec for all calls. it will be up to server discretion when to support it.
  • The client can cancel a task or advise the server it’s ok to delete the outcome using DELETE [content-location]
  • Other than the 5xx response, these responses have no body, except when the accept content type is ‘text/html’, in which case the responses should have an HTML representation of the content in the header (e.g. a redirect, an error, or a list of files to download) (it’s up to server discretion to decide whether to support text/html – typically, the reference/test servers do, and the production servers don’t)
  • Link Headers can have one or more links in them, per rfc 5988
  • Todo: decide whether to add ‘supports asynchronous’ flag to the CapabilityStatement resource

Format of returned data

If the client uses the Accept type if application/fhir+json or application/fhir+xml, the response will be a bundle in the specified format. Alternatively, the client can use the type application/fhir+ndjson. In this case:

  • The response is a set of files in ndjson format (see http://ndjson.org/).
  • Each file contains only resources of a single type.
  • There can be more than one file for each resource type.
  • Bundles are broken up at Bundle.entry.resource – e.g. a bundle is split on Entries so the the bundle json file will contain the bundle without the entry resource, and the resources are found (by id) in the type specific resource files (todo: how does that work for history?)

The nd-json files are split up by resource type to facilitate processing by generic software that reads nd-json into storage services such as Hadoop.

Notes:

  • the content type application/fhir+ndjson will be documented in the base spec
  • We may need to do some registration work to make +ndjson legal
  • We spent some time discussing formats such as Apache Avro and Parquet – these have considerable performance benefits over nd-json but are much harder to produce and consume. Clients and servers are welcome to do content type negotiation to support Parquet/ORC/etc, but for now, only nd-json is required. We’ll monitor implementation experience to see how it goes

Follow up Requests

Having made the initial request, applications should store and retain the data, and then only retrieve subsequent changes. this is done by providing a _start time on the request.

Notes:

  • Todo: Is _start the right parameter (probably need _lastUpdated, or a new one)?
  • Todo: where does the marker time (to go into the start/date of the next follow up request) go?
  • clients should be prepared to receive resources that change on the boundary more than once (still todo)

Subscriptions

The ONC request included “push of data”. It became clear, when discussing this, that server side push is hard for servers. Given that this applications can perform these queries regularly/as needed, we didn’t believe that push (e.g. based on subscriptions) was needed, and we have not described how to orchestrate a push based on these semantics at this time


Prototyping

It’s time to test out this proposal and see how it actually works. With that in mind, we’ll work to prototype this API on the reference servers, and then we’ll hold a connectathon on this API at the New Orleans HL7 meeting in January. Given this is an ONC request, we’ll be working with ONC to find participants in the connectathon, but we’ll be asking the Argonaut vendors to have a prototype available for this connectathon.

Also, I’ll be creating FHIR change proposals for community review for all the changes anticipated in this write up. I guess we’ll also be talking about an updated Argonaut implementation guide at some stage.

 

#FHIR, CDS-Hooks, and Clinical Decision Support

This is a guest post written by Kevin Shekleton from Cerner, and first posted to the HL7 CDS email list. Reproduced here for wider availability by agreement with Kevin


TL;DR: CDS Hooks will be working with the HL7 Clinical Reasoning team to make sure our approaches are complementary, and to ensure that CDS Hooks is on a path to standardization. The CDS Hooks implementation community should expect no changes to our open, community-based development process (but should expect to see increased interest and engagement from the community).

As briefly mentioned a few days ago on an earlier thread, there is some news to share from the HL7 WGM a couple weeks ago. I didn’t share this immediately at that time because frankly, I wasn’t sure as to the details yet. Rather than posting a vague post I was waiting until we had a few more discussions before communicating this out. 🙂
During the WGM, I attended a joint meeting between the CDS, CQI, and FHIR-I working groups. During this meeting, one of the topics of discussion was a new project scope statement (PSS) to semantically align Clinical Reasoning to CDS Hooks. There was an acknowledgement by the HL7 working group of the support and interest CDS Hooks has within the EHR and CDS vendor communities, so ensuring Clinical Reasoning aligns (where/when possible) to CDS Hooks is beneficial to those planning to support both projects.
The CDS working group has been working on a model for clinical decision support within FHIR called Clinical Reasoning (formerly known as CDS on FHIR). I’ve fielded many questions from folks all asking the same thing: “What is the difference between Clinical Reasoning and CDS Hooks?”
At the end of the joint meeting, several of us stuck around afterwards to discuss the two projects in further detail. Specifically, we began to directly address that aforementioned question: “What is the difference between Clinical Reasoning and CDS Hooks?”. We all agreed that none of us have ever had a very clear response to that question, mainly because each of us have been focused on our respective projects and have not sat down recently to compare/contrast the specifics of our approaches and goals.
Bryn Rhodes (primary architect of Clinical Reasoning), Isaac Vetter (Epic), and I proceeded to work for the next 6 hours or so on educating each other on architecture specifics, projects goals, and design constraints of each project. In doing so, we came away with the following high level takeaways:
  • CDS Hooks is designed solely around the execution of external clinical decision support.
  • Clinical Reasoning was designed primarily around the definition, sharing, and execution of local clinical decision support. However, the project also defines capabilities for external decision support that are based on older specifications, resulting in the overlap with CDS Hooks.
Based upon our initial work that afternoon/night, we all agreed on several things:
  • Continuing our conversations was in the best interest of both projects.
  • Both projects should be complementary
  • The sweet spot of Clinical Reasoning is in the space of local CDS
  • The sweet spot of CDS Hooks is in the space of external CDS
To reflect this, we modified the aforementioned project scope statement to commit to continuing these discussions in 2017 with the goal of more directly aligning the projects. Specifically, we agreed to explore moving CDS Hooks as an independent entity within the HL7 CDS community to solve the problem of external CDS, leaving the current Clinical Reasoning project to focus on the problem of local CDS.
What does this mean to all of you who are implementing CDS Hooks?
Not much, actually. We’re not changing our focus or design. The simplicity and focus of CDS Hooks has been one of its best strengths which is evident in the broad support, interest, and ease of development within the community. We will not compromise that.
What does this mean for how the project is managed?
Again, not much. CDS Hooks will remain a consensus driven open source project using modern development practices and tooling and following its own independent release process. I think this has worked well for other projects like SMART. I am working on a more formal project governance (more on this later) that should allow us to continue operating as-is while simultaneously satisfying HL7’s requirements.
Additionally, all of the conversations and work we’re just now starting will be done in full view of the community. Any proposed changes to CDS Hooks will continue to be logged as Github Issues and discussed with those interested, we’ll still run Connectathon tracks to get implementer feedback, and we’ll continue to use this mailing list and Zulip for discussions.
How does this benefit CDS Hooks, Clinical Reasoning, and the community?
First, the entire CDS community will have a clear understanding of Clinical Reasoning and CDS Hooks as well as when it’s appropriate to use each approach.
Second, both projects are going to be strengthened by our continued joint work to align on shared needs, identify gaps, and work in complementary directions rather than potentially pulling in opposing directions.
Finally, having CDS Hooks published under HL7 will benefit organizations that are constrained to recommending or implementing HL7 standards.
I’m excited for the work we’re all going to do within the CDS standards communities and specifically, CDS Hooks. The community support around CDS Hooks has been outstanding and I’m looking forward to working towards a 1.0 releases of a CDS Hooks spec this year as well as our first production implementations.

Verhoeff Algorithm in Delphi

I needed an implementation of the Verhoeff check digit algorithm in Delphi, and couldn’t find one. So reproduced here for ease of use by anyone else who needs it:

const
 verhoeff_d : array[0..9,0..9] of integer = (
 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
 (1, 2, 3, 4, 0, 6, 7, 8, 9, 5),
 (2, 3, 4, 0, 1, 7, 8, 9, 5, 6),
 (3, 4, 0, 1, 2, 8, 9, 5, 6, 7),
 (4, 0, 1, 2, 3, 9, 5, 6, 7, 8),
 (5, 9, 8, 7, 6, 0, 4, 3, 2, 1),
 (6, 5, 9, 8, 7, 1, 0, 4, 3, 2),
 (7, 6, 5, 9, 8, 2, 1, 0, 4, 3),
 (8, 7, 6, 5, 9, 3, 2, 1, 0, 4),
 (9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
 );
// The permutation table
 verhoeff_p : array[0..7,0..9] of integer = (
 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
 (1, 5, 7, 6, 2, 8, 3, 0, 9, 4),
 (5, 8, 0, 3, 7, 9, 6, 1, 4, 2),
 (8, 9, 1, 6, 0, 4, 3, 5, 2, 7),
 (9, 4, 5, 3, 1, 2, 6, 8, 7, 0),
 (4, 2, 8, 6, 5, 7, 3, 9, 0, 1),
 (2, 7, 9, 3, 8, 0, 6, 4, 1, 5),
 (7, 0, 4, 6, 9, 1, 3, 2, 5, 8)
 );
 //The inverse table
 verhoeff_inv : array [0..9] of char = ('0', '4', '3', '2', '1', '5', '6', '7', '8', '9');

//For a given number generates a Verhoeff digit
function genCheckDigit(s : String): char;
var
 i, c, len : integer;
begin
 c := 0;
 s := s + '0';
 len := length(s);

 for i := len downto 1 do
   c := verhoeff_d[c][verhoeff_p[((len-i) mod 8)][ord(s[i]) - ord('0')]];

 result := verhoeff_inv[c];
end;

////Validates that an entered number is Verhoeff compliant.
////The check digit must be the last one.
procedure validateCheckDigit(s : String);
var
 i, c, len : integer;
begin
 c := 0;
 len := length(s);

 for i := len downto 1 do
   c := verhoeff_d[c][verhoeff_p[((len-i) mod 8)][ord(s[i]) - ord('0')]];

 if c <> 0 then
 raise Exception.Create('Check digit error: "'+s+'" is not valid by Verhoeff algorithm');
end;

 

#FHIR Video Contest

We work hard to ensure that the FHIR specification is as easy to understand as possible. For example, we have several ‘getting started’ guides for different audiences. But never-the-less, getting orientated with the specification, and/or the FHIR connectathon process can still be a challenge. So today, HL7 is announcing a competition.

Contest entrants must post a video to Youtube that helps implementers ‘get started’ with the FHIR specification and/or the FHIR connectathons. Videos should be less than 5 minutes long, and be posted to Youtube by November the 1st.

Video entries will be judged by Ed Hammond (don’t know Ed? He’s “Mr HL7” is anyone is – see this award), and the winner will get free registration (or refund etc) for their next HL7 meeting.

Ed and I will be awarding some prizes for additional categories, including a ‘community preference’ award.

#FHIR and Character encoding in URLs

One issue that is causing confusion for FHIR implementers is the question of what characters need to be escaped in an http: URL. The general shape of an http: url is

http://[server name]/[path]?[name]=[value]&[name]=[value]

Examples:

  • http://acme.org/fhir/Patient/1
  • http://acme.org/fhir/Patient?gender=male&address-postalcode=12345

For a FHIR implementer, we will assume that there is no need to do escaping in the [server name] and [path] fragments (there’s possibly corner cases where you might need to, but these are either rare or non-existent in the FHIR community). On the other hand, there’s certainly specified circumstances where the parameter value is specified to contain characters that may need escaping. For example, one possible URL is:

GET fhir/ValueSet?url=http%3A%2F%2Fhl7.org%2Ffhir%2FValueSet%2Fclinical-findings

In this URL, the characters : and / have been encoded using % encoding, as specified in the http standard. (See the encoding table here, but I prefer this tool for normal use). But what characters do you have to encode like that? well, that’s where it gets a little slippery. Quoting from wikipedia:

When a character from the reserved set (a “reserved character”) has special meaning (a “reserved purpose”) in a certain context, and a URI scheme says that it is necessary to use that character for some other purpose, then the character must be percent-encoded.

The key thing here is that which characters have to be encoded depends on which characters have special meaning. In a parameter value, the character ‘&’ has special meaning – so you have to escape that. Escaping the rest is optional. So this URL is equal to the one above:

GET fhir/ValueSet?url=http://hl7.org/fhir/ValueSet/clinical-findings

as is this:

GET fhir/ValueSet?url=%68%74%74%70%3A%2F%2F%68%69%37%2E%6F%72%67%2F%66%68%69%72%2F%56%61%69%75%65S%65%74%2F%63%69%69%6E%69%63%61%69%2D%66%69%6Ed%69%6E%67%73

These are all valid, and servers should support all the possible variants. Generally, we try to keep away from specifying characters that need escaping; they just cause problems for everyone. Yes, they’re resolvable, but no, we don’t want people losing time over them, so we don’t, e.g. define parameter names with ‘=’ in them.

So, as a client, you only need to escape in a very few places. There’s one place in the FHIR spec where this escaping arises as an explicit issue, we we need escape with in the value of the parameter itself. This edge case is discussed explicitly in the spec.

Note that there’s one other case where you absolutely have to escape the parameter values: if they contain characters not in the ASCII code range of characters 33 – 127 – typically, spaces or unicode characters.

Question: Apple CareKit and #FHIR

Question:

I am very new to FHIR and now i am trying the find out equivalent resource for  Apple carekit data. I think i can use FHIR Careplan & Goal for the CareKit data. Is that right?

Answer:

I’ve not done any work with CareKit, but Apple suggested I talk to Seth Berkowitz at BIDMC, who says:

CareKit is a set of UI and database components that provide a framework to display careplans, collect patient generated data, provide insightful feedback to and from patients via their iOS phones.  By leveraging simple game mechanics and Apple’s design ethos, the UI components of CareKit help motivate patients to comply with their daily medications and activities as part of their care plan.  The assessment component streamlines the collection of subjective and objective data from patients using the phone as middleware. Objective data collection is facilitated through HealthKit, which is Apple’s centralized database on it’s phones that facilitates the sharing of objective health metrics in between apps.  The last component of carekit is a communication module that helps patients share their care plans and results with friends, family, and medical professionals

BIDMC we are integrating our CareKit app directly into our homebuilt EHR so that the app becomes a direct conduit of prescriptions and orders from doctor to patient, and patient generated data from patient to doctor.  Although our short term goal is to benefit our own population of patients, we share Apple’s long term vision of widely disseminating these engaging apps.  To that end, we are trying to leverage FHIR APIs as much as possible to serve as the connections between our EHR and the App.  The hope is that Apps like this serve as a “carrot” to promote more widespread adoption of the FHIR standard.  Our two main APIs using FHIR are a medication search bundle and CarePlan resource.  Our medication bundle leverages our institutions participation in the Argonaut projects

CareKit encompasses several functions which pose potential FHIR interfaces for data download and upload.  To date, my group has focused on leveraging FHIR for data download in order to populate the CareKit “CareCard” (a patient check list of careplan activities) and Carekit “Assessment” or subjective and objective measurements collected on the phone. An overarching question that we’ve been trying to solve is how encode UI / implementation specific data fields within the appropriate FHIR schema.  For example, a careplan activity in carekit is displayed with a title, a subtitle, and more detailed instructions.  For each careplan activity I’ve been using the following mapping

  • Title: activity.detail.code.text
  • Subtitle:  activity.detail.goal (either display or description of a contained resource)
  • Instructions: activity.detail.description

For quantitative measurements that are collected on the phone through the HealthKit database, I define an “observation” activity within the careplan.  The activity.detail.code.coding array defines a LOINC codable concept which is then mapped to Apple’s internal reference system for various physiological measurements (heart rate, blood pressure, daily sodium intake, etc)

Finally, we define certain alert conditions that may prompt a message to the patient after a measurement is obtained.  These alerts are implemented as an extension to the activity.detail.goal.  The extension includes a valueQuantity which is the threshold that triggers the alert and a referenced Flag resource which is the alert prompt to the user.

There’s much more to be done to build an end-to-end CareKit FHIR interface, but that’s what we’ve been working on so far.

Thanks to Seth and also to Pascal Pfiffner, who’s been a trail blazer with regard to FHIR use on iOS (and who maintains the FHIR Swift reference implementation).

Seth noted that with the careplan resource, it feels like they’re pushing the limits of how the careplan is being used in practice – and indeed, that’s true. There’s a lot of active projects using FHIR as the format for exchange underlying shared care/ collaborative care projects that involve the patient, and their various care teams: family, professional, social etc., and this is a new – exciting! – area where there’s not a lot of established knowledge, culture, and practice for us to fall back on. So implementers should expect more change in this area than in the well established ones (patient management, diagnostics, medication administration, billing).

Question: Binding choices

Question:

A question regarding “Standard” codes vs. Customized codes: To my understanding, if I want to exchange FHIR resource, any property in that resource can be filled by either of the following options:

  • Using the standard clinical coding system for relevant clinical properties (for example, SNOMED CT code for MedicationOrder>Medication>code
  • Using the HL7 FHIR administrative coding system for relevant administrative properties (for example, http://hl7.org/fhir/ValueSet/medication-order-status for MedicationOrder>Status)
  • Using customized, in-house, coding system, but for that I need to define it as appropriate ValueSet, bounded into appropriate Profile.

Answer:

So this answer (and the question, really) applies to any property in a resource that has a type of Coding or CodeableConcept. In principle, any property of a resource that has a type can be filled by any one of those choices – a SNOMED CT code (or RxNorm, or LOINC, or …), a FHIR defined code, or a locally defined code. However for all these properties, we ‘bind’ them to a value set, and that value set makes a rule about what kind of codes can be used.

Element <– (binding) –> ValueSet

So if the property is bound to SNOMED CT, then you have to use a code from SNOMED CT. But note that if the type is CodeableConcept, which can have more than 1 coding, then this means that one of the codings has to come from SNOMED CT – for the others, you have can use anything at all that you like.

Further, the binding itself has an important property – the ‘strength‘ of the binding. This key property tells you how to interpret the binding:

required You have to use one of the specified codes
extensible You have to use one of the specified codes, unless there isn’t an appropriate one. Then you can use whatever you like
preferred This is the sort of codes you should use – and this value set really is a good idea to use
example This is the sort of codes you should use

So the last 2 binding strengths are not, well, binding: you can ignore them as you see fit. So what you can actually use in a resource property depends on the strength of the binding, and the value set it references. But, sadly, most of the really interesting properties in most resources have a binding strength of ‘example’ – precisely because they are most interesting, we have no way to get consensus on the right coding system (let alone the right set of concepts). A great example is Condition.code:

. code 1..1 CodeableConcept Identification of the condition, problem or diagnosis
Condition/Problem/Diagnosis Codes (Example)

An example binding to a large set of SNOMED CT codes….

Finally, some notes on your choices:

  • Standard clinical coding system: we always recommend that you use one of these. But these can be hard to use. We introduced the terminology service to make this easier, and this is a concept that’s just about in the goto-market phase
  • FHIR code systems are mostly defined for the fixed properties like status where you have to use one of the fixed codes we defined, but sometimes we define a code system to be used with Coding/CodeableConcept. We generally try pretty hard to not overlap with the standard terminologies, so it’s usually a choice of one or the other
  • When you use a customised in house coding system, you don’t actually have to define it using a value set, but doing so allows you to tell everyone else in a computable fashion what you are doing, so it’s a good idea, yes.

 

 

#FHIR and the Gartner Hype Cycle

As FHIR product director, I get plenty of comments about the hype associated with FHIR. And there is plenty of hype. Here’s the Gartner hype curve:

Where are we on that curve, people want to know? Well, my answer is that as far as I can tell, the rate of increase of hype is still increasing, so it seems as though we’re still in the initial rocket phase.

What’s the hype?

For me, hype is beyond enthusiasm – it’s when people make wildly inflated claims about what is possible, (wilfully) misunderstand the limitations of the technology, and evangelise the technology for all sorts of ill judged applications (about where block chain in healthcare is right now).

So what things do I see that I think are hype? Well there are many symptoms, but one fundamental cause: there’s an apparently widely held view that “FHIR will solve interoperability”.

It’s not going to.

FHIR is 2 things: a technology, and a culture. I’m proud of both of those things. I think both of those will make a huge contribution towards solving the problems of interoperability in healthcare. But people who think that problem will be solved anytime soon don’t understand the constraints we work under.

HL7 is an IT standardisation Organization. We have severely limited ability to standardise the practice of healthcare or medicine. We just have to accept them as they are. So we can’t provide prescriptive information models. We can’t force vendors or institutions to do things the same way. We can’t force them to share particular kinds of information at particular times. All we can do is describe a common way to do it, if people want to do it.

FHIR is good for sharing information out of an EHR – but confirming to FHIR doesn’t prove anything; there’ll have to be some policy layer above that. More generally, if you have 2 teams (departments, vendors, governments, whatever) that don’t see eye to eye, forcing them to adopt FHIR as a technology isn’t going to change anything. Getting them to adopt the FHIR culture – that will. But you cannot impose that.

So what can we do about that?

What we – the FHIR team – can do is to make sure the fundamentals are in place. Good governance, solid processes, well tested specifications, an open and inclusive engagement framework. If we can get that right – and it’s a work in process – then the trough of despair won’t be as deep as it might, and we can focus on our task: getting the standards out of the way of solving problems in people’s healthcare.

Follow up: have you read my 3 laws of interoperability?