Gestionar recursos FHIR mediante paquetes FHIR

En esta página se explica cómo gestionar recursos FHIR ejecutando paquetes FHIR, que son una colección de recursos FHIR y operaciones que se realizan en esos recursos FHIR.

El método ExecuteBundle implementa la interacción de lote o transacción estándar de FHIR (DSTU2, STU3, R4 y R5) y las operaciones de historial.

Paquetes FHIR

Un paquete FHIR contiene una matriz de entradas, cada una de las cuales representa una operación (como crear, actualizar o eliminar) en un recurso (como una observación o un paciente). Consulta las descripciones detalladas de los elementos del recurso Bundle.

Cuando ejecutas un paquete FHIR, el tipo de paquete determina cómo se realizan las operaciones del paquete. Están disponibles los siguientes tipos de paquete:

  • batch: ejecuta las operaciones como varias solicitudes independientes.
  • transaction: ejecuta las operaciones como varias solicitudes que dependen entre sí.
  • history: inserta las entradas en el historial de un recurso.

Por ejemplo, supongamos que un paquete de transacciones incluye la creación de un recurso Patient y un recurso Observation. Si falla la solicitud de creación del recurso Patient, no se creará el recurso Observation.

Si una operación falla cuando el tipo de paquete es batch, la API Cloud Healthcare ejecuta las operaciones restantes del paquete. Si una operación falla cuando el tipo de paquete es transaction, la API Cloud Healthcare detiene la ejecución de las operaciones y revierte la transacción.

Packs de contenido histórico

Los paquetes de historial son extensiones personalizadas del estándar FHIR que admiten casos prácticos de copia de seguridad y restauración, como la sincronización. Puedes usar paquetes de historial para insertar o sustituir versiones de recursos en el historial de un recurso FHIR. Solo puede quitar versiones de recursos con el método Resource-purge. El paquete history se ejecuta como una sola transacción con un límite de 100 entradas por paquete. Si una versión de un recurso del paquete history tiene una marca de tiempo posterior a la de la versión más reciente del almacén FHIR, esta última se actualizará en consecuencia. Si el paquete history se inserta correctamente, se devuelve una respuesta vacía. De lo contrario, se devuelve un OperationOutcome que describe el error.

La compatibilidad con los paquetes de historial no está habilitada de forma predeterminada. Un administrador del almacén FHIR debe definir enableHistoryModifications como true en la configuración del almacén FHIR. No puedes usar paquetes de historial si disableResourceVersioning está configurado como true en la configuración del almacén FHIR.

Los paquetes del historial se proporcionan en el mismo formato en el que se devuelven desde el método fhir.history. Para que sea válida, cada entrada del paquete requiere un ID de recurso, una marca de tiempo de modificación y un estado. Además, todas las entradas deben tener el mismo ID de recurso. El ID de recurso se proporciona en el campo resource.id o en el campo request.url. Si se proporcionan campos, el ID de recurso proporcionado debe ser el mismo. La marca de tiempo del recurso se proporciona con el campo meta.lastUpdated del recurso o el campo response.lastModified.

Conceder permisos para ejecutar paquetes

Se necesita el rol de permiso datasets.fhirStores.fhir.executeBundle para ejecutar paquetes. Para conceder este permiso, usa el rol healthcare.fhirResourceReader. Para saber cómo conceder este permiso, consulta Modificar una política.

Para ejecutar paquetes del historial, también se necesita el rol de permiso datasets.fhirStores.fhir.import.

La API Cloud Healthcare comprueba los permisos de cada operación del paquete. Si tienes permiso healthcare.fhirResources.create, pero no permiso healthcare.fhirResources.update, solo puedes ejecutar paquetes que contengan operaciones healthcare.fhirResources.create.

Ejecutar un paquete

Para ejecutar un paquete FHIR, usa el método projects.locations.datasets.fhirStores.fhir.executeBundle.

En los siguientes ejemplos, BUNDLE.json es la ruta y el nombre de archivo de un paquete de FHIR codificado en JSON. También puedes incluir el paquete en el cuerpo de la solicitud.

El siguiente Bundle de ejemplo crea un recurso Patient y elimina otro:

{
  "resourceType": "Bundle",
  "id": "bundle-transaction",
  "meta": {
    "lastUpdated": "2018-03-11T11:22:16Z"
  },
  "type": "transaction",
  "entry": [
    {
      "resource": {
        "resourceType": "Patient",
        "name": [
          {
            "family": "Smith",
            "given": [
              "Darcy"
            ]
          }
        ],
        "gender": "female",
        "address": [
          {
            "line": [
              "123 Main St."
            ],
            "city": "Anycity",
            "state": "CA",
            "postalCode": "12345"
          }
        ]
      },
      "request": {
        "method": "POST",
        "url": "Patient"
      }
    },
    {
      "request": {
        "method": "DELETE",
        "url": "Patient/1234567890"
      }
    }
  ]
}

En los siguientes ejemplos se muestra cómo ejecutar un paquete.

curl

Para ejecutar un paquete, haz una solicitud POST y especifica la siguiente información:

  • El nombre y la ubicación del conjunto de datos superior y del almacén FHIR
  • La ubicación del archivo de paquete en tu máquina local
  • Un token de acceso

En el siguiente ejemplo se muestra una solicitud POST que utiliza curl:

curl -X POST \
    -H "Content-Type: application/fhir+json; charset=utf-8" \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    --data @BUNDLE_FILE.json \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir"

Independientemente del resultado de las operaciones individuales, después de ejecutar un paquete por lotes, el servidor devuelve una representación codificada en JSON de un recurso Bundle de tipo batch-response. El recurso Bundle contiene una entrada por cada entrada de la solicitud con el resultado del procesamiento de la entrada, que puede ser una combinación de resultados correctos y de error.

Si un paquete de transacciones se completa correctamente, el servidor devuelve una representación codificada en JSON de un recurso Bundle de tipo transaction-response que contiene una entrada por cada entrada de la solicitud con el resultado correcto de la operación.

Si se produce un error al ejecutar un paquete de transacciones, el cuerpo de la respuesta no contendrá ningún paquete. En su lugar, contiene un recurso OperationOutcome codificado con JSON que describe el motivo del error. Las operaciones correctas que se han revertido no se registran en la respuesta.

El siguiente paquete de ejemplo es el resultado de ejecutar correctamente el ejemplo anterior. La primera entrada indica que la operación para crear un paciente se ha realizado correctamente e incluye el ID del nuevo recurso. La segunda entrada indica que la operación de eliminación se ha completado correctamente.

{
  "entry": [
    {
      "response": {
        "location": projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/RESOURCE/RESOURCE_ID,
        "status": "201 Created"
      }
    },
    {
      "response": {
        "status": "200 OK"
      }
    }
  ],
  "resourceType": "Bundle",
  "type": "transaction-response"
}

PowerShell

Para ejecutar un paquete, haz una solicitud POST y especifica la siguiente información:

  • El nombre y la ubicación del conjunto de datos superior y del almacén FHIR
  • La ubicación del archivo de paquete en tu máquina local
  • Un token de acceso

En el siguiente ejemplo se muestra una solicitud POST que utiliza Windows PowerShell:

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-RestMethod `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/fhir+json" `
  -InFile BUNDLE_FILE.json `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir" | ConvertTo-Json

Independientemente del resultado de las operaciones individuales, después de ejecutar un paquete por lotes, el servidor devuelve una representación codificada en JSON de un recurso Bundle de tipo batch-response. El recurso Bundle contiene una entrada por cada entrada de la solicitud con el resultado del procesamiento de la entrada, que puede ser una combinación de resultados correctos y de error.

Si un paquete de transacciones se completa correctamente, el servidor devuelve una representación codificada en JSON de un recurso Bundle de tipo transaction-response que contiene una entrada por cada entrada de la solicitud con el resultado correcto de la operación.

Si se produce un error al ejecutar un paquete de transacciones, el cuerpo de la respuesta no contendrá ningún paquete. En su lugar, contiene un recurso OperationOutcome codificado con JSON que describe el motivo del error. Las operaciones correctas que se han revertido no se registran en la respuesta.

El siguiente paquete de ejemplo es el resultado de ejecutar correctamente el ejemplo anterior. La primera entrada indica que la operación para crear un paciente se ha realizado correctamente e incluye el ID del nuevo recurso. La segunda entrada indica que la operación de eliminación se ha completado correctamente.

{
  "entry": [
    {
      "response": {
        "etag": "ETAG",
        "lastModified": "2020-08-03T04:12:47.312669+00:00",
        "location": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/RESOURCE/RESOURCE_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "ETAG",
        "lastModified": "2020-08-03T04:12:47.312669+00:00",
        "status": "200 OK"
      }
    }
  ],
  "resourceType": "Bundle",
  "type": "transaction-response"
}

Go

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"

	healthcare "google.golang.org/api/healthcare/v1"
)

// fhirExecuteBundle executes an FHIR bundle.
func fhirExecuteBundle(w io.Writer, projectID, location, datasetID, fhirStoreID string) error {
	ctx := context.Background()

	healthcareService, err := healthcare.NewService(ctx)
	if err != nil {
		return fmt.Errorf("healthcare.NewService: %w", err)
	}

	fhirService := healthcareService.Projects.Locations.Datasets.FhirStores.Fhir

	payload := map[string]interface{}{
		"resourceType": "Bundle",
		"type":         "transaction",
		"entry": []map[string]interface{}{
			{
				"resource": map[string]interface{}{
					"resourceType": "Patient",
					"active":       true,
				},
				"request": map[string]interface{}{
					"method": "POST",
					"url":    "Patient",
				},
			},
		},
	}
	jsonPayload, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("json.Encode: %w", err)
	}

	parent := fmt.Sprintf("projects/%s/locations/%s/datasets/%s/fhirStores/%s", projectID, location, datasetID, fhirStoreID)

	call := fhirService.ExecuteBundle(parent, bytes.NewReader(jsonPayload))
	call.Header().Set("Content-Type", "application/fhir+json;charset=utf-8")
	resp, err := call.Do()
	if err != nil {
		return fmt.Errorf("executeBundle: %w", err)
	}
	defer resp.Body.Close()

	respBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("could not read response: %w", err)
	}

	if resp.StatusCode > 299 {
		return fmt.Errorf("create: status %d %s: %s", resp.StatusCode, resp.Status, respBytes)
	}
	fmt.Fprintf(w, "%s", respBytes)

	return nil
}

Java

import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.healthcare.v1.CloudHealthcare;
import com.google.api.services.healthcare.v1.CloudHealthcareScopes;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;

public class FhirStoreExecuteBundle {
  private static final String FHIR_NAME = "projects/%s/locations/%s/datasets/%s/fhirStores/%s";
  private static final JsonFactory JSON_FACTORY = new GsonFactory();
  private static final NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();

  public static void fhirStoreExecuteBundle(String fhirStoreName, String data)
      throws IOException, URISyntaxException {
    // String fhirStoreName =
    //    String.format(
    //        FHIR_NAME, "your-project-id", "your-region-id", "your-dataset-id", "your-fhir-id");
    // String data = "{\"resourceType\": \"Bundle\",\"type\": \"batch\",\"entry\": []}"

    // Initialize the client, which will be used to interact with the service.
    CloudHealthcare client = createClient();
    HttpClient httpClient = HttpClients.createDefault();
    String baseUri = String.format("%sv1/%s/fhir", client.getRootUrl(), fhirStoreName);
    URIBuilder uriBuilder = new URIBuilder(baseUri).setParameter("access_token", getAccessToken());
    StringEntity requestEntity = new StringEntity(data);

    HttpUriRequest request =
        RequestBuilder.post()
            .setUri(uriBuilder.build())
            .setEntity(requestEntity)
            .addHeader("Content-Type", "application/fhir+json")
            .addHeader("Accept-Charset", "utf-8")
            .addHeader("Accept", "application/fhir+json; charset=utf-8")
            .build();

    // Execute the request and process the results.
    HttpResponse response = httpClient.execute(request);
    HttpEntity responseEntity = response.getEntity();
    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
      System.err.print(
          String.format(
              "Exception executing FHIR bundle: %s\n", response.getStatusLine().toString()));
      responseEntity.writeTo(System.err);
      throw new RuntimeException();
    }
    System.out.print("FHIR bundle executed: ");
    responseEntity.writeTo(System.out);
  }

  private static CloudHealthcare createClient() throws IOException {
    // Use Application Default Credentials (ADC) to authenticate the requests
    // For more information see https://cloud.google.com/docs/authentication/production
    GoogleCredentials credential =
        GoogleCredentials.getApplicationDefault()
            .createScoped(Collections.singleton(CloudHealthcareScopes.CLOUD_PLATFORM));

    // Create a HttpRequestInitializer, which will provide a baseline configuration to all requests.
    HttpRequestInitializer requestInitializer =
        request -> {
          new HttpCredentialsAdapter(credential).initialize(request);
          request.setConnectTimeout(60000); // 1 minute connect timeout
          request.setReadTimeout(60000); // 1 minute read timeout
        };

    // Build the client for interacting with the service.
    return new CloudHealthcare.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
        .setApplicationName("your-application-name")
        .build();
  }

  private static String getAccessToken() throws IOException {
    GoogleCredentials credential =
        GoogleCredentials.getApplicationDefault()
            .createScoped(Collections.singleton(CloudHealthcareScopes.CLOUD_PLATFORM));

    return credential.refreshAccessToken().getTokenValue();
  }
}

Node.js

Puedes consultar un archivo de paquete de muestra en el repositorio de GitHub del código de muestra.

const google = require('@googleapis/healthcare');
const healthcare = google.healthcare({
  version: 'v1',
  auth: new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  }),
  headers: {'Content-Type': 'application/fhir+json'},
});
const fs = require('fs');

async function executeFhirBundle() {
  // TODO(developer): uncomment these lines before running the sample
  // const cloudRegion = 'us-central1';
  // const projectId = 'adjective-noun-123';
  // const datasetId = 'my-dataset';
  // const fhirStoreId = 'my-fhir-store';
  // const bundleFile = 'bundle.json';
  const parent = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/fhirStores/${fhirStoreId}`;

  const bundle = JSON.parse(fs.readFileSync(bundleFile));

  const request = {parent, requestBody: bundle};
  const resource =
    await healthcare.projects.locations.datasets.fhirStores.fhir.executeBundle(
      request
    );
  console.log('FHIR bundle executed');
  console.log(resource.data);
}

