REST API capabilities in the FHIR service in Azure Health Data Services

In this article, we cover some of the nuances of the RESTful interactions of the FHIR® service in Azure Health Data Services.

Conditional create/update

The FHIR service supports create, conditional create, update, and conditional update as defined by the FHIR specification. One useful header in these scenarios is the If-Match header. The If-Match header is used to validate the version being updated before making the update. If the ETag doesn’t match the expected ETag, it produces the error message 412 Precondition Failed.

Delete and conditional delete

The FHIR service offers two delete types. There's Delete, which is also know as Hard + Soft Delete, and Conditional Delete.

Delete can be performed for an individual resource id, or in bulk. To learn more on deleting resources in bulk, visit $bulk-delete operation.

Delete (hard and soft delete)

Delete defined by the FHIR specification requires that after deleting a resource, subsequent nonversion reads of that resource return a 410 HTTP status code. As a result, the resource is no longer found through searching. Additionally, the FHIR service enables you to fully delete the resource (including all history). To fully delete the resource, pass a parameter true setting to hardDelete: (DELETE {{FHIR_URL}}/{resource}/{id}?hardDelete=true). If you don't pass this parameter or set hardDelete to false, the historic versions of the resource are still available.

Note

If you only want to delete the history, the FHIR service supports a custom operation called $purge-history. This operation allows you to delete the history from a resource.

Conditional delete

Conditional delete allows you to pass search criteria to delete a resource. By default, the Conditional delete allows you to delete one item at a time. You can also specify the _count parameter to delete up to 100 items at a time. Following are some examples of using conditional delete.

To delete a single item, specify search criteria that return a single item.

DELETE https://{{FHIR_URL}}/Patient?identifier=1032704

Or, do the same search but include hardDelete=true to also delete all history.

DELETE https://{{FHIR_URL}}/Patient?identifier=1032704&hardDelete=true

To delete multiple resources, include the _count=100 parameter. This parameter deletes up to 100 resources that match the search criteria.

DELETE https://{{FHIR_URL}}/Patient?identifier=1032704&_count=100

Recovery of deleted files

If you don't use the hard delete parameter, then the records in the FHIR service still exist. Find the records by doing a history search on the resource and looking for the last version with data.

If you don't know the ID of the resource that was deleted, use this URL pattern:

<FHIR_URL>/<resource-type>/<resource-id>/_history

For example: https://myworkspace-myfhirserver.fhir.azurehealthcareapis.com/Patient/123456789/_history

If you don't know the ID of the resource, do a history search on the entire resource type:

<FHIR_URL>/<resource-type>/_history

For example: https://myworkspace-myfhirserver.fhir.azurehealthcareapis.com/Patient/_history

After you find the record to restore, use the PUT operation to recreate the resource with the same ID, or use the POST operation to make a new resource with the same information.

Note

There is no time-based expiration for history or soft delete data. The only way to remove history or soft-deleted data is with a hard delete or the purge history operation.

Batch and transaction bundles

In the FHIR service, bundles are considered a container that holds multiple resources. Batch and transaction bundles enable users to submit a set of actions to be performed on a server in single HTTP request/response. The actions can be performed independently as a batch, or as a single atomic transaction where the entire set of changes succeed or fail as a single entity. Actions on multiple resources of the same or different types can be submitted, such as create, update, or delete. For more information, see FHIR bundles.

A batch or transaction bundle interaction with the FHIR service is performed with HTTP POST command at base URL.

POST {{fhir_url}} 
{ 
  "resourceType": "Bundle", 
  "type": "batch", 
  "entry": [ 
    { 
      "resource": { 
        "resourceType": "Patient", 
        "id": "patient-1", 
        "name": [ 
          { 
            "given": ["Alice"], 
            "family": "Smith" 
          } 
        ], 
        "gender": "female", 
        "birthDate": "1990-05-15" 
      }, 
      "request": { 
        "method": "POST", 
        "url": "Patient" 
      } 
    }, 
    { 
      "resource": { 
        "resourceType": "Patient", 
        "id": "patient-2", 
        "name": [ 
          { 
            "given": ["Bob"], 
            "family": "Johnson" 
          } 
        ], 
        "gender": "male", 
        "birthDate": "1985-08-23" 
      }, 
      "request": { 
        "method": "POST", 
        "url": "Patient" 
      } 
    } 
   } 
  ] 
} 

For a batch, each entry is treated as an individual interaction or operation.

Note

For batch bundles there are no interdependencies between different entries in a FHIR bundle. The success or failure of one entry doesn't impact the success or failure of another entry.

For a transaction bundle, all interactions or operations either succeed or fail together. When a transaction bundle fails, the FHIR service returns a single OperationOutcome.

Transaction bundles don't support:

  • Conditional delete
  • Search operations using _search

Bundle parallel processing

Batch and transaction bundles are executed serially in the FHIR service. To improve performance and throughput, we enabled parallel processing of bundles.

