Aidbox Docs

Patch

In most Operations in FHIR, you manipulate a resource as a whole (create, update, delete operations). But sometimes you want to update specific data elements in a resource and do not care about the rest. In other words, you need an element/attribute level operation.

With the patch operation, you can update a part of a resource by sending a declarative description of operations that should be performed on an existing resource. To describe these operations in Aidbox, you can use different notations (methods):

Patch Method

You can specify a patch method by the content-type header or by the _method parameter.

methodparameterheader
json-patchjson-patchapplication/json-patch+json
merge-patchmerge-patchapplication/merge-patch+json
fhirpath-patchfhirpath-patch-

If the method is not specified, Aidbox will try to guess it by the following algorithm:

  • if the body contains "Parameters" resourceType, it is fhirpath-patch
  • if the payload is an array, it is json-patch
  • else merge-patch

Choosing a patch method

All three methods produce equivalent results for simple field updates and trigger the same update event. They differ in body shape, expressiveness, and verbosity:

MethodBody shapeBest forNotes
Merge PatchJSON object — fields you want to set or null outAd-hoc field updates, "set this, clear that"Simplest. Cannot reorder arrays or target array elements by predicate.
JSON PatchJSON array of operations per RFC 6902Array operations (add with /-, remove, replace at index), compact programmatic patchesBody must be an array — see the warning under JSON Patch. Targets elements by JSON Pointer position.
FHIRPath PatchParameters resource with one or more operation partsSelecting elements by FHIRPath predicate (Patient.identifier.where(system='foo')), extension-by-id replacement, FHIR-spec-aligned toolingMost verbose — about 3–4× the bytes of an equivalent JSON Patch — but the only method that can target by FHIRPath expression rather than positional index.

Rule of thumb: reach for merge-patch for one-off updates, JSON Patch when you need array operations or compact diffs, and FHIRPath Patch when you need to select elements by predicate or are integrating with FHIR-spec tooling.

Binary JSON-patch

Since version 2503, It is also possible to encode JSON patches using base64 Binary.data:

PATCH /fhir/Patient/1?_method=json-patch
content-type: application/json
accept: application/json

{
  "resourceType": "Binary",
  "contentType": "application/json-patch+json",
  "data": "WyB7ICJvcCI6InJlcGxhY2UiLCAicGF0aCI6Ii9hY3RpdmUiLCAidmFsdWUiOmZhbHNlIH0gXQ=="
}

Events and subscriptions

A PATCH request that changes a resource fires the same update lifecycle event as a PUT, regardless of which patch method (merge-patch, json-patch, or fhirpath-patch) was used. Consumers that listen for resource updates therefore see PATCH-originated changes:

If the patch produces no actual change to the resource (for example, replacing a field with the same value it already has), Aidbox returns 200 OK but does not fire an event — subscribers are not notified.

The audit log records PATCH operations under the fhir/patch event type, distinct from fhir/update, so patch-originated changes can be identified separately in audit history.

Examples

Let's suppose we've created a Patient resource with the id pt-1

POST /Patient

{
  "resourceType": "Patient",
  "id": "pt-1",
  "active": true,
  "name": [
    {
      "given": ["John"],
      "family": "Doe",
      "use": "official"
    },
    {
      "given": ["Johny"],
      "family": "Doe"
    }
  ],
  "telecom": [
    {
      "system": "phone",
      "value": "(03) 5555 6473",
      "use": "work",
      "rank": 1
    }
  ],
  "birthDate": "1979-01-01"
}

Merge Patch

Let's say we want to switch to an active flag to false and remove telecom:

PATCH /Patient/pt-1

{
  "active": false,
  "telecom": null
}

Response:

// 200

{
  "id": "pt-1",
  "resourceType": "Patient",
  "name": [
    {
      "use": "official",
      "given": ["John"],
      "family": "Doe"
    },
    {
      "given": ["Johny"],
      "family": "Doe"
    }
  ],
  "active": false,
  "birthDate": "1979-01-01"
}

JSON Patch

With JSON patch, we can do more sophisticated transformations — change the first given name, delete the second name, and change the active attribute value to true:

The JSON Patch body must be a JSON array of operation objects per RFC 6902. Sending a single object instead of an array will result in an error.

[{"op": "add", "path": "/birthDate", "value": "1990-01-01"}]
{"op": "add", "path": "/birthDate", "value": "1990-01-01"}
PATCH /Patient/pt-1

