Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Administra recursos de FHIR con paquetes de FHIR

En esta página, se explica cómo administrar recursos de FHIR con la ejecución de paquetes FHIR. El método ExecuteBundle implementa la interacción por lotes/transacción estándar de FHIR (DSTU2, STU3 y R4).

Paquetes de FHIR

Un paquete de FHIR contiene un arreglo de entradas, cada una de las cuales representa una operación, como crear, actualizar o borrar dentro de un recurso, como una observación o un paciente. Consulta las descripciones detalladas de los elementos en el recurso Bundle.

Cuando se ejecuta un paquete de FHIR, el tipo de paquete determina cómo se realizan las operaciones dentro de él. Establecer el tipo de paquete en batch ejecuta las operaciones como varias solicitudes independientes. Establecer el tipo de paquete en transaction ejecuta las operaciones como varias solicitudes que dependen unas de otras. Por ejemplo, si un paquete de transacciones incluye la creación de un paciente y una observación, cuando la solicitud de creación del paciente falla, no se crea la observación.

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

Otorga permisos para ejecutar paquetes

Se requiere la función de permiso datasets.fhirStores.fhir.executeBundle para ejecutar paquetes. Para otorgar este permiso, usa la función healthcare.fhirResourceReader. Si deseas conocer los pasos para otorgar este permiso, consulta Modifica una política.

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

Ejecuta un paquete

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

En las siguientes muestras, BUNDLE.json es la ruta y el nombre de archivo de un paquete de FHIR con codificación JSON. También puedes incluir el paquete en el cuerpo de la solicitud.

En el siguiente paquete de muestra, se crea un recurso paciente y se borra otro recurso paciente:

{
  "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, realiza una solicitud POST y especifica la siguiente información:

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

En el siguiente ejemplo, se muestra una solicitud POST mediante 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"

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

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

Si se produce un error mientras se ejecuta un paquete de transacciones, el cuerpo de la respuesta no contiene un paquete. En su lugar, contiene un recurso OperationOutcome codificado en JSON que describe el motivo del error. Las operaciones exitosas que se revirtieron no se informan en la respuesta.

El siguiente paquete de muestra es el resultado de la ejecución correcta del ejemplo anterior. La primera entrada indica el éxito de la operación para crear un Paciente e incluye el ID del nuevo recurso. La segunda entrada indica el éxito de la operación de eliminación.

{
  "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, realiza una solicitud POST y especifica la siguiente información:

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

En el siguiente ejemplo, se muestra una solicitud POST mediante 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

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

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

Si se produce un error mientras se ejecuta un paquete de transacciones, el cuerpo de la respuesta no contiene un paquete. En su lugar, contiene un recurso OperationOutcome codificado en JSON que describe el motivo del error. Las operaciones exitosas que se revirtieron no se informan en la respuesta.

El siguiente paquete de muestra es el resultado de la ejecución correcta del ejemplo anterior. La primera entrada indica el éxito de la operación para crear un Paciente e incluye el ID del nuevo recurso. La segunda entrada indica el éxito de la operación de eliminación.

{
  "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"
	"io/ioutil"

	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: %v", 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,
				},
			},
		},
	}
	jsonPayload, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("json.Encode: %v", 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: %v", err)
	}
	defer resp.Body.Close()

	respBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("could not read response: %v", 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.jackson2.JacksonFactory;
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 JacksonFactory();
  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

Hay un archivo de paquete de muestra disponible en el repositorio de GitHub de muestra de código.

const {google} = require('googleapis');
const healthcare = google.healthcare('v1');
const fs = require('fs');

async function executeFhirBundle() {
  const auth = await google.auth.getClient({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  });

  google.options({auth, headers: {'Content-Type': 'application/fhir+json'}});

  // 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

Hay un archivo de paquete de muestra disponible en el repositorio de GitHub de muestra de código.

def execute_bundle(
    base_url, project_id, cloud_region, dataset_id, fhir_store_id, bundle,
):
    """Executes the operations in the given bundle."""
    url = "{}/projects/{}/locations/{}".format(base_url, project_id, cloud_region)

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

    # Make an authenticated API request
    session = get_session()

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

    with open(bundle, "r") 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("Executed bundle from file: {}".format(bundle))
    print(json.dumps(resource, indent=2))

    return resource

Resuelve referencias a recursos creados en un paquete

Los recursos de un paquete de transacciones pueden contener referencias a recursos que no existen en el sistema de destino, pero que se crean durante la ejecución del paquete. La API de Cloud Healthcare resuelve la asociación entre los recursos mediante el campo entry.fullUrl. Las referencias que coinciden con el valor entry.fullUrl de otro recurso del paquete se vuelven a escribir con el ID del recurso correspondiente en el almacén. Esto tiene éxito sin importar el orden de las operaciones en el paquete.

La API de Cloud Healthcare acepta la fullUrl en los siguientes formatos:

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

En el siguiente conjunto de muestras, se crea un recurso de paciente y un recurso de observación que hace referencia al recurso de paciente.

{
  "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

Hay un archivo de paquete de muestra disponible en el repositorio de GitHub de muestra de código.

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

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

En el siguiente ejemplo, se muestra una solicitud POST mediante 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 muestra es el resultado de la ejecución correcta del ejemplo anterior. La primera entrada indica el éxito de la operación para crear un Paciente e incluye el ID del nuevo recurso. La segunda entrada indica el éxito de la operación para crear la observación y, además, incluye el ID del recurso nuevo.

{
  "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

Hay un archivo de paquete de muestra disponible en el repositorio de GitHub de muestra de código.

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

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

En el siguiente ejemplo, se muestra una solicitud POST mediante 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 muestra es el resultado de la ejecución correcta del ejemplo anterior. La primera entrada indica el éxito de la operación para crear un Paciente e incluye el ID del nuevo recurso. La segunda entrada indica el éxito de la operación para crear la observación y, además, incluye el ID del recurso nuevo.

{
  "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"
}