FHIR Chat · FHIR API versioning · implementers

Stream: implementers

Topic: FHIR API versioning


view this post on Zulip Jonny Rylands (Sep 25 2017 at 20:56):

Is there a standard way to version FHIR REST interfaces? (e.g. https://host/{FHIR-VERSION}/{API-VERSION}/Patient/1 )

view this post on Zulip Lloyd McKenzie (Sep 26 2017 at 03:11):

Not at present. And our intention, once things are normative, is for version not to matter anymore.

view this post on Zulip David Hay (Sep 26 2017 at 06:10):

will still have business versions...

view this post on Zulip Ewout Kramer (Sep 26 2017 at 09:46):

Not at present. And our intention, once things are normative, is for version not to matter anymore.

That being said, DSTU2, and increasingly STU3 and R4 will be around for a long time - and it's kind of a FAQ. Out of interest: As a client - what would you do if there was a "standard" way of finding the endpoint for a specific version - would you envision being able to use multiple versions.....I can see that would get likelier with each version of the spec, and resources becoming more mature...

view this post on Zulip Jonny Rylands (Sep 26 2017 at 13:04):

No in the most part I wouldn't envisage a client using multiple API versions (or negotiating versions).

The purpose of the API versioning is two fold - to prevent against breaking backwards compatibility, and to be able to technically and clinically assure a clients implementation of a particular version of an API. The assurance breaks if the interface evolves over time, hence our need for versioned interfaces. (- or never to change our interface! :-))

Note by API version I'm referring to the version of the interface, rather than the FHIR version, though the two are obviously interconnected.

Also to mention that the clients are not in our direct control, and therefore we cannot simultaneously update client & interface/implementation at the same time.

view this post on Zulip John Moehrke (Sep 26 2017 at 13:11):

I really want to hold to the no versioning, as Lloyd has expressed. BUT when we get to R4, we are going to be faced with no alternative. This because in R4 we will not be taking ALL resources to Normative, some will be STU. Those STU resources might take a few additional revisions before they become normative. Thus in R4 we must support a normative Bundle holding normative resources, and non-normative resources. Those non-normative resources might be generation 4 or 5 or 6 or their final normative... Thus I hate to say it, but we need some solution eventually.

view this post on Zulip Ewout Kramer (Sep 26 2017 at 13:46):

One aspect that I am getting out of this is the endpoint url remaining the same, yet the API version going up. Some clients (at least the .NET and Java ones) let you verify this by getting the CapabilityStatement and checking the version - but that's kind of chicken and egg, using a specific version of the CapabilityStatement (which was renamed as well in STU3!) to check the version. Following something like you sketched out as a best practice is a good thing - and I see it being done that way.

At the San Diego WGM we found examples of both out in the wild:

The latter situation allows for content negotiation involving versions. An interesting concept that we might want to try out at the next connectathon in New Orleans in january.

view this post on Zulip Kevin Olbrich (Sep 27 2017 at 15:45):

We are operating under the assumption that we will need to support multiple FHIR version simultaneously for quite some time. The approach we are taking towards that is to pass the version in the Accept header by setting the mime type to something like 'application/fhir+json; fhirVersion=3.0.1' and then switching versions on the server.

view this post on Zulip Matthew Spielman (Sep 27 2017 at 18:56):

We are offering multiple endpoints by version rather than doing anything like headers.

view this post on Zulip Lloyd McKenzie (Sep 27 2017 at 22:56):

The AcceptHeader approach isn't standard and isn't likely to be recognized by most servers

view this post on Zulip Ewout Kramer (Sep 28 2017 at 07:35):

@Kevin Olbrich @Matthew Spielman - that's interesting you each represent one of the options I mentioned - I'd be interested in why you have chosen one over the other...

view this post on Zulip John Moehrke (Sep 28 2017 at 12:56):

The mime-type one is automatic since we have changed mime-type between DSTU2 and STU3...

view this post on Zulip John Moehrke (Sep 28 2017 at 12:56):

Neither of these address my concern about mixtures. specifically that at R4 we will have mixtures from that point forward.

view this post on Zulip Lloyd McKenzie (Sep 28 2017 at 14:41):

Not sure what you mean by "mixtures" John. In a given instance, all resources must be from a single version. If you're sending an R5 instance, all content will be from R5. It's just that the normative content will also be compatible with R4.

view this post on Zulip John Moehrke (Sep 28 2017 at 14:58):