[
  {"op": "replace", "path": "/name/0/given/0", "value": "Nikolai"},
  {"op": "remove", "path": "/name/1"},
  {"op": "replace", "path": "/active", "value": true}
]

Response:

// 200 OK
{
  "id": "pt-1",
  "resourceType": "Patient",
  "name": [
    {
      "use": "official",
      "given": ["Nikolai"],
      "family": "Doe"
    }
  ],
  "active": true,
  "birthDate": "1979-01-01"
}

Array append with /-

In JSON Pointer paths, /- refers to the end of an array and can be used with the add operation to append a new element:

PATCH /Patient/pt-1

[
  {
    "op": "add",
    "path": "/name/-",
    "value": {
      "given": ["Jane"],
      "family": "Doe"
    }
  }
]

This appends a new name entry to the name array instead of replacing an element at a specific index.

FHIRPath Patch

FHIRPath Patch is a syntax-agnostic mechanism within the FHIR standard that enables precise modifications to FHIR resources by utilizing FHIRPath expressions to identify target elements.

This approach allows for operations such as add, insert, delete, replace, and move.

FHIRPath Patch operations are represented within a Parameters resource:

Add

The add operation appends a new value to a specified element within a FHIR resource

  • The path specifies where the new value should be added
  • The name represents the property being added
  • The value provides the data that will be added
Add primitive example
PATCH /fhir/Patient/pt-1

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "operation",
      "part": [
        {"name": "type", "valueCode": "add"},
        {"name": "path", "valueString": "Patient"},
        {"name": "name", "valueString": "birthDate"},
        {"name": "value", "valueDate": "1931-01-01"}
      ]
    }
  ]
}
Add BackboneElement example
PATCH /fhir/Patient/pt-1

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "operation",
      "part": [
        {"name": "type", "valueCode": "add"},
        {"name": "path", "valueString": "Patient"},
        {"name": "name", "valueString": "contact"},
        {
          "name": "value",
          "part": [
            {
              "name": "name",
              "valueHumanName": {"text": "a name"}
            }
          ]
        }
      ]
    }
  ]
}

Insert

The insert operation allows you to insert a new element into an existing list at a specified position

  • The path specifies the collection where the element should be inserted. Collection must be present
  • The value specifies the new data to insert
  • The index defines the position (0-based) at which to insert the element. The index is mandatory and must be equal to or less than the number of elements already in the list
Insert example
PATCH /fhir/Patient/pt-1

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "operation",
      "part": [
        {"name": "type", "valueCode": "insert"},
        {"name": "path", "valueString": "Patient.name"},
        {"name": "index", "valueInteger": 0},
        {
          "name": "value",
          "valueHumanName": {"given": ["John"]}
        }
      ]
    }
  ]
}

Delete

The delete operation removes an element from a resource. Only one element can be deleted at a time.

  • The path specifies the element to be deleted
Delete primitive example
PATCH /fhir/Patient/pt-1

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "operation",
      "part": [
        {"name": "type", "valueCode": "delete"},
        {"name": "path", "valueString": "Patient.gender"}
      ]
    }
  ]
}
Delete specific array element
PATCH /fhir/Patient/pt-1

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

Replace

The replace operation updates the value of an existing element within a FHIR resource

  • The path specifies the element to be replaced
  • The value provides the new data that will replace the existing value
  • The operation will fail if the specified element does not exist
Replace primitive example
PATCH /fhir/Patient/pt-1

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "operation",
      "part": [
        {"name": "type", "valueCode": "replace"},
        {"name": "path", "valueString": "Patient.gender"},
        {"name": "value", "valueCode": "female"}
      ]
    }
  ]
}

Replace extension by id example:

PATCH /fhir/Patient/pt1

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "operation",
      "part": [
        {"name": "type", "valueCode": "replace"},
        {"name": "path", "valueString": "Patient.extension('http://example.org/my-extension').value"},
        {"name": "value", "valueString": "new-value"}
      ]
    }
  ]
}

Move

The move operation allows you to relocate an element within a collection from one index to another

  • The path specifies the collection or list where the element is located
  • The from index indicates the current position of the element to be moved (0-based index)
  • The to index indicates the new position where the element should be moved
PATCH /fhir/Patient/pt-1

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "operation",
      "part": [
        {"name": "type", "valueCode": "move"},
        {"name": "path", "valueString": "Patient.identifier"},
        {"name": "source", "valueInteger": 1},
        {"name": "destination", "valueInteger": 0}
      ]
    }
  ]
}

Last updated: