Stream: implementers
Topic: SMART launch with multiple FHIR versions
Cooper Thompson (Sep 04 2018 at 16:36):
We support some resources on DSTU2, others on STU3, and will soon have some on R4. Because our development capacity is limited, it is not likely that we will always be able to support all resources on all versions (at least not in the near future). So we are in the position where we have apps that need to query multiple different FHIR versions to get all the data they need. In order to support this when doing a SMART launch, we need to communicate the different iss endpoints and FHIR IDs for different versions. One option we discussed was doing some Epic-specific context parameters in the oauth2/token response like so:
{ "patient": "id2", "epic.stu3.patient": "id3", "epic.stu3.iss ": "https://server/api/FHIR/STU3", "epic.r4.patient": "id4", "epic.r4.iss ": "https://server/api/FHIR/R4", "token_type": "bearer", "scope": "whatever", "client_id": "whatever", "expires_in": 3600, "access_token": "asdf", ... }
This is kinda a 'meh' approach, but AFAIK the HTTP Header option for asking for a specific FHIR version from a single endpoint still isn't a thing. Plus we've sort of painted ourselves into a corner for now by putting the version in a URL path component (which I don't mind admitting because I think everyone else basically has too).
Do folks have thoughts on this idea, or alternatives for solving this problem?
Cooper Thompson (Sep 04 2018 at 16:39):
Note that in our case, the access token would work against any of the listed FHIR endpoints.
Jenni Syed (Sep 04 2018 at 16:44):
Ignoring the iss/SMART issue... this could be difficult for consumers to handle. Libraries vary on how easy it is to consume (and validate) different versions of FHIR within the same executable/classpath
Jenni Syed (Sep 04 2018 at 16:46):
But back to iss... :)
Jenni Syed (Sep 04 2018 at 16:46):
Even if you were able to do the version handling pre-version header in the server by adding a different entry... the challenge would be how to communicate which version the resource is in.
Jenni Syed (Sep 04 2018 at 16:47):
IE: since you don't have the header option, If you added my.fhir.allversions.com/..., which sees "Observation" (as an example) and knows that's available only on STU 3...
There's no way to tell the caller that what they're getting is STU 3 instead of DSTU 2
Jenni Syed (Sep 04 2018 at 16:48):
So that their parser doesn't blow up
Jenni Syed (Sep 04 2018 at 16:51):
(this abstraction/adding a layer that handles routing is a way around ISS if it wasn't for the "how to tell them what version you were able to handle" issue)
Cooper Thompson (Sep 04 2018 at 17:29):
For your point about consumers - juggling versions in libraries is going to be a problem so long as you don't support all the resources the app needs on the version the app wants. If an app needs to use two different versions, they have to solve that problem anyway.
Back to iss...
Right now, the version you are getting is encoded in the iss URL, which isn't "spec-official", but is maybe "good enough". We could go ahead and call out the version associated with all resources returned from an iss URL in the JSON. Long term maybe that is a response header (which doesn't solve files or messaging, as we all know...). My opinion on putting a version in the token response is basically the same as my initial proposal, which is to say: "meh - but given where we are not sure I see better short-term options".
{ "patient": "id2", "epic.stu3.patient": "id3", "epic.stu3.iss ": "https://server/api/FHIR/STU3", "epic.stu3.version ": "STU3", "epic.r4.patient": "id4", "epic.r4.version ": "R4", "epic.r4.iss ": "https://server/api/FHIR/R4", "token_type": "bearer", "scope": "whatever", "client_id": "whatever", "expires_in": 3600, "access_token": "asdf", ... }
Nick Hatt (Sep 04 2018 at 20:54):
@Cooper Thompson I saw the channel #versioned API exists. There isn't really a consensus in there, but you may find some interesting background info.
Grahame Grieve (Sep 04 2018 at 21:58):
the HTTP Header option for asking for a specific FHIR version from a single endpoint still isn't a thing
Grahame Grieve (Sep 04 2018 at 21:58):
it is documented in the current ballot version of R4 and can be retrofitted to previous versions (that's the point, really).
Grahame Grieve (Sep 04 2018 at 21:58):
I do not think that this removes the need for the discussion though
Matt Varghese (Sep 13 2018 at 14:12):
I also want to point out that:
1. The HTTP header will not cover CDS hooks. CDS Hooks makes a custom JSON bundle rather than using the FHIR bundle. In the Collection of CDS Hooks resources (trying to not call it bundle) that goes in either the prefetch or the context, each resource may be a different FHIR version. Our solution should support that.
2. The HTTP header will not cover the FHIR Bundle resource. It can only capture the FHIR version of the bundle itself. Each resource inside the bundle will likely be a different FHIR version, given where EHRs are at with implementing FHIR. How do we capture the versions of each of these resources?
3. I think the right thing to do is for each resource to have its own version - resources becoming self identifying. The argument I have heard against this is that, then we will have to parse the resource before we know how to parse the resource. However, the same concern applies to resource type, but resource type is the first thing in the JSON for the resource, and it works! We can additionally consider performance optimizations like the HTTP header option being talked about. But having the resrouceVersion
, in addition to resourceType
, in the resource itself will avoid problems where some flow which was not anticipated stores off a resource without storing off the version which currently is not part of the resource.
4. Even if for no other reason, having the resourceVersion
in the resource itself enhances debugability. Say the EMR responds with the HTTP header saying resource is 1.0.2, but the resource actually is 3.0.1, and the EMR mixed up the version in the header - the self-identifying resourceVersion
will allow the consumer to quickly spot why their app crashed, because it is less likely to be mixed up than an out of bounds mechanism like the header.
Josh Mandel (Sep 13 2018 at 15:08):
One pattern we've been thinking about comes up when a single authorization server is minting tokens that can be used at multiple FHIR endpoints -- which I think applies here @Cooper Thompson. We've introduced the concept of a ./well-known/smart-configuration.json
file in the ballot revisions for SMART. (This file lists a server's capabilities, OAuth endpoints, etc.)
I wonder if this file might be used to include a "list of other endpoints where your access token can be used", as in:
{ "authorization_endpoint": "https://ehr.example.com/auth/authorize", "token_endpoint": "https://ehr.example.com/auth/token", "token_endpoint_auth_methods_supported": ["client_secret_basic"], "registration_endpoint": "https://ehr.example.com/auth/register", "scopes_supported": ["openid", "profile", "launch", "launch/patient", "patient/*.*", "user/*.*", "offline_access"], "response_types_supported": ["code", "code id_token", "id_token", "refresh_token"], "management_endpoint": "https://ehr.example.com/user/manage" "introspection_endpoint": "https://ehr.example.com/user/introspect" "revocation_endpoint": "https://ehr.example.com/user/revoke", "capabilities": ["launch-ehr", "client-public", "sso-openid-connect"], "endpoints": [{ // FHIR endpoint content here "address": "https://ehr.example.com/r3", "payloadMimeType": "application/fhir+json; fhirVersion=3.6" },{ // FHIR endpoint content here "address": "https://ehr.example.com/r4" "payloadMimeType": "application/fhir+json; fhirVersion=4.0" }] }
Josh Mandel (Sep 13 2018 at 15:08):
I've been thinking about this in the context of providing access to an Imaging server, but it could be used to provide access to any collection of FHIR servers just the same way.
Josh Mandel (Sep 13 2018 at 15:14):
(@Grahame Grieve I'm not sure in the example above how to express "this is a FHIR r4 server"; I sketched this out badly with a mimeType parameter, but that also winds up saying "json" which I didn't want to specify.)
Lloyd McKenzie (Sep 13 2018 at 15:29):
At the moment, FHIR Bundles containing hetrogeneous resources is non-conformant. And I'm not aware of any of the reference implementations that could handle that situation.
Lloyd McKenzie (Sep 13 2018 at 15:30):
The expectation has always been that servers will convert their data to the version requested, will suppress data they can't convert or will fail
Matt Varghese (Sep 13 2018 at 15:32):
@Lloyd McKenzie , I think that is the problem that needs to be solved.
If the EHR only has support for MedicationRequest in DSTU2 and ProcedureRequest in STU3, it might be a long time before the former is updated. What if you need a bundle of them both currently? The current answer is this is not possible, and we need to change that. The expectation does not satisfy the current needs and needs review.
Jenni Syed (Sep 13 2018 at 15:44):
That could be pretty challenging for parsers/libraries
Jenni Syed (Sep 13 2018 at 15:45):
when we did our transition from may2015 to DSTU2, we just had separate servers. Apps only moved over to the other once everything they needed was available on that version.
Jenni Syed (Sep 13 2018 at 15:45):
when you say in the same bundle, are you talking about $everything style operations? Batch/Transaction?
Jenni Syed (Sep 13 2018 at 15:47):
that was also pre-versioning. If I wanted to try to do something like what you're describing today, I would set up a server that understood the new headers. However, like lloyd mentioned, if there was no way for my server to do the conversion on the fly for some resource, it would likely fail
Lloyd McKenzie (Sep 13 2018 at 15:49):
FHIR is designed to be coherent within a version, but not across versions. How will you handle a ServiceRequest reference in an R4 instance that you're exposing as an R3 ProcedureRequest. It's a huge ugly can of worms.
Lloyd McKenzie (Sep 13 2018 at 15:54):
For a lot of resources, the conversions are relatively straight-forward and we provide computable mappings. Implementations can (and should) implement those. Where the changes have been more radical, clients can choose betwen making separate queries (e.g. one against R4, one against STU3) or forego certain functionality. Crossing the streams doesn't work with any of our infrastructure - validator, reference implementations, testing services, public test servers, etc. It's something we could explore as we start to approach R5, but I can't fathom how we could land such a thorny issue, document and test it in time for R4. We've only got 1.5 months until the substantive freeze for R4 and the last connectathon before that publication happens in 2 weeks.
Matt Varghese (Sep 13 2018 at 16:49):
You are only punting the problem from the FHIR consumer (App/CDS Service etc) to the FHIR producer / EHR who is already struggling to keep up with FHIR versions, and make implementations of resources available.
We, at least internally at Epic, don't see an immediate future where we will have all resources we support across all versions. So it is an urgent need that we create mechanism for FHIR to go across versions in resource consumption.
Note also that people are already doing this - just through custom ways. We are just asking to standardize this.
I understand it is challenging - but aren't we all here already to solve challenging problems?
Josh Mandel (Sep 13 2018 at 16:57):
Not to solve challenging problems per se -- we are trying to address real world needs with technical solutions that are a good blend of ... Suitable, Universal, Implementable, etc.
Lloyd McKenzie (Sep 13 2018 at 16:57):
If we're going to punt an issue anywhere, it will almost always be to the servers - as they're generally the most sophisticated systems in the exchange and best able to deal with increased complexity. (Expecting multi-version support and integration of multiple reference implementations in an iPhone or android client isn't really on the table.) The challenge is understood, but there's also a question of timeframes. We can't make any substantive changes to Bundle for R4 without throwing out the notion of R4 containing normative content. That's not something we'd contemplate for this issue. So if it's going to be solved (which will depend on us figuring out a workable technical mechanism), there's no way for it to exist in the official spect until R5.
Matt Varghese (Sep 13 2018 at 20:25):
EHRs also have a finite set of resources (not the FHIR term). EHRs can either use that to create different version copies of what is conceptually the same thing, or to implement new FHIR resources. Especially, if say an STU3 instance of a resource "meets the need," the EHR could say, "it's more useful for me to spend the time making a new resource in R4, than to port that existing resource into DSTU2 and to R4." Essentially, if we solve the versioning problem, then there is more interoperability and more resources to consume,
whereas if we fixate on FHIR version consistency, the pace of adoption of FHIR will be severely constrained.
Also, your point of EHR having sophisticated systems is not an accurate representation of all considerations. DSS services, and other FHIR consumers generally use publicly available libraries etc for FHIR. Right now, the existing libraries are married to specific versions. However, if for example the .NET FHIR library on nuget instead of being three libraries FHIR.NET-DSTU2, FHIR.NET-STU3 and FHIR.NET-R4, were one single library FHIR.NET which contained the resource models for DSTU2, STU3 and R4 (or even better, every numeric version of FHIR), then the job of the consumer - in my perspective - is rather simple. In fact, these FHIR version transmutation solutions you mentioned can even be baked into such consumer libraries.
However, unlike that, the EHRs have a real problem with supporting all versions - there is a data-model behind the FHIR data-model that is not FHIR, but proprietary - engineered over many years. And while transmuting a resource from DSTU2 to STU3 may be okay for the consumer's use, there are greater expectations on the EHR with regard to data fidelity - if there are optional elements in the newer version that the lower version did not support, but the data is available to the EHR, then the EHR should fill that in. So on the EHR side, this is not a simple transmutation of resources between versions.
As for load on a mobile device, the ASP.NET HL7 library + a simple app published on it come to a mere 5.2MB of hosting space. So I can't imagine it being a lot of code / overhead we are talking about even on mobile. And if they don't use a multi-version library, they are maintaining status quo - not retrogressing, whereas if they use a multi-version library, they can go above and beyond what they can consume today. Plus, if the app is really clinically valuable, it will likely evolve to have a server backend.
Therefore, I really think supporting versioning within the resource and resources of different versions on the same FHIR server is the better long term strategy.
Also, a lot of other standards do the same thing - support versioning within their payloads. They must have seen some value in it?
Matt Varghese (Sep 13 2018 at 21:19):
Also, on the ability to adopt new FHIR versions as they come out, if resources across multiple versions can co-exist and be exchanged, then when one resource is available in R4, the R4 version of that resource can be used, even though other resources are all STU3. Whereas currently, a consumer has to wait until the producer has upgraded all their required resources to R4, before they can consume R4 from the producer. So there is a huge lag, less feedback and delayed adoption, leading to slower maturity.
Isaac Vetter (Sep 27 2018 at 21:49):
Hey Guys - interesting question from an implementer pointing out that running multiple versions of HAPI on a mobile client started to get too big.
Matt Varghese (Sep 28 2018 at 01:16):
@Isaac Vetter I think you are missing the more important takeaway that someone is already trying to do this :P
And asking for help on how to do this.
Josh Mandel (Sep 28 2018 at 04:33):
I think the question there was about library support for consuming multiple versions of FHIR -- not for a way to represent/handle individual payloads with mixtures of multiple versions.
Matt Varghese (Oct 01 2018 at 17:26):
@Josh Mandel Yes, the specific question there is about library support for multiple versions of FHIR. However, I infer from it that they may be trying to consume multiple FHIR versions within the same App. 'Why?' becomes the natural follow-up question in my mind..
I had seen this spec http://build.fhir.org/versioning.html on supporting versioning, and @Kevin Olbrich also pointed me to this since he was involved in the development. I see that as a great step forward. I had asked for a resourceVersion property above, but @Cooper Thompson convinced me that if we make the profile meta required, then that will essentially cover the need without breaking backwards compatibility. So then the only thing missing from the proposal really is the ability to mix resources of different versions in bundles, CDS-Hooks etc; although, if a bundle profile is made, which specifies different profiles crossing versions on the included resources, maybe this is possible?
So what I am asking really may not be very far off. And @Kevin Shekleton had expressed willingness to consider CDS-Hooks incorporating a cross-version solution if FHIR comes up with one that can be reasonably analogously included in CDS-Hooks as well.
Grahame Grieve (Oct 01 2018 at 22:30):
we have no framework for crossing resource versions inside a bundle. I can't imagine how we'd introduce that. I presume you are interested in what goes in the prefetch? if so, we make no rule that the different properties of the pre-fetch object are all the same version
Grahame Grieve (Oct 01 2018 at 22:31):
nor should you make the meta.profile required - certainly not in the general case.
Matt Varghese (Oct 02 2018 at 04:34):
@Grahame Grieve, you are not offering a solution :(
Let's say, as you envision, some time in the future, FHIR becomes stable. Let's say it's FHIR version R10. Then, let's say cultural identity becomes a major concern for Patient resource, like gender identity is today, and so we need to make a change to the Patient resource in R11.
Is the FHIR stance going to be that, until (1) EMRs have implemented R11 for ALL resources they previously supported in R10 (this is actually some work, even though possible rote-work), and (2) FHIR Application that previously used R10 has completely upgraded itself to use everything in R11, the new capabilities for the Patient resource may not be used?
If that is not how we envision it, then we have to also accept the possibility that this patient resource may be bundled with other resources in a FHIR bundle. So we need to be able to bundle the R11 Patient resource with other R10 resources in this hypothetical, but very faithful to present day problems, use-case.
Grahame Grieve (Oct 02 2018 at 09:48):
this is why I recommend not stating the version of the resources at all. because if you don't, then the EMR reading the bundle can read it as either Rx or Rx+1 and accept unknown elements
Grahame Grieve (Oct 02 2018 at 09:49):
but I repeat: we have no framework for mixing versions in a bundle. It's not that I'm not interested in the problem, it's just that I can't imagine how we could expect applications to support that
Dennis Patterson (Oct 02 2018 at 14:53):
Cerner is in the same camp of not having capacity to constantly uplift all resources across the board to the latest version of FHIR. If we introduce a new resource, we also don't want to necessarily have to back-patch it to an old version of FHIR just because that's what the majority of consumers are using. We share the situation of using separate endpoints for separate versions of FHIR, but have no interest in mixing multiple versions in a single request/reply.
We've discussed a future move towards a single base URL (not necessarily a single deployment) that can route based on the fhirVersion in the media type. A client library would:
1. call $versions to discover what's supported
2. optionally call /metadata for one or more supported versions
3. obtain resources using content type negotiation
We would have to create this single entry point (likely behind an API Gateway to abstract away our deployment strategy), support the $versions operation, start requiring fhirVersion in Accept/Content-Type headers, and gradually migrate 3rd party apps to use it.
This would:
- allow one url for SMART launch
- help with references between resources (though there are still complexities around resource renames, for example)
As FHIR content becomes more and more normative, this seems like the right direction. In the meantime, with breaking changes and EHRs unable to keep up with constant uplifts, I recognize that it introduces more complexity into client libraries.
Matt Varghese (Oct 02 2018 at 15:46):
@Grahame Grieve, isn't the burden of mixing versions already on the client application with the multiple version spec (http://build.fhir.org/versioning.html), with or without mixed version bundles?
@Dennis Patterson, isn't the $version you are proposing an additional web service call? In a SMART app, or especially in CDS Hooks where there is a constraint on turnaround time, and the FHIR server is not known until the App / Hook invocation (for any caching), doesn't this mean, there is yet another burden on the App/Service? The App has to first find versions supported, then if the bundle / collection of resources being requested spans across versions for different resources, the App needs to build logic to break that request into multiple separate requests for the same logical request? Or am I misunderstanding what is proposed?
Dennis Patterson (Oct 02 2018 at 16:07):
$versions is out on http://build.fhir.org/operation-capabilitystatement-versions.html; I'm suggesting it has use here. The call would be made up-front and cached. For the bundle where the are multiple resources existing across different versions, I'll make up an example use-case: an app wanted resource A and B, where A exists for STU3 and DSTU2, but B only exists for DSTU2. One option would be to get resource A at STU3 and resource B separately at DSTU2. Alternatively, you could take a common denominator approach and load both at DSTU2 if chattiness is a concern. EHRs will, of course, work with apps to prioritize resources uplifts to match use-cases.
Last updated: Apr 12 2022 at 19:14 UTC