Manipulating a single FHIR Patient Resource
October 16, 2013 11 Comments
Following on from the previous post about REST in general, let’s dig in a bit more and start manipulating a single resource in FHIR. We’ll read an existing resource, update it and create a new one.
First task is to set up the tools we’re going to need to experiment. There are at least 2 sets of tools you’ll need to do this properly:
- Something to send and receive HTTP requests. This will to allow you to specify the content, the HTTP method and request headers, and also to view the response headers, Status Code and any response body that the server returns. (refer to my previous post if these terms are new to you)
- Something to create and view XML and JSON resources. You might also want to download the FHIR schema files from the spec (look for the link that says ‘FHIR Schema & Schematrons).
Depending on your environment, there are many options for both of these. To keep thing simple I’m going to use a chrome browser extension (Postman) for making the HTTP requests, and the Oxygen XML editor for the XML/JSON stuff, but you choose what works for you. I’m going to assume that you know how to use these tools – or are at least willing to find out!
Reading an existing resource
Before we start – an important message about the ‘@’ symbol. Currently, the FHIR specification uses the ‘@’ symbol in a URI to make it clear which part of the URI is the ID for the resource. This is going to change in the next version of the spec, and it will be removed, however it might take some time for the test servers to be modified. If you get weird errors when trying the instructions below, then remove the ‘@’ and see if that helps.
To read an existing resource when you know its URI (i.e. the server location and ID on that server) you use an HTTP GET request. I’m using Grahames’ server for this example which is a public server that anyone can change, so the details may be different for you.
Here’s what I got using Postman to retrieve the Patient resource with an ID of 2:
Note that:
- The full URI to that resource on Grahams’ server is http://hl7connect.healthintersections.com.au/svc/fhir/Patient/@2
- I asked the server to return the resource in the XML format, by setting a request header – Accept – to ‘application/xml+fhir. I could have set the Accept header to ‘application/json+fhir to get a JSON formatted resource – try it! Here is a bit more on these mime-types.
- The Status Code was 200 – which means that everything worked OK.
In Postman, I can also look at the response headers – which the server sets – as shown below:
Notes:
- The Content-Location header has the value http://hl7connect.healthintersections.com.au/svc/fhir/patient/@2/history/@2 . This is a ‘version specific’ URI – it specifies not only the resource Id, but also the specific version of this resource – in this case it’s the second version.
- The content-type header tells us that this is an XML format.
- There are a number of other useful headers that we won’t go into right now.
Updating a resource
Lets update this resource. What we’ll do is to copy the resource we just retrieved into our XML editor, make some changes, paste them back into Postman and PUT them to the server. Optionally, we’ll validate the updated resource using the FHIR schema before we send it to the server.
Step 1: Copy the resource you just downloaded
Step 2: Paste the resource into your XML editor
Step 3: Change the file – for example you could add a new name just after the existing name, like so:
... <!-- Original Name --> <name> <use value="official"/> <family value="SASHA"/> <given value="BOJICIC"/> </name> <!-- New Name --> <name> <use value="usual"/> <family value="As"/> <given value="Otherwise known"/> </name> ...
If you want to, you can check that this is valid against the FHIR schema by associating the updated file with the correct XML schema (it will be Patient.xsd in whatever folder you downloaded the schema to) and clicking the ‘validate’ button in your editor.
Step 4: Copy the changed resource
Step 5: In Postman, change the GET to a PUT and paste the updated resource into the body of the request (the raw tab is the best)
Step 6: press the Send button.
All going well, the server should accept the changed resource, and return a response with a status code of 200. The Content-Location header should show that the version has been incremented. Here’s what I got:
Notes:
- The spec does not require that version numbers are sequential ones – although Grahames server does do this. Others (like Ewouts) use a different scheme – all that matters is that a new version of a resource gets a new version number.
- We used PUT and not POST because we knew the full URI (including the resource ID). POST would have indicated that we wanted to create a new resource – as we’ll do in a minute.
- If you PUT to a URI, and there is no existing resource at that URI then it will still be saved, but the status code that is returned will be 201 rather than 200.
- At the moment, when you update (or create) a resource, then the FHIR server will return the resource it saved. This behaviour will be changed to be more consistent with the HTTP spec in the next FHIR version, and the resource will no longer be returned.
And before we move off the topic of updates – and versions:
- You can always retrieve a specific version of a resource using the version specific URI that was returned when the resource was updated – eg http://hl7connect.healthintersections.com.au/svc/fhir/patient/@2/history/@3
- You can get a list of all the versions that exist for a resource (if any) by appending the term ‘history’ to the URI of the resource – eg http://hl7connect.healthintersections.com.au/svc/fhir/patient/@2/history
- (Note that this will return a list of resources in a bundle – I’ll cover bundles in the next post when I discuss searching)
Creating new resource
So, that’s getting an existing resource and updating it – what about creating an entirely new one? Well that’s easy – and you can do it right now. All you have to do is:
- Use the POST method instead of the PUT method
- Send the request to the root for that resource on the server – e.g. http://hl7connect.healthintersections.com.au/svc/fhir/Patient in the case of Grahames’ server – rather than to a URI (after all, you don’t know what ID the server is going to assign to the new resource yet).
All you have to do is to change the URL in POSTMan (get rid of the /@2 at the end of the line), change the method to POST and press <Send>.
The server will process the request and return a response. This time the status code will be 201 – indicating a new resource was created. The actual URI for the resource will be in the Content-Location header (and it will, of course, be a version specific URI).
How hard is that?
A question that came up from the previous REST post was about who creates the resource ID’s. In particular, can a client create the ID rather than the server?
It is certainly possible for the client to assign the ID – in FHIR, if a client PUT’s a resource to a URI (i.e. includes the ID) and there is no resource already there, then the server will create the resource using that ID (it returns a 201 status to indicate that this has happened). The issue with this of course is in potential ID collisions – what prevents 2 clients using the same ID for different resources?
However, FHIR takes the view that this is a deployment decision, and is up to the implementers and trading partners using the server. They could insist on GUID’s as the IDs for example.
Do play around with reading, creating and updating Patient resources. You can try creating entirely new resources in your editor (and don’t forget to use the schema validation so you know you have a valid resource). Read the documentation for the Patient resource to find out what properties you can add, and don’t forget to look at the examples that are in the spec (in a tab at the top of the page).
The next post in this series will start to explore the topic of searching – how do you find a resource when you don’t know its URI – and where we’ll be introduced to a new construct – the resource bundle.
Cheers…
How does concurrency control work under FHIR? That is, when putting an update to the server, how can the client be sure that there hasn’t been an intervening update. Perhaps there’s some recommended optimistic locking protocol …
The following is stated by the spec in the section on updates (http://www.hl7.org/implement/standards/fhir/http.html#update):
In particular, servers may choose to implement version-aware updates, where the only updates that are accepted quote the current version of the resource. In this case, the client must submit the currently correct version specific URL in the Content-Location in the PUT request. If the value is missing, the server SHALL return a 412 Preconditions failed response. Clients SHOULD submit a proper Content-Location header and SHALL correctly understand a 409 response as an update conflict.
At this time this can’t be specified in either conformance or profile resource- though maybe it should be…
cheers…
I’ve added a row to the ballot tracking log. (Appropriate place would be Conformance, as that’s where server behavior is captured.)
Thanks Lloyd…
You couldn’t also use an etag in the header for optimistic locking? – a common RESTful approach.
Interesting thought. I recall a number of conversations in the early days about etags, and the spec currently states “The Version Id is represented by the full canonical URL in the content-location header (see vread below). The Version Id may also be represented in the http ETag, but the use of ETag is not needed by this specification” (search for etag in this page: http://www.hl7.org/implement/standards/fhir/http.html and you’ll find it).
So this suggests that the etag might also be used, although the decision was made to go with the Content-Location. My guess is that it’s one of those things that could be re-addressed once people start implementing FHIR, and trying these things out in the wild…
Pingback: FHIR searching | Hay on FHIR
Pingback: FHIR: A question of identity | Hay on FHIR
Pingback: Creating examples in FHIR | Hay on FHIR
Pingback: A REST primer – FHIR style – part 1. | Hay on FHIR
Pingback: Finding Patients seen by clinicians | Hay on FHIR