Okay, so your perspective is that once a Resource goes normative it is not "R4", it is "Normative". Thus all Normative are infinitely compatible. Somehow I knew that, and agree with it.. but it did get lost in the versioning discussion. Especially since we are projecting "R4" as something that 'contains normative' content... thus there is marketing that seems to indicate normative resources do have a "Revision" number...

view this post on Zulip Lloyd McKenzie (Sep 28 2017 at 15:00):

A normative resource in R5 could even have an extra data element or two than it had in R4. It's just that the backward compatibility rules would allow you to ignore those elements if you're processing them as R4 instances.

view this post on Zulip Joel Schneider (Sep 28 2017 at 15:03):

Wouldn't having only some resources normative mean the FHIR API endpoint as a whole is not normative? (in that it's important for the client to know the server's FHIR API version)

view this post on Zulip Joel Schneider (Sep 28 2017 at 15:14):

Would CapabilityStatement.resource be a reasonable place to indicate something about the normative vs. non-normative status of a resource implementation?

view this post on Zulip David Hay (Sep 28 2017 at 18:02):

Some notes here: https://www.hl7.org/fhir/versions.html

view this post on Zulip Lloyd McKenzie (Sep 28 2017 at 19:06):

CapabilityStatement lets you indicate the version of FHIR you support - which in turn tells you which resources are Normative and should have the normative compatibility rules applied.

view this post on Zulip Aaron Seib (Sep 28 2017 at 19:11):

I think that it would make sense to indicate this in the CapabilityStatement.resource - curious if there are any who would disagree.

view this post on Zulip Kevin Olbrich (Sep 28 2017 at 20:04):

@Ewout Kramer We took the accept header approach because we need to be able to integrate with multiple partners with dissimilar FHIR versions and maintaining a separate url endpoint (and possibly servers) struck us as a maintenance nightmare. We also liked the accept header approach because it makes more semantic sense to us for the URL of the resource to define where to find the information and the details of the serialization format and fhir version are about how to transmit that data. Internallly we handle all our objects as domain models and serialize/deserialize them to/from the requested FHIR version as necessary, and we have built some code generation tools that can abstract away a lot of the implementation details. This article is an interesting read on the subject... https://www.troyhunt.com/your-api-versioning-is-wrong-which-is/. Another benefit of this approach is that a client can upgrade their version at any time and so long as they request a FHIR version our server supports they can just use the existing url they may have stored and they can expect to get the resource back without having to munge their data.

view this post on Zulip Chris Grenz (Sep 28 2017 at 20:08):

For those interested: https://www.linkedin.com/pulse/fhir-nuts-bolts-versioning-chris-grenz/

view this post on Zulip Cooper Thompson (Sep 28 2017 at 20:26):

I'm also very interested in the topic of versioning the API for backwards compatibility within a single FHIR version.

Maybe the terminology is:

  • fhir-spec-version (e.g. 1.0.2)
  • fhir-patch-version (i.e. what set of patches you have for Epic's implementation of 1.0.2)
  • fhir-resource-version (the vread/vid in the RESTful API. I just list list this for completeness - this is well understood I think)

My specific concern how to not break all of the connected clients we have when we roll out a bug fix (for example, when we fix a bug in our implementation of FHIR 1.0.2). I had also thought about using an HTTP header so the client could tell us what fhir-patch-version they want (i.e. what set of bug fixes they want us to apply when we render the resource we send back to them).

I'm sure Epic is the only FHIR server implementation that will have any bugs though, so maybe it's not applicable to the general community :).

Our problem is that operationally, if our server has a bug, often the clients that connect to us will implement a workaround. If that client is connecting to our FHIR server at two different sites, they would have that workaround applied to both sites. When we roll out a bug fix, one site may get it before the other side, so the client would need to remove the workaround for just the one site, but not the other. This seems ok for 2 sites, but once we are at 300+ sites it won't be realistic for clients to migrate away from the workaround one site at a time.

Add to this that a client may be connecting to Cerner and Epic servers, having a common way to specify the patch-level they want would be cool.

view this post on Zulip Kevin Olbrich (Sep 28 2017 at 20:32):

@Cooper Thompson couldn't the CapabilityStatement.software.version be used to determine if a workaround should be used with a specific server?

view this post on Zulip David Teirney (Sep 28 2017 at 21:04):

We're using the FHIR version within the server root path, e.g. https://fhir.example.org/fhir/0.5/Patient or https://fhir.example.org/fhir/1.0/Patient. Not all our resources support both versions so our clients are either using the 0.5 or 1.0 collection of resources (eventually 2.0). Conveniently this means it's straightforward (well sort of) to get the Conformance statement for the supported resources for each version.

