Stream: implementers
Topic: Bundle processing PUTs?
John Silva (Jul 30 2019 at 18:08):
Trying to understand what is supposed to happen with FHIR bundle transactions with request.method="PUT" (https://www.hl7.org/fhir/http.html#transaction)
If a client has, for example, a Lab value and is going to add this to a bundle along with the Patient resource, what should be used for the request values. In other words, if my client doesn't necessarily know if the previous (e.g. prelim) verison of this Lab has been sent to the server or not should it use request.method="PUT" and then should it encode both
request.ifNoneExist=Observataion?Identifier=<labId> and
request.ifMatch=Observation?Identifier=<labid>
or does the client need to put the resource in the bundle twice, once with the request.method="POST" and another with request.method="PUT"
(I can't 'read between the lines' in the batch processing page to understand what should or shouldn't be done in this case.)
A related question, should a FHIR server support both ifNoneExist and ifMatch for the request.method="PUT" or is this defined anywhere?
Lloyd McKenzie (Jul 30 2019 at 18:26):
It's totally fine to have both a PUT and a POST for the same thing with ifMatch for the PUT and ifNoneExist for the POST. ifNoneExist would be odd to use for a PUT
Paul Church (Jul 30 2019 at 18:27):
I think you want conditional update for this case: PUT Observation?Identifier=<labid>. In a bundle, request.method="PUT" and request.url="Observation?Identifier=<labid>". If the resource isn't found, it will be created.
Paul Church (Jul 30 2019 at 18:28):
If-Match is specific to ETags to manage version contention, I don't think you can specify search parameters.
John Silva (Jul 30 2019 at 20:45):
@Lloyd McKenzie -- ok, but that would mean the FHIR client would have to have 2 entries for the same resource, one with POST and the other with PUT. Also, this doesn't seem to be documented anywhere -- just your comments (or suggestions) -- how is an implementer supposed to know how to deal with this? Also, it is 'legal' or not for the PUT request to have both ifMatch and ifNoneExist? The ifMatch would be used for the update whereas the ifNoneExist would be used for conditional create? (or am I completely missing the intention of how batch processing is supposed to work?)
Lloyd McKenzie (Jul 30 2019 at 21:08):
ifMatch and ifNoneExist on the same thing I think would be 'anded' - so probably not the behavior you want. I'm not sure if the approach of submit twice - once as an add and once as an update has been documented. I'm also not totally sure how references would behave in that case as I think the ids need to be unique - but the references would need to point to "whichever is successful". @Grahame Grieve ?
Grahame Grieve (Jul 30 2019 at 21:09):
We're running up against the limits of a transaction. I don't think it's possible
John Silva (Jul 30 2019 at 21:44):
So does this mean that this use case is NOT supported? How is a FHIR client supposed to know if a FHIR server has a Obs (or any resource) already -- is the expectation that the FHIR client has to perform queries in order to determine how to construct a bundle? That seems very inefficient (and problematic -- what if a resource was posted in between the time of the query and the posting of the bundle -- that's why the bundle is done transactionally -- to protect from this.)
How do other deal with this? I can't believe we're the first to have this use case or question about bundle transaction processing?
Paul Church (Jul 30 2019 at 21:46):
What's wrong with conditional update? It does exactly the "update if it exists, create if not" in a single operation. Works the same in or out of a bundle.
re: the interaction of if-match and if-none-exist - PUT doesn't allow if-none-exist; that's only allowed on POST. There is no operation that allows both if-match and if-none-exist, as per http://hl7.org/fhir/http.html#summary
John Silva (Jul 30 2019 at 21:51):
@Paul Church -- yes, I want to do a 'conditional update' but with the logic 'inside' of the bundle transaction. The 'conditional update' seems to be an HTTP header on the POST (and experimental or TU according to this page: https://www.hl7.org/fhir/http.html#ccreate )
Paul Church (Jul 30 2019 at 22:10):
My interpretation of bundle handling is that if request.url is "Observation?search-conditions" it triggers conditional update in the transaction. There is a crucible conformance test case for this, XFER2. Conditional update is not based on an http header: https://www.hl7.org/fhir/http.html#cond-update
It's true that it's experimental and I don't know whether there's an answer exclusively in terms of normative functionality.
Lloyd McKenzie (Jul 31 2019 at 02:31):
You can't do both a create and a conditional update - so there's no way to say "create this if it doesn't exist, update it if it does". You could use a PUT to do a create, but lots of servers won't support that.
Lloyd McKenzie (Jul 31 2019 at 02:32):
More specifically, if you do both a create and a conditional update (and have them set up so that only one occurs), your challenge is that if you have references to that newly updated/created thing, there's no way to have the reference point to "whichever one succeeded"
Paul Church (Jul 31 2019 at 03:29):
A conditional update that finds no matches and is not provided with an id is treated as a create (a proper create, not an upsert). This is how you say "create this if it doesn't exist, update it if it does". The spec anticipates this exact situation.
I was thinking about how to accomplish this without conditional update. The batch/transaction rules prohibit interdependencies within the bundle so there shouldn't be any legal two-operation solution. I think the only way is if the client generates a resource ID based on its own identifier scheme and the server allows upsert. Then you can PUT to that location and it will work either way, with no difficulty in resolving references.
Lloyd McKenzie (Jul 31 2019 at 04:32):
Transaction doesn't prohibit dependencies
Lloyd McKenzie (Jul 31 2019 at 04:33):
The challenge with the PUT approach is lots of servers don't allow clients to determine resource ids. If a server does, you're golden. If not, you have a problem.
Alexander Kiel (Jul 31 2019 at 06:18):
One issue I see with FHIR conditional update is, that in case the resource already exists, you will just override it with your version, loosing any previous state. So if you don't know wether the resource exists on the server, you also don't know it's state, if it exists.
The use case I can see here, is a client which is the only source for resources in question but doesn't keep track of whether is has already put the resource into the FHIR server in question. Say a lab system which likes to put it's observations into a central FHIR server. @John Silva Is your use case like this?
John Silva (Jul 31 2019 at 09:51):
@Lloyd McKenzie - we have actually implemented client-specified id's since one of our FHIR clients needed it. So, since we have then our FHIR Clients should be able to use the PUT (with ifMatch or ifNoneExist - still not clear on this) to do either a create (with client'specd id) ot update if the resource exists (based on ifMatch).
@Alexander Kiel - yes, our use case is that a Lab server is sending HL7 V2 messages and we have an interface engine that operates 'statelessly' (i.e. V2 msg in/map/FHIR out) so it doesn't know if the same Lab result has been sent previously, e.g. prelim result then final or final then corrected. The good thing is that this doesn't typically happen with high-frequency monitoring-type (device) data that is only sent once; typically only human-entered data on a Lab system or EMR where it can be updated/corrected.
Alexander Kiel (Jul 31 2019 at 10:19):
@John Silva The interface engine then sends the mapped FHIR resources to a FHIR server for storage?
John Silva (Jul 31 2019 at 11:41):
@Alexander Kiel - yes, V2 --> map V2 segs to FHIR resources in bundle -> store in FHIR server (I would expect that this is a common pattern for anyone dealing with HL7 V2 "legacy" systems)
Alexander Kiel (Jul 31 2019 at 11:46):
@John Silva Ok understand. But if you interface engine has no state than you also don't have any versionId vor the IfMatch header. So with client Id's you you'd use a PUT without any headers and it will create-or-update (upsert) or you can use FHIR conditional update with search parameters and also no headers. What is the reason you want to use headers like IfMatch or IfNoneExists?
Last updated: Apr 12 2022 at 19:14 UTC