executeFhirBundle();

Python

Puedes consultar un archivo de paquete de muestra en el repositorio de GitHub del código de muestra.

def execute_bundle(
    project_id,
    location,
    dataset_id,
    fhir_store_id,
    bundle,
):
    """Executes the operations in the given bundle.

    See https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/healthcare/api-client/v1/fhir
    before running the sample."""
    # Imports Python's built-in "os" module
    import os

    # Imports the google.auth.transport.requests transport
    from google.auth.transport import requests

    # Imports a module to allow authentication using a service account
    from google.oauth2 import service_account

    # Gets credentials from the environment.
    credentials = service_account.Credentials.from_service_account_file(
        os.environ["GOOGLE_APPLICATION_CREDENTIALS"]
    )
    scoped_credentials = credentials.with_scopes(
        ["https://www.googleapis.com/auth/cloud-platform"]
    )
    # Creates a requests Session object with the credentials.
    session = requests.AuthorizedSession(scoped_credentials)

    # URL to the Cloud Healthcare API endpoint and version
    base_url = "https://healthcare.googleapis.com/v1"

    # TODO(developer): Uncomment these lines and replace with your values.
    # project_id = 'my-project'  # replace with your GCP project ID
    # location = 'us-central1'  # replace with the parent dataset's location
    # dataset_id = 'my-dataset'  # replace with the parent dataset's ID
    # fhir_store_id = 'my-fhir-store' # replace with the FHIR store ID
    # bundle = 'bundle.json'  # replace with the bundle file
    url = f"{base_url}/projects/{project_id}/locations/{location}"

    resource_path = "{}/datasets/{}/fhirStores/{}/fhir".format(
        url, dataset_id, fhir_store_id
    )

    headers = {"Content-Type": "application/fhir+json;charset=utf-8"}

    with open(bundle) as bundle_file:
        bundle_file_content = bundle_file.read()

    response = session.post(resource_path, headers=headers, data=bundle_file_content)
    response.raise_for_status()

    resource = response.json()

    print(f"Executed bundle from file: {bundle}")
    print(json.dumps(resource, indent=2))

    return resource

Hacer una solicitud PATCH

Puedes usar paquetes FHIR para hacer solicitudes JSON PATCH en recursos FHIR. Consulta más información sobre cómo ejecutar una solicitud PATCH en un paquete FHIR.

Resolver referencias a recursos creados en un paquete

Los recursos de un paquete de transacciones pueden contener referencias a recursos que no existan en el sistema de destino, pero que se creen durante la ejecución del paquete. La API Cloud Healthcare resuelve la asociación entre los recursos mediante el campo entry.fullUrl. Las referencias que coincidan con el valor entry.fullUrl de otro recurso del paquete se reescriben con el ID del recurso correspondiente en el almacén. Esto se realiza correctamente independientemente del orden de las operaciones del paquete.