Discretely versioning each resource is surely tricky because there are references returned to other resource locations in many parts of the data model, which are supposed to be relative to the server root of the FHIR server.

We haven't had too many problems with breaking backwards compatibility since so much of FHIR is optional anyway and extensions use "name/value" semantics. So, clients need to know how to deal with content that isn't there. Most of the issues we've had so far with changes is making sure that clients understand the quirks of standard FHIR responses, e.g. OperationOutcome resources can be mixed in with the expected resource type requested (so you have to check the resource type before trying to parse it), or that the Bundle won't have an empty array it will just not be there if the total is 0.

Having said all this, we use Accept header versioning for all our other non-FHIR APIs.

view this post on Zulip Joel Schneider (Sep 28 2017 at 22:01):

CapabilityStatement lets you indicate the version of FHIR you support - which in turn tells you which resources are Normative and should have the normative compatibility rules applied.

It's encouraging to understand that CapabilityStatement.fhirVersion will enable safe client/server interactions using normative resources.

Presumably the FHIR implementation offered by any stable/production FHIR endpoint (base url) should never change in a way that breaks backward compatibility, because doing that could be dangerous, and would be very unfriendly to existing clients.

view this post on Zulip Lloyd McKenzie (Sep 29 2017 at 02:28):

Yeah, versioning definitely needs to be handled at the API level, not the resource level. @Aaron Seib Are you arguing for including the normative status in the CapabilityStatement? That wouldn't make a whole lot of sense because the CapabilityStatements don't get to decide whether something is normative or not - that's HL7's call. All the CapabilityStatement can do is declare what version of FHIR overall is supported by that endpoint.

view this post on Zulip Chris Grenz (Sep 29 2017 at 13:20):

I disagree that versioning "definitely needs to be handled at the API level, not the resource level." The API must be versioned at the API level, but a stream of resources could be a mix of versions. In many systems, the stream will be a mix. Any one resource must be a single version (although I could envision a Bundle with a mix in some limited use cases).

view this post on Zulip Chris Grenz (Sep 29 2017 at 13:22):

Systems (e.g. integration engines) that include mappings between versions could be perfectly happy with a mix of post-normative versions.

view this post on Zulip Lloyd McKenzie (Sep 29 2017 at 15:12):

Each instance must be a single version - and the references in those instances need to resolve to the same version if they're resolvable. If you do funky things with headers, you can send different types of instances to the same URL, but you're essentially establishing distinct "virtual" endpoints via your headers.

view this post on Zulip Chris Grenz (Sep 29 2017 at 15:59):

Agree with the caveat that I think it would be OK for an R5 Observation (normative) to reference an R4 Patient (normative). If we distinguish between normative versions in these situations, interop is very much hindered.

view this post on Zulip Lloyd McKenzie (Sep 29 2017 at 19:01):

In an instance, an R5 Observation would need to reference an R5-compliant patient. It's just easy to do that if patient is normative.

view this post on Zulip Jonathan Shultlis (Sep 29 2017 at 23:43):

We have a server that has been in a pilot for over a year, and need to carry forward AuditEvent and other data across FHIR versions. We cannot (must not) migrate the old records. We can easily write code that can deal with multiple FHIR versions, but to do that we need an efficient way to determine what version a resource is. We're currently using a meta.tag for that, that gets parsed out and stored in the AuditEvent table for easy access to choose what FHIR version parser to use.

view this post on Zulip Ewout Kramer (Oct 02 2017 at 15:24):

@Ewout Kramer We took the accept header approach (...) This article is an interesting read on the subject... https://www.troyhunt.com/your-api-versioning-is-wrong-which-is/.

Thanks @Kevin Olbrich, interesting read....

view this post on Zulip Ewout Kramer (Oct 02 2017 at 15:31):

"Support all three wrong ways" ;-) Makes me think of our current Accept/_format couple...

view this post on Zulip Grahame Grieve (Oct 03 2017 at 02:28):

so we talked about this in San Deigo, and agreed that in new Orleans we'll do a connctathon stream around using application/fhir.[version] to evaluate how that goes. In the meantime, anyone can version their APIs by putting the version in the URL itself - that will work whatever. But it does confuse identity and reference.

As for merging version in a stream (or a bundle!) ... it's sort of logical, but there's some unresolvable pitfalls around moving content between resources between versions, etc. So I think that for the next version, and in regard to previous versions, we'll just put our hands over our ears and pretend we don't have to think about that. But that won't fly in the R4/R5 land