To use parallel batch bundle processing:

  • Set header x-bundle-processing-logic value to parallel.
  • Ensure there's no overlapping resource ID that executes on DELETE, POST, PUT, or PATCH operations in the same bundle.

History

The history interaction retrieves the history of either a particular resource, all resources of a given type, or all resources supported by the system. History interactions are performed by the HTTP GET command.

For example: GET https://{{FHIR_URL}}/{resource type}/{resource id}/_history GET https://{{FHIR_URL}}/{resource type})/_history

The response is a bundle with type set to the specified version history, sorted with oldest versions last, and including deleted resources.

To search with history, use the following interactions.

  • _count : defines the number of resources returned on single page.
  • _since : includes resource versions created at or after the given instant in time.
  • _before : includes resource versions that were created before the given instant in time.

For more information on history and version management visit FHIR versioning policy and history management.

Patch and conditional patch

Patch is a valuable RESTful operation when you need to update only a portion of the FHIR resource. Using patch allows you to specify the element that you want to update in the resource without having to update the entire record. FHIR defines three ways to patch resources: JSON Patch, XML Patch, and FHIRPath Patch. The FHIR service supports JSON Patch and FHIRPath Patch, along with Conditional JSON Patch and Conditional FHIRPath Patch (which allows you to patch a resource based on a search criteria instead of a resource ID). For examples, refer to the FHIRPath Patch REST file and the JSON Patch REST file. For more information, see HL7 documentation for patch operations with FHIR.

Note

When using PATCH against STU3, and if you are requesting a History bundle, the patched resource's Bundle.entry.request.method is mapped to PUT. This is because STU3 doesn't contain a definition for the PATCH verb in the HTTPVerb value set.

Patch with FHIRPath patch

This method of patch is the most powerful as it uses FHIRPath for selecting which element to target. One common scenario is using FHIRPath Patch to update an element in a list without knowing the order of the list. For example, if you want to delete a patient’s home telecom information without knowing the index, you can use the following example.

PATCH http://{FHIR-SERVICE-HOST-NAME}/Patient/{PatientID}
Content-type: application/fhir+json

{
    "resourceType": "Parameters",
    "parameter": [
        {
            "name": "operation",
            "part": [
                {
                    "name": "type",
                    "valueCode": "delete"
                },
                {
                    "name": "path",
                    "valueString": "Patient.telecom.where(use = 'home')"
                }
            ]
        }
    ]
}

Any FHIRPath Patch operations must have the application/fhir+json Content-Type header set. FHIRPatch Patch supports add, insert, delete, remove, and move operations. FHIRPatch Patch operations also can be easily integrated into Bundles. For more examples, look at the sample FHIRPath Patch REST file.

Patch with JSON Patch

JSON Patch in the FHIR service conforms to the well-used specification defined by the Internet Engineering Task Force. The payload format doesn't use FHIR resources and instead uses a JSON document using JSON-Pointers for element selection. JSON Patch is more compact and has a test operation that allows you to validate that a condition is true before doing the patch. For example, if you want to set a patient as deceased only if they're not already marked as deceased, you can use the following example.

PATCH http://{FHIR-SERVICE-HOST-NAME}/Patient/{PatientID}
Content-type: application/json-patch+json

[
	{
		"op": "test",
		"path": "/deceasedBoolean",
		"value": false
	},
	{
		"op": "replace",
		"path": "/deceasedBoolean",
		"value": true
	}
]

Any JSON Patch operations must have the application/json-patch+json Content-Type header set. JSON Patch supports add, remove, replace, copy, move, and test operations. For more examples, look at the sample JSON Patch REST file.

JSON Patch in bundles

By default, JSON Patch isn't supported in bundle resources because a bundle only supports FHIR resources, and the JSON Patch payload isn't a FHIR resource. To work around this constraint, use binary resources with a content type "application/json-patch+json" and the base64 encoding of the JSON payload inside of a bundle. For more information, see the FHIR Chat Zulip.

In the following example, we change the gender for the patient to female. We take the JSON Patch [{"op":"replace","path":"/gender","value":"female"}] and encoded it to base64.

POST https://{FHIR-SERVICE-HOST-NAME}/
Content-Type: application/json

{
	"resourceType": "Bundle",
	"id": "bundle-batch",
	"type": "batch",
	"entry": [
		{
			"fullUrl": "Patient/{PatientID}",
			"resource": {
				"resourceType": "Binary",
				"contentType": "application/json-patch+json",
				"data": "W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6Ii9nZW5kZXIiLCJ2YWx1ZSI6ImZlbWFsZSJ9XQ=="
			},
			"request": { 
				"method": "PATCH",
				"url": "Patient/{PatientID}"
			}
		}
	]
}

Troubleshooting

Can I delete multiple patient observations or all patient resources in a single API call?

The $bulk-delete operation allows you to delete resources from the FHIR server asynchronously. You can execute the $bulk-delete operation either at the system level or for specific resource types. Bulk-delete

Overview of FHIR search

Note

FHIR® is a registered trademark of HL7 and is used with the permission of HL7.