La API Cloud Healthcare acepta fullUrl en los siguientes formatos:

  • urn:uuid:UUID
  • urn:oid:OID
  • cualquier URL
  • un nombre de recurso con el formato RESOURCE_TYPE/RESOURCE_ID, como Patient/123. No se recomienda usar este formato porque fullUrl es un marcador de posición local del paquete. Esto puede generar confusión si un recurso de la tienda tiene el mismo nombre, pero el recurso del paquete se resuelve con un nombre diferente como resultado de una operación de creación.

El siguiente paquete de ejemplo crea un recurso Patient y un recurso Observation que hace referencia al recurso Patient.

{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry":[
    {
      "request": {
        "method":"POST",
        "url":"Patient"
      },
      "fullUrl": "urn:uuid:05efabf0-4be2-4561-91ce-51548425acb9",
      "resource": {
        "resourceType":"Patient",
        "gender":"male"
      }
    },
    {
      "request": {
        "method":"POST",
        "url":"Observation"
      },
      "resource": {
        "resourceType":"Observation",
        "subject": {
          "reference": "urn:uuid:05efabf0-4be2-4561-91ce-51548425acb9"
        },
        "status":"preliminary",
        "code": {
          "text":"heart rate"
        }
      }
    }
  ]
}

En los siguientes ejemplos se muestra cómo ejecutar un paquete.

curl

Puedes consultar un archivo de paquete de muestra en el repositorio de GitHub del código de muestra.

Para ejecutar un paquete, haz una solicitud POST y especifica la siguiente información:

  • El nombre y la ubicación del conjunto de datos superior y del almacén FHIR
  • Ubicación del archivo de paquete en Cloud Storage
  • Un token de acceso

En el siguiente ejemplo se muestra una solicitud POST que utiliza curl:

curl -X POST \
    -H "Content-Type: application/fhir+json; charset=utf-8" \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    --data @BUNDLE_FILE.json \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir"

El siguiente paquete de ejemplo es el resultado de ejecutar correctamente el ejemplo anterior. La primera entrada indica que la operación para crear un paciente se ha realizado correctamente e incluye el ID del nuevo recurso. La segunda entrada indica que la operación para crear la observación se ha completado correctamente e incluye el ID del nuevo recurso.

{
  "entry": [
    {
      "response": {
        "etag": "ETAG1",
        "lastModified": "2020-08-04T16:14:14.273976+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/datasets/REGION/fhirStores/FHIR_STORE_ID/fhir/Patient/PATIENT_ID/_history/HISTORY_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "ETAG",
        "lastModified": "2020-08-04T16:14:14.273976+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/datasets/REGION/fhirStores/FHIR_STORE_ID/fhir/Observation/OBSERVATION_ID/_history/HISTORY_ID",
        "status": "201 Created"
      }
    }
  ],
  "resourceType": "Bundle",
  "type": "transaction-response"
}

PowerShell

Puedes consultar un archivo de paquete de muestra en el repositorio de GitHub del código de muestra.

Para ejecutar un paquete, haz una solicitud POST y especifica la siguiente información:

  • El nombre y la ubicación del conjunto de datos superior y del almacén FHIR
  • Ubicación del archivo de paquete en Cloud Storage
  • Un token de acceso

En el siguiente ejemplo se muestra una solicitud POST que utiliza Windows PowerShell:

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-RestMethod `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/fhir+json" `
  -InFile BUNDLE_FILE.json `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir" | ConvertTo-Json

El siguiente paquete de ejemplo es el resultado de ejecutar correctamente el ejemplo anterior. La primera entrada indica que la operación para crear un paciente se ha realizado correctamente e incluye el ID del nuevo recurso. La segunda entrada indica que la operación para crear la observación se ha completado correctamente e incluye el ID del nuevo recurso.

{
  "entry": [
    {
      "response": {
        "etag": "ETAG1",
        "lastModified": "2020-08-04T16:14:14.273976+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/datasets/REGION/fhirStores/FHIR_STORE_ID/fhir/Patient/PATIENT_ID/_history/HISTORY_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "ETAG",
        "lastModified": "2020-08-04T16:14:14.273976+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/datasets/REGION/fhirStores/FHIR_STORE_ID/fhir/Observation/OBSERVATION_ID/_history/HISTORY_ID",
        "status": "201 Created"
      }
    }
  ],
  "resourceType": "Bundle",
  "type": "transaction-response"
}