view this post on Zulip Abbie Watson (Oct 10 2017 at 22:25):

Is there a standard way to version FHIR REST interfaces? (e.g. https://host/{FHIR-VERSION}/{API-VERSION}/Patient/1 )

The Touchstone project recommendation is to use the fhirVersion in the URL path base.
We've been doing the following in our Node apps:

JsonRoutes.add("put", "/" + fhirVersion + "/Patient/:id", function (req, res, next) { ... }

Where fhirVersion is one of the following versions:
https://www.hl7.org/fhir/directory.html

We've been getting quite successful interoperability with the Touchstone conformance tests doing so.

ps. The 'versionless' ideal that people have seems to suggest a slight misunderstanding of the DICOM standard (which is not versionless, contrary to popular talking points).

view this post on Zulip Adrian Lanzafame (Oct 19 2017 at 07:20):

if the version isn't specified in the URL, how do I figure out what version of an external Reference I am meant to request from the external server? I understand that this confuses identify and reference but how would I go about separating those concepts in the scenario?

view this post on Zulip Lloyd McKenzie (Oct 19 2017 at 13:30):

The CapabilityStatement for the server endpoint will declare what version it supports

view this post on Zulip Grahame Grieve (Oct 22 2017 at 22:51):

I am getting around to specifying the X-version API track for the new Orleans connectathon.

view this post on Zulip Grahame Grieve (Oct 22 2017 at 22:51):

It seems to me that given where we are, there needs to be a single simple call that a client can make of a server: "what versions do you support"

view this post on Zulip Grahame Grieve (Oct 22 2017 at 22:52):

retrieving a full conformance statement has proven slow in practice, and then we renamed it - both of those were annoying but manageable. But if the first question you have for a server is now 'what versions can you be?' then we need some new API.

view this post on Zulip Grahame Grieve (Oct 23 2017 at 02:14):

Connectation Proposal: http://wiki.hl7.org/index.php?title=201801_Versioned_API

comments welcome - I'm not sure how far to push scenario #4. In a few days my server will start supporting scenario#1

view this post on Zulip Grahame Grieve (Oct 23 2017 at 02:14):

with regard to the connectathon details:

view this post on Zulip Grahame Grieve (Oct 23 2017 at 02:15):

in San Diego we (ITS and FHIR-I) agreed that we would use application/fhir.r3+xml|json to differentiate between FHIR versions on a version-independent interface

view this post on Zulip Grahame Grieve (Oct 23 2017 at 02:16):

but when I presented this to the Australian connectathon last week, there was a strong preference for a parameter: application/fhir+xml|json; fhir-version=r3

view this post on Zulip Grahame Grieve (Oct 23 2017 at 02:17):

then, when I implemented, I discovered that there was a variety of mime types across my implementation that needed the same treatment (e.g., at a minimum, for turtle and nd-json). And the only way to do it consistently was with a mime type parameter

view this post on Zulip Grahame Grieve (Oct 23 2017 at 02:17):

hence I have proposed that instead

view this post on Zulip Jens Villadsen (Oct 23 2017 at 06:49):

I see at mix of #2 and #3 from https://www.troyhunt.com/your-api-versioning-is-wrong-which-is/ #2 in the proposal.

view this post on Zulip Grahame Grieve (Oct 23 2017 at 06:49):

yes. that's right. a mix

view this post on Zulip Ewout Kramer (Oct 30 2017 at 16:29):

I'm just wondering whether even calling $version makes too much assumptions, by using FHIR to ask something about FHIR. Would OPTIONS work as well (without breaking CORS this time)

view this post on Zulip Grahame Grieve (Oct 30 2017 at 19:24):

how would that work?

view this post on Zulip Ewout Kramer (Oct 30 2017 at 20:25):

Thought about returning an OPTIONS with an Accept header including the accepted formats + versions

view this post on Zulip Grahame Grieve (Oct 30 2017 at 20:27):

I can't find anyone else using it like this?

view this post on Zulip Ewout Kramer (Oct 30 2017 at 20:29):

Indeed. To quote a random Google search I did about this: "As RESTful Web Services puts it, “OPTIONS is a promising idea that nobody uses.”"

view this post on Zulip Grahame Grieve (Oct 30 2017 at 20:29):

except CORS.... which makes it difficult for anyone other use, in my view

view this post on Zulip Grahame Grieve (Oct 31 2017 at 01:09):

the simplified json representation was intended to jump us around the versioning issues


Last updated: Apr 12 2022 at 19:14 UTC