Reading & Development: 2 hours
Quick Intro
The My Health Record system is built around the concept of clinical documents. There are approximately 15 different clinical document types that the My Health Record currently allows. For more information about these clinical documents and their purpose see here.
In the previous guides we have only retrieved data from 2 clinical documents; the Personal Health Summary and the Shared Health Summary. This guide will look at retrieving all clinical document data (including these 2, but excluding MBS documents). MBS and PBS items will be covered in the next guide.
More Information
As per My Health Record system policy, Medicare/DVA Benefits Report (TypeCode: 100.16644 & ClassCode: 100.16644) documents are not available for download. Correspondingly, the Search Document List API does not include documents of this type in the list of returned document references.
In this guide, we will look two APIs classified under this group:
1. Search Document List (GET)
2. Get Document (GET)
Step 1: Search Document List (GET)
We begin by retrieving a list of the clinical documents available in the consumer’s My health Record. This API provides the ability to retrieve the list of document references for the individual. The API returns a bundle of DocumentReference by matching a class or type of document provided as input.
Familiarise yourself with the API specifics below and you may also want to read Section 3.4.2 of the API Specification (3 pages).
More Information
You can view the lists the class code and type code as supported by the My Health Record system from the API Specification in Appendix Common A5.
Resource URI | [fqdn/fhir/v2.0.0]/DocumentReference |
HTTP Method | GET (read) |
Request Headers | Authorization (OAuth Token), App-Id, App-Version, Platform-Version (optional) |
Request Parameters (searchParam) | Required Request Parameters patient - Logical identifier of the patient. (1..1) class - This code is to identify the type of the document. (0..*). The request message should be formed with the class = ClassCode^^CodingSystem type – Another option for identifying the type of document. The request message should formed with the type = TypeCode^^CodingSystem e.g.: “100.16644^^NCTIS” Note: either ‘class’ or ‘type’ is required in each DocumentReference request. Optional Request Parameters identifier - Master Version Specific Identifier created - to date (yyyy-mm-dd) prefix with “le” e.g. le2016-05-20 (Cardinality: 0..1) status - current (approved)| superseded (deprecated)| entered-in-error (deleted) _format - The suggested values are application/xml+fhir (to represent it as XML) OR application/json+fhir |
FHIR based resource reference | http://hl7.org/fhir/2016May/documentreference.html |
In the next few steps, we will design a modify our UI and add the code-behind logic to retrieve the patient document List.
Step 2: Add a new UI page
1. Create a new content page called GenericDocumentServicesPage.xaml.
2. Add the following UI code between <ContentPage.Content> tags inside the GenericDocumentServicesPage.xaml file.
<StackLayout>
<Label Text="Generic Document Services" Margin="0, 20, 0, 20" Style="{StaticResource PageHeader}"
VerticalOptions="Start"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"/>
<BoxView HorizontalOptions="FillAndExpand" HeightRequest="1" Color="#222222" Margin="0, 0, 0, 20"/>
<Button Margin="0,10,0,0" Text="Search Document List" HorizontalOptions="Center"
x:Name="searchDocumentsList"
Clicked="searchDocuments_Clicked"
BackgroundColor="{StaticResource Primary}"
TextColor="White" />
</StackLayout>
3. Add this new page into the Flyout Menu bar using the following code inside the AppShell.xaml file.
<ShellContent Title="Generic Document Services List" Route="GenericDocumentServicesPage" ContentTemplate="{DataTemplate local:GenericDocumentServicesPage}" />
Step 3: Document List code changes
1. Add a new method inside the IMhrFhirService interface
Task<IRestResponse> SearchDocumentList(string id);
2. Add an implementation method as per code below inside the MhrFhirService class. We have passed the class parameter as “60591-5^^LOINC” which represents a Shared Health Summary.
public async Task<IRestResponse> SearchDocumentList(string id)
{
RestRequest request = new RestRequest("DocumentReference", Method.GET);
request.AddParameter("patient", id);
string documentTypeClass = "60591-5^^LOINC"; // Shared Health Summary
request.AddParameter("class", documentTypeClass);
// or
//request.AddParameter("type", "type");
// optional parameters
string fromDate = "2000-01-01";
string toDate = "2020-12-31";
request.AddParameter("created", "ge" + fromDate);
request.AddParameter("created", "le" + toDate);
//request.AddParameter("identifier", "");
//request.AddParameter("author", "");
//request.AddParameter("identifier", "");
//request.AddParameter("status", "");
//request.AddParameter("slotName", "");
//request.AddParameter("slotValue", "");
//request.AddParameter("_format", "application/json+fhir");
// This method was already added in previous guide to add request headers such as authorization, app id, app version.
await AddStandardHeaders(request);
IRestResponse fhirApiResponse = await _httpClient.ExecuteAsync(request);
return fhirApiResponse;
}
3. Add the following method on the Get Document List button click event inside the partial class GenericDocumentServicesPage.xaml.cs.
private async void searchDocuments_Clicked(object sender, EventArgs e)
{
IMhrFhirService mhrFhirService = DependencyService.Get<MhrFhirService>();
string patientId = "8666701594";
IRestResponse fhirMhrApiResponse = await mhrFhirService.SearchDocumentList(patientId);
if (fhirMhrApiResponse.StatusCode == HttpStatusCode.OK)
{
string json = fhirMhrApiResponse.Content;
}
else
{
string errorDesc = fhirMhrApiResponse.StatusDescription;
}
}
4 .Run the application and test the search document list functionality. You should also test values for class and type.
The following JSON is returned from the Search Document List API response, where id is the document identifier and is used to retrieve the document.
"HTTP":"OK"{
"resourceType":"Bundle",
"id":"2.25.139963090649856566513851356817625345709",
"type":"searchset",
"total":1,
"entry":[
{
"fullUrl":"https://apinams.svt.gw.myhealthrecord.gov.au/fhir/v2.0.0/DocumentReference/48f9c8a4-525f-430a-9aea-8a844c6a6e84",
"resource":{
"resourceType":"DocumentReference",
"id":"48f9c8a4-525f-430a-9aea-8a844c6a6e84",
"contained":[
{
"resourceType":"Practitioner",
"id":"62fffc5a-3386-49c6-9a1d-8fce1849e12a",
"identifier":[
{
"type":{
"coding":[
{
"system":"http://hl7.org/fhir/v2/0203",
"code":"NPI",
"display":"National provider identifier"
}
],
"text":"HPI-I"
},
"system":"http://ns.electronichealth.net.au/id/hi/hpii/1.0",
"value":"8003611566667220"
}
],
"name":[
{
"family":[
"Environment"
],
"given":[
"Good"
],
"prefix":[
"Dr."
]
}
],
"practitionerRole":[
{
"specialty":[
{
"text":"Intensive Care Specialist"
}
]
}
]
},
{
"resourceType":"Organization",
"id":"328b511a-c9c8-4859-90e0-d3f6c5804e33",
"identifier":[
{
"type":{
"coding":[
{
"system":"http://hl7.org/fhir/v2/0203",
"code":"NOI",
"display":"National Organization Identifier"
}
]
},
"system":"http://ns.electronichealth.net.au/id/hi/hpio/1.0",
"value":"8003628233352432"
}
],
"name":"Test Health Service 696"
}
],
"masterIdentifier":{
"system":"urn:ietf:rfc:3986",
"value":"urn:oid:1.3.16.1.38818.18446744073688372048.20200624043147715"
},
"identifier":[
{
"system":"urn:ietf:rfc:4122",
"value":"urn:uuid:48f9c8a4-525f-430a-9aea-8a844c6a6e84"
}
],
"subject":{
"reference":"Patient/2054814551"
},
"type":{
"coding":[
{
"system":"http://loinc.org",
"code":"60591-5",
"display":"Shared Health Summary"
}
]
},
"class":{
"coding":[
{
"system":"http://loinc.org",
"code":"60591-5",
"display":"Shared Health Summary"
}
]
},
"author":[
{
"reference":"#62fffc5a-3386-49c6-9a1d-8fce1849e12a"
},
{
"reference":"#328b511a-c9c8-4859-90e0-d3f6c5804e33"
}
],
"created":"2020-03-24T18:30:03Z",
"indexed":"2020-03-24T18:30:03.000Z",
"status":"current",
"docStatus":{
"coding":[
{
"system":"http://hl7.org/fhir/composition-status",
"code":"final",
"display":"Final"
}
]
},
"description":"Sample1_SHS",
"content":[
{
"attachment":{
"contentType":"application/zip",
"language":"en-AU",
"url":"https://apinams.svt.gw.myhealthrecord.gov.au/fhir/v2.0.0/Binary/1.3.16.1.38818.18446744073688372048.20200624043147715",
"size":10520,
"hash":"214c62b9e1acd52b49b83c415bb97e5ef39f4dfc",
"title":"Shared Health Summary"
},
"format":[
{
"system":"urn:ietf:rfc:3986",
"code":"urn:oid:1.2.36.1.2001.1006.1.16565.3",
"display":"Shared Health Summary - Conformance 3A"
}
]
}
],
"context":{
"period":{
"start":"2020-03-24T18:30:03Z",
"end":"2020-03-24T18:30:03Z"
},
"facilityType":{
"coding":[
{
"system":"http://www.abs.gov.au/ausstats/[email protected]/mf/1292.0",
"code":"8511",
"display":"General Practice"
}
]
},
"practiceSetting":{
"coding":[
{
"system":"http://www.abs.gov.au/ausstats/[email protected]/mf/1292.0",
"code":"8511-3",
"display":"General practice medical clinic service"
}
]
}
}
},
"search":{
"mode":"match"
}
}
]
}
Step 4: Get Document (GET)
Once you have access to the DocumentReference bundle you will be able to request specific clinical documents. Th Get Document API provides the ability to retrieve a specific document for an individual from the My Health Record system.
The API returns a base64binary of the CDA zip package as per the FHIR® specification.
Familiarise yourself with the API details listed below.
Resource URI | [fqdn/fhir/v2.0.0]/Binary/[docID] |
HTTP Method | GET (read) |
Request Headers | Authorization (OAuth Token), App-Id, App-Version, Platform-Version (optional) |
Request Parameters (searchParam) | patient - Logical identifier of the patient. (1..1) |
FHIR based resource reference | |
Response | The system will return ‘Binary’. The binary response which is formatted as Base64Binary has an imposed upper limit of 7340032 Bytes (7 MB). A response exceeding this size limit will result in an error message being thrown |
In the next few steps we will modify our UI and add the code-behind logic to retrieve the patient document binary.
1. Add a button called Get Document underneath the Get Document List button inside the GenericDocumentServicesPage.XAML file.
<Button Margin="0,10,0,0" Text="Get Document" HorizontalOptions="Center"
x:Name="getDocument"
Clicked="getDocument_Clicked"
BackgroundColor="{StaticResource Primary}"
TextColor="White" />
2. Add a new method inside the IMhrFhirService interface.
Task<IRestResponse> GetDocument(string id, string documentId);
3. Add an implementation method as per code below inside the MhrFhirService class created in previous guides.
public async Task<IRestResponse> GetDocument(string id, string documentId)
{
RestRequest request = new RestRequest("Binary/{id}/", Method.GET);
request.AddUrlSegment("id", documentId);
request.AddParameter("patient", id);
// This method was already added in previous guide to add request headers such as authorization, app id, app version.
await AddStandardHeaders(request);
IRestResponse fhirApiResponse = await _httpClient.ExecuteAsync(request);
return fhirApiResponse;
}
4. Add the following method on Get Document button click event added in previous step inside the partial class GenericDocumentServicesPage.xaml.cs
private async void getDocument_Clicked(object sender, EventArgs e)
{
IMhrFhirService mhrFhirService = DependencyService.Get<MhrFhirService>();
string patientId = " 2054814551";
string documentId = " 1.3.16.1.38818.18446744073688372048.20200624043147715";
IRestResponse fhirMhrApiResponse = await mhrFhirService.GetDocument(patientId, documentId);
if (fhirMhrApiResponse.StatusCode == HttpStatusCode.OK)
{
byte[] bytes = fhirMhrApiResponse.RawBytes;
}
else
{
//string errorDesc = fhirMhrApiResponse.StatusDescription;
}
}
5. Run the application and test the Get Document functionality.
If the code has worked successfully, it returns the base64binary of the CDA zip package. In the next section we will save the zip package, extract the contents, and render the document using the CDA Generic stylesheet available on the Agency’s GitHub.
Step 5: Viewing the CDA documents
The following steps will show you how to save the CDA package as a zip file, extract the contents onto the device, and render it using the generic stylesheet.
1. Download the Generic stylesheet and save as Generic_CDA_Stylesheet.xsl into the assets folder of the device project, in our case the Android Project.
2. Modify the UI code to add a WebView inside the GenericDocumentServicesPage.xaml file, which will be used as a browser to render the CDA document. Note the <AbsoluteLayout> element at the bottom of the code which contains the WebView.
<StackLayout>
<Label Text="Generic Document Services" Margin="0, 20, 0, 20" Style="{StaticResource PageHeader}"
VerticalOptions="Start"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"/>
<BoxView HorizontalOptions="FillAndExpand" HeightRequest="1" Color="#222222" Margin="0, 0, 0, 20"/>
<Button Margin="0,10,0,0" Text="Search Document List" HorizontalOptions="Center"
x:Name="searchDocumentsList"
Clicked="searchDocuments_Clicked"
BackgroundColor="{StaticResource Primary}"
TextColor="White" />
<Button Margin="0,10,0,0" Text="Get Document" HorizontalOptions="Center"
x:Name="getDocument"
Clicked="getDocument_Clicked"
BackgroundColor="{StaticResource Primary}"
TextColor="White" />
<AbsoluteLayout>
<WebView x:Name="webView"
AbsoluteLayout.LayoutBounds="5,30,400,500" />
</AbsoluteLayout>
</StackLayout>
3. Modify the getDocument_Clicked method as shown in the following code.
private async void getDocument_Clicked(object sender, EventArgs e)
{
IMhrFhirService mhrFhirService = DependencyService.Get<MhrFhirService>();
string patientId = "2054814551";
string documentId = "1.3.16.1.38818.18446744073688372048.20200624043147715";
string cacheDirectory = FileSystem.CacheDirectory;
IRestResponse fhirMhrApiResponse = await mhrFhirService.GetDocument(patientId, documentId);
if (fhirMhrApiResponse.StatusCode == HttpStatusCode.OK)
{
try
{
string zipFilePath = $"{cacheDirectory}/{documentId}-package.zip";
string extractPathFolder = $"{cacheDirectory}/{documentId}";
// Hl7.Fhir.STU3 nuget installed in previous dev guides contains FHIR json parser to parse into binary.
FhirJsonParser parser = new FhirJsonParser();
Binary binary = (Binary)parser.Parse(fhirMhrApiResponse.Content);
File.WriteAllBytes($"{cacheDirectory}/{documentId}-package.zip", binary.Content);
// ZipFile.ExtractToDirectory method doesn't have overload method to extract and overwrite files in the .NET standard version.
// It raise the exception if file already exits.
if (Directory.Exists(extractPathFolder))
{
Directory.Delete(extractPathFolder, true);
// Unzip the package
ZipFile.ExtractToDirectory($"{cacheDirectory}/{documentId}-package.zip", extractPathFolder);
}
// CDA_ROOT.XML is main CDA document stored inside the CDA/CDADoc directory of extracted zip file.
string cdaDocFilePath = $"{extractPathFolder}/CDA/CDADoc/CDA_ROOT.XML";
if (File.Exists(cdaDocFilePath))
{
string baseFolder = FindBaseFolder($"{cacheDirectory}/{documentId}");
if (baseFolder != null)
{
byte[] content = File.ReadAllBytes(cdaDocFilePath);
string cda = Encoding.UTF8.GetString(content);
File.WriteAllText($"{cacheDirectory}/cda.xml", cda);
StringBuilder htmlStringBuilder = new StringBuilder();
using (var stream = await FileSystem.OpenAppPackageFileAsync("NEHTA_Generic_CDA_Stylesheet.xsl"))
using (var xmlWriter = XmlWriter.Create(htmlStringBuilder))
using (var memoryStream = new MemoryStream(content))
using (var xmlReader = XmlReader.Create(memoryStream))
using (var xReader = XmlReader.Create(stream))
{
XslCompiledTransform compiledTransform = new XslCompiledTransform();
compiledTransform.Load(xReader);
compiledTransform.Transform(xmlReader, xmlWriter);
}
string cdaHtml = htmlStringBuilder.ToString();
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = cdaHtml;
webView.Source = htmlSource;
}
}
}
catch (Exception ex)
{
}
}
else
{
string errorDesc = fhirMhrApiResponse.StatusDescription;
}
}
4. Add the following missing namespaces in the class file.
using System.IO;
using System.IO.Compression;
using System.Xml;
using System.Xml.Xsl;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Hl7.Fhir.Model;
using Hl7.Fhir.Serialization;
using MhrFhirDemoApp.Services;
using RestSharp;
5. Run and test the Get Document functionality.
Conclusion
Your application now has the ability to load all clinical document data except the requests that are specific to MBS and PBS data. You will likely be developing mechanisms for displaying the data retrieved and this can often be quite an involved task.
Important
Be sure to read the Presentation Requirements and Guidelines document before you begin in-depth work on presenting data retrieved from the My Health Record system.
In the next guide we will retrieve MBS and PBS documents.
View All | Back | Next: Medicare and PBS Information - My Health Record FHIR Gateway Developer Guide 7