Importa y exporta recursos de FHIR con Cloud Storage

En esta página, se explica cómo importar y exportar recursos de FHIR desde y hacia Cloud Storage mediante los métodos projects.locations.datasets.fhirStores.import y projects.locations.datasets.fhirStores.export.

Según el formato de tus datos de FHIR, para cargar datos en una tienda de FHIR, puedes usar el método projects.locations.datasets.fhirStores.import o el método projects.locations.datasets.fhirStores.fhir.executeBundle. Para obtener orientación sobre cómo elegir un método, consulta Importación de FHIR.

Configura permisos de Cloud Storage

Antes de importar y exportar recursos de FHIR desde y hacia Cloud Storage, debes otorgar permisos adicionales a la cuenta de servicio del agente de servicios de Cloud Healthcare. Para obtener más información, consulta Permisos de Cloud Storage de la tienda de FHIR.

Genera datos simulados de pacientes

Synthea™ es un simulador que sirve para generar datos de población de pacientes. Si no usas Synthea™ para generar datos de población de pacientes, ve a Importa recursos de FHIR o Exporta recursos de FHIR.

Solo puedes importar datos en la versión que tu tienda de FHIR se configuró para aceptar.

Para descargar e instalar Synthea™, completa los siguientes pasos:

  1. Clona el repositorio de la herramienta de Synthea™ desde GitHub:

    git clone https://github.com/synthetichealth/synthea.git
    
  2. Completa los pasos de instalación.

Continúa con una de las siguientes secciones para generar datos de una versión específica de FHIR:

Genera datos simulados de pacientes para R4

De forma predeterminada, los datos generados de Synthea™ usan la representación JSON de FHIR R4 para los recursos. Para generar datos de FHIR R4 de Synthea™ e importarlos a una tienda de FHIR de la API de Cloud Healthcare, completa los siguientes pasos:

  1. Sigue las instrucciones para generar datos de pacientes sintéticos. Los datos generados se envían a synthea/output/fhir_r4 para FHIR R4.

  2. Copia los datos generados en un bucket de Cloud Storage para poder importarlos a una tienda de FHIR de la API de Cloud Healthcare. Por ejemplo, para copiar los datos a un directorio llamado synthea-data en un depósito de Cloud Storage existente, ejecuta el siguiente comando gcloud storage cp desde el directorio synthea:

    gcloud storage cp output/fhir_r4/* gs://BUCKET/synthea-data
  3. Sigue las instrucciones para importar recursos de FHIR.

Genera datos de pacientes simulados para DSTU2 o STU3

Para generar datos de FHIR DSTU2 o STU3 de Synthea™ e importarlos a una tienda de FHIR de la API de Cloud Healthcare, completa los siguientes pasos:

  1. Desde el directorio de synthea, usa un editor de texto para abrir el archivo src/main/resources/synthea.properties y, luego, realiza los siguientes cambios, según si generas datos DSTU2 o STU3.

    Para generar datos de FHIR STU3, haz lo siguiente:

    • Configura todos los valores *.fhir.export y *.fhir_dstu2.export como false.
    • Configura todos los valores *.fhir_stu3.export como verdadero.

    Para generar datos de FHIR DSTU2, haz lo siguiente:

    • Configura todos los valores *.fhir.export y *.fhir_stu3.export como false.
    • Configura todos los valores *.fhir_dstu2.export como verdadero.

    Por ejemplo, para generar datos de FHIR STU3, haz lo siguiente:

    exporter.fhir.export = false
    exporter.fhir_stu3.export = true
    exporter.fhir_dstu2.export = false
    
    exporter.hospital.fhir.export = false
    exporter.hospital.fhir_stu3.export = true
    exporter.hospital.fhir_dstu2.export = false
    
    exporter.practitioner.fhir.export = false
    exporter.practitioner.fhir_stu3.export = true
    exporter.practitioner.fhir_dstu2.export = false
  2. Sigue las instrucciones para generar datos de pacientes sintéticos. Los datos generados se envían a synthea/output/fhir_stu3 para FHIR STU3 o al directorio synthea/output/fhir_dstu2 para FHIR DSTU2.

  3. Copia los datos generados en un bucket de Cloud Storage para poder importarlos a una tienda de FHIR de la API de Cloud Healthcare. Por ejemplo, para copiar los datos a un directorio llamado synthea-data en un depósito de Cloud Storage existente, ejecuta el siguiente comando gcloud storage cp desde el directorio synthea:

    gcloud storage cp output/fhir_stu3/* gs://BUCKET/synthea-data
  4. Sigue las instrucciones para importar recursos de FHIR.

Importa recursos de FHIR

Cuando configures el cuerpo de la solicitud de importación, configura ContentStructure en uno de los siguientes valores:

  • CONTENT_STRUCTURE_UNSPECIFIED
  • BUNDLE: el archivo de origen contiene una o más líneas de JSON delimitado por saltos de línea (ndjson). Cada línea es un paquete que contiene uno o más recursos. Si no especificas ContentStructure, el valor predeterminado será BUNDLE.
  • RESOURCE: el archivo de origen contiene una o más líneas de JSON delimitado por saltos de línea (ndjson). Cada línea es un solo recurso.
  • BUNDLE_PRETTY: el archivo completo de origen es un paquete JSON. El JSON puede abarcar varias líneas.
  • RESOURCE_PRETTY: el archivo completo de origen es un recurso JSON. El JSON puede abarcar varias líneas.

Por ejemplo, supongamos que importas un archivo llamado resources.ndjson con el siguiente contenido:

{"class":{"code":"IMP","display":"inpatient encounter","system":"http://hl7.org/fhir/v3/ActCode"},"id":"6090e773-3e91-40a7-8fce-1e22f6774c29","reason":[{"text":"The patient had an abnormal heart rate. She was concerned about this."}],"resourceType":"Encounter","status":"finished","subject":{"reference":"Patient/2938bb9e-1f16-429e-8d44-9508ab0e4151"}}
{"class":{"code":"IMP","display":"inpatient encounter","system":"http://hl7.org/fhir/v3/ActCode"},"id":"7101f884-4f02-51b8-9gdf-2f33g7885d30","reason":[{"text":"The patient was experiencing recurrent fevers."}],"resourceType":"Encounter","status":"finished","subject":{"reference":"Patient/3049cc0f-2g27-530f-9e55-0619bc1f5262"}}
{"birthDate":"1970-01-01","gender":"female","id":"2938bb9e-1f16-429e-8d44-9508ab0e4151","name":[{"family":"Smith","given":["Darcy"],"use":"official"}],"resourceType":"Patient"}

El archivo contiene dos recursos Encounter y un recurso Patient. Cada recurso está en una línea separada, por lo que debes configurar ContentStructure como RESOURCE.

Es posible que tus datos se importen de forma incorrecta o que no se importen si es que ContentStructure no coincide con el formato de tus datos. Por ejemplo, el archivo de muestra anterior no se importará correctamente a menos que ContentStructure se configure como RESOURCE en la solicitud de importación.

En los siguientes ejemplos, se muestra cómo importar recursos de FHIR desde un bucket de Cloud Storage.

Console

Para importar recursos de FHIR desde un bucket de Cloud Storage, completa los siguientes pasos:

  1. En la consola de Google Cloud, ve a la página Conjuntos de datos.
    Ir a Conjuntos de datos
  2. Haz clic en el conjunto de datos que contiene el almacén de FHIR al que importas los recursos de FHIR.
  3. En la lista de almacenes de datos, selecciona Importar en la lista Acciones para el almacén de FHIR.

    Aparecerá la página Importa al almacén de FHIR.
  4. En la lista Proyecto, selecciona un proyecto de Cloud Storage.
  5. En la lista Ubicación, selecciona un depósito de Cloud Storage.
  6. En Configuración de importación de FHIR, selecciona la estructura de contenido relevante.
  7. Haz clic en Importar para importar recursos de FHIR.
  8. Para seguir el estado de la operación, haz clic en la pestaña Operaciones. Una vez que se completa la operación, aparecerán las siguientes indicaciones:
    • La sección Estado de la operación de larga duración tiene una marca de verificación verde debajo del encabezado Aceptar.
    • La sección Descripción general tiene una marca de verificación verde y un indicador Aceptar en la misma fila que el ID de la operación.
    Si encuentras algún error, haz clic en Acciones y, luego, en Ver detalles en Cloud Logging.

gcloud

Para importar recursos de FHIR a una tienda de FHIR, usa el comando gcloud healthcare fhir-stores import gcs. Especifica la siguiente información:

  • El nombre del conjunto de datos superior
  • El nombre de la tienda de FHIR
  • La ubicación del objeto en un bucket de Cloud Storage. La ubicación de los archivos dentro del bucket es arbitraria y no necesita adherirse exactamente al formato especificado en el siguiente ejemplo. Cuando especificas la ubicación de los recursos de FHIR en Cloud Storage, puedes usar comodines para importar varios archivos desde uno o más directorios. Se admiten los siguientes comodines:
    • Usa * para hacer coincidir 0 o más caracteres sin separadores. Por ejemplo, gs://BUCKET/DIRECTORY/Example*.ndjson coincide con Example.ndjson y Example22.ndjson en DIRECTORY.
    • Usa ** para hacer coincidir 0 o más caracteres (con separadores). Se debe usar al final de una ruta y no debe haber otros comodines en la ruta. También se puede usar con una extensión de nombre de archivo (como .ndjson), que importa todos los archivos con la extensión de nombre de archivo en el directorio especificado y en sus subdirectorios. Por ejemplo, gs://BUCKET/DIRECTORY/**.ndjson importa todos los archivos con la extensión de nombre de archivo .ndjson en DIRECTORY y en sus subdirectorios.
    • Usa ? para hacer coincidir 1 carácter. Por ejemplo, gs://BUCKET/DIRECTORY/Example?.ndjson coincide con Example1.ndjson, pero no coincide con Example.ndjson ni Example01.ndjson.

En el siguiente ejemplo, se muestra el comando gcloud healthcare fhir-stores import gcs.

gcloud healthcare fhir-stores import gcs FHIR_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --gcs-uri=gs://BUCKET/DIRECTORY/FHIR_RESOURCE_NAME.ndjson

Para especificar la estructura de los archivos de origen de FHIR, usa la marca --content-structure.

La línea de comandos muestra el ID de la operación y, después de que se completa la operación, done:

Request issued for: [FHIR_STORE_ID]
Waiting for operation [OPERATION_ID] to complete...done.
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID

Para ver más detalles de la operación, ejecuta el comando gcloud healthcare operations describe y proporciona el OPERATION_ID de la respuesta:

gcloud healthcare operations describe OPERATION_ID \
  --dataset=DATASET_ID

En la respuesta, se incluye done: true.

done: true
metadata:
'@type': type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata
apiMethodName: google.cloud.healthcare.v1.fhir.FhirService.ImportResources
createTime: 'CREATE_TIME'
endTime: 'END_TIME'
logsUrl: https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL,
counter:
  success: 'SUCCESS_COUNT' 
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID
response:
'@type': type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ImportResourcesResponse
fhirStore: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID

API

Para importar recursos de FHIR a una tienda de FHIR, usa el método projects.locations.datasets.fhirStores.import.

  • La ubicación de los archivos dentro del bucket es arbitraria y no necesita adherirse exactamente al formato especificado en los siguientes ejemplos.
  • Cuando especificas la ubicación de los recursos de FHIR en Cloud Storage, puedes usar comodines para importar varios archivos desde uno o más directorios. Se admiten los siguientes comodines:
    • Usa * para hacer coincidir 0 o más caracteres sin separadores. Por ejemplo, gs://BUCKET/DIRECTORY/Example*.ndjson coincide con Example.ndjson y Example22.ndjson en DIRECTORY.
    • Usa ** para hacer coincidir 0 o más caracteres (con separadores). Se debe usar al final de una ruta y no debe haber otros comodines en la ruta. También se puede usar con una extensión de nombre de archivo (como .ndjson), que importa todos los archivos con la extensión de nombre de archivo en el directorio especificado y en sus subdirectorios. Por ejemplo, gs://BUCKET/DIRECTORY/**.ndjson importa todos los archivos con la extensión de nombre de archivo .ndjson en DIRECTORY y en sus subdirectorios.
    • Usa ? para hacer coincidir 1 carácter. Por ejemplo, gs://BUCKET/DIRECTORY/Example?.ndjson coincide con Example1.ndjson, pero no coincide con Example.ndjson ni Example01.ndjson.

curl

Para importar recursos de FHIR a una tienda de FHIR, realiza una solicitud POST y especifica la siguiente información:

  • El nombre del conjunto de datos superior
  • El nombre de la tienda de FHIR
  • La ubicación del objeto en un bucket de Cloud Storage
  • Un token de acceso

En el siguiente ejemplo, se muestra cómo importar un solo archivo con el uso de una solicitud POST mediante curl.

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    --data "{
      'contentStructure': 'CONTENT_STRUCTURE',
      'gcsSource': {
        'uri': 'gs://BUCKET/DIRECTORY/FHIR_RESOURCE_FILE'
      }
    }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:import"

Si la solicitud tiene éxito, se mostrará la respuesta en formato JSON en el servidor:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

La respuesta contiene un nombre de operación. Para realizar un seguimiento del estado de la operación, puedes usar el método get de la operación:

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

Si la solicitud es exitosa, el servidor mostrará una respuesta con el estado de la operación en formato JSON:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ImportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ImportResourcesResponse",
  }
}

PowerShell

Para importar recursos de FHIR a una tienda de FHIR, realiza una solicitud POST y especifica la siguiente información:

  • El nombre del conjunto de datos superior
  • El nombre de la tienda de FHIR
  • La ubicación del objeto en un bucket de 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-WebRequest `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/json; charset=utf-8" `
  -Body "{
    'contentStructure': 'CONTENT_STRUCTURE',
    'gcsSource': {
      'uri': 'gs://BUCKET/DIRECTORY/FHIR_RESOURCE_FILE'
    }
  }" `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:import" | Select-Object -Expand Content

Si la solicitud tiene éxito, se mostrará la respuesta en formato JSON en el servidor:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

La respuesta contiene un nombre de operación. Para realizar un seguimiento del estado de la operación, puedes usar el método get de la operación:

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

Invoke-WebRequest `
  -Method Get `
  -Headers $headers `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID" | Select-Object -Expand Content

Si la solicitud es exitosa, el servidor mostrará una respuesta con el estado de la operación en formato JSON:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ImportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ImportResourcesResponse",
  }
}

Go

import (
	"context"
	"fmt"
	"io"
	"time"

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

// importsFHIRResource imports an FHIR resource.
func importFHIRResource(w io.Writer, projectID, location, datasetID, fhirStoreID, gcsURI string) error {
	ctx := context.Background()

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

	storesService := healthcareService.Projects.Locations.Datasets.FhirStores

	name := fmt.Sprintf("projects/%s/locations/%s/datasets/%s/fhirStores/%s", projectID, location, datasetID, fhirStoreID)
	req := &healthcare.ImportResourcesRequest{
		ContentStructure: "RESOURCE",
		GcsSource: &healthcare.GoogleCloudHealthcareV1FhirGcsSource{
			Uri: gcsURI,
		},
	}

	op, err := storesService.Import(name, req).Do()
	if err != nil {
		return fmt.Errorf("Import: %w", err)
	}

	operationsService := healthcareService.Projects.Locations.Datasets.Operations
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
			newOp, err := operationsService.Get(op.Name).Do()
			if err != nil {
				return fmt.Errorf("operationsService.Get(%q): %v", op.Name, err)
			}
			if newOp.Done {
				if newOp.Error != nil {
					return fmt.Errorf("import operation %q completed with error: %s", op.Name, newOp.Error.Details)
				}
				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.CloudHealthcare.Projects.Locations.Datasets.FhirStores;
import com.google.api.services.healthcare.v1.CloudHealthcareScopes;
import com.google.api.services.healthcare.v1.model.GoogleCloudHealthcareV1FhirGcsSource;
import com.google.api.services.healthcare.v1.model.ImportResourcesRequest;
import com.google.api.services.healthcare.v1.model.Operation;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.Collections;

public class FhirStoreImport {
  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 fhirStoreImport(String fhirStoreName, String gcsUri) throws IOException {
    // String fhirStoreName =
    //    String.format(
    //        FHIR_NAME, "your-project-id", "your-region-id", "your-dataset-id", "your-fhir-id");
    // String gcsUri = "gs://your-bucket-id/path/to/destination/dir"

    // Initialize the client, which will be used to interact with the service.
    CloudHealthcare client = createClient();

    // Configure where the store should be imported from.
    GoogleCloudHealthcareV1FhirGcsSource gcsSource =
        new GoogleCloudHealthcareV1FhirGcsSource().setUri(gcsUri);
    ImportResourcesRequest importRequest = new ImportResourcesRequest().setGcsSource(gcsSource);

    // Create request and configure any parameters.
    FhirStores.CloudHealthcareImport request =
        client
            .projects()
            .locations()
            .datasets()
            .fhirStores()
            .healthcareImport(fhirStoreName, importRequest);

    // Execute the request, wait for the operation to complete, and process the results.
    try {
      Operation operation = request.execute();
      while (operation.getDone() == null || !operation.getDone()) {
        // Update the status of the operation with another request.
        Thread.sleep(500); // Pause for 500ms between requests.
        operation =
            client
                .projects()
                .locations()
                .datasets()
                .operations()
                .get(operation.getName())
                .execute();
      }
      System.out.println("FHIR store import complete: " + operation.getResponse());
    } catch (Exception ex) {
      System.out.printf("Error during request execution: %s", ex.toString());
      ex.printStackTrace(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();
  }
}

Node.js

const google = require('@googleapis/healthcare');
const healthcare = google.healthcare({
  version: 'v1',
  auth: new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  }),
});
const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

const importFhirResources = async () => {
  // 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 gcsUri = 'my-bucket/my-directory/*.json'
  const name = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/fhirStores/${fhirStoreId}`;
  const request = {
    name,
    resource: {
      contentStructure: 'RESOURCE',
      gcsSource: {
        uri: `gs://${gcsUri}`,
      },
    },
  };

  const operation =
    await healthcare.projects.locations.datasets.fhirStores.import(request);
  const operationName = operation.data.name;

  const operationRequest = {name: operationName};

  // Wait twenty seconds for the LRO to finish.
  await sleep(20000);

  // Check the LRO's status
  const operationStatus =
    await healthcare.projects.locations.datasets.operations.get(
      operationRequest
    );

  const success = operationStatus.data.metadata.counter.success;

  if (typeof success !== 'undefined') {
    console.log(
      `Import FHIR resources succeeded. ${success} resources imported.`
    );
  } else {
    console.log(
      'Imported FHIR resources failed. Details available in Cloud Logging at the following URL:\n',
      operationStatus.data.metadata.logsUrl
    );
  }
};

importFhirResources();

Python

def import_fhir_resources(project_id, location, dataset_id, fhir_store_id, gcs_uri):
    """Import resources into the FHIR store by copying them from the
    specified source.

    See https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/healthcare/api-client/v1/fhir
    before running the sample."""
    # Imports the Google API Discovery Service.
    from googleapiclient import discovery

    api_version = "v1"
    service_name = "healthcare"
    # Instantiates an authorized API client by discovering the Healthcare API
    # and using GOOGLE_APPLICATION_CREDENTIALS environment variable.
    client = discovery.build(service_name, api_version)

    # 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
    # gcs_uri = 'my-bucket'  # replace with a Cloud Storage bucket
    fhir_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, location, dataset_id
    )
    fhir_store_name = f"{fhir_store_parent}/fhirStores/{fhir_store_id}"

    body = {
        "contentStructure": "CONTENT_STRUCTURE_UNSPECIFIED",
        "gcsSource": {"uri": f"gs://{gcs_uri}"},
    }

    # Escape "import()" method keyword because "import"
    # is a reserved keyword in Python
    request = (
        client.projects()
        .locations()
        .datasets()
        .fhirStores()
        .import_(name=fhir_store_name, body=body)
    )

    response = request.execute()
    print(f"Imported FHIR resources: {gcs_uri}")

    return response

Exporta recursos de FHIR

En los siguientes ejemplos, se muestra cómo exportar recursos de FHIR a un bucket de Cloud Storage. Cuando exportas recursos de FHIR desde una tienda de FHIR, se exportan todos los recursos de la tienda de FHIR.

Si exportas recursos de FHIR según un programa, considera exportar tus datos de forma incremental. Para obtener instrucciones, consulta Exportaciones incrementales.

Durante la exportación, la API de Cloud Healthcare crea un archivo para cada tipo de recurso de la tienda de FHIR. El nombre del archivo consta del ID de la operación y el tipo de recurso separados por un guion bajo. Cada archivo consiste en un JSON delimitado por saltos de línea, en el que cada línea es un recurso de FHIR correspondiente al tipo de recurso en el nombre de archivo. Por ejemplo, si exportas varios registros de pacientes, el archivo de salida se llamará similar a 1264567891234567_Patient y contendrá una línea para cada recurso de paciente desde el almacén de FHIR.

Console

Para exportar recursos de FHIR a Cloud Storage, completa los siguientes pasos:

  1. En la consola de Google Cloud, ve a la página Conjuntos de datos.
    Ir a Conjuntos de datos
  2. Haz clic en el conjunto de datos que contiene el almacén de FHIR del que exportas los recursos de FHIR.
  3. En la lista de almacenes de datos, selecciona Exportar de la lista Acciones lista para el almacén de FHIR.

    Aparecerá la página Exporta recursos de FHIR.
  4. Selecciona Depósito de Google Cloud Storage.
  5. En la lista Proyecto, selecciona un proyecto de Cloud Storage.
  6. En la lista Ubicación, selecciona un depósito de Cloud Storage.
  7. Haz clic en Exportar para exportar recursos FHIR a la ubicación definida en Cloud Storage.
  8. Para seguir el estado de la operación, haz clic en la pestaña Operaciones. Una vez que se completa la operación, aparecerán las siguientes indicaciones:
    • La sección Estado de la operación de larga duración tiene una marca de verificación verde debajo del encabezado Aceptar.
    • La sección Descripción general tiene una marca de verificación verde y un indicador Aceptar en la misma fila que el ID de la operación.
    Si encuentras algún error, haz clic en Acciones y, luego, en Ver detalles en Cloud Logging.

gcloud

Para exportar los recursos de FHIR a un bucket de Cloud Storage, usa el comando gcloud healthcare fhir-stores export gcs. Especifica la siguiente información:

  • El nombre del conjunto de datos superior
  • El nombre del almacén FHIR
  • Es el nombre del proyecto superior.
  • El bucket o el directorio de Cloud Storage de destino Escribe en un bucket o un directorio de Cloud Storage, en lugar de en un objeto, ya que la API de Cloud Healthcare crea un objeto para cada tipo de recurso. Cada objeto consiste en un JSON delimitado por saltos de línea, en el que cada línea es un recurso de FHIR. Si especificas un directorio que no existe, se creará.
  • Una marca opcional, --resource-type, que solo exporta tipos de recursos específicos, definidos como una lista separada por comas de uno o más tipos de recursos de FHIR
  • Una marca opcional, --since, que solo exporta recursos actualizados después de un momento específico, definidos como YYYY-MM-DDThh:mm:ss.sss+zz:zz

En el siguiente ejemplo, se muestra el comando gcloud healthcare fhir-stores export gcs.

gcloud healthcare fhir-stores export gcs FHIR_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --project=PROJECT_ID
  --gcs-uri=gs://BUCKET/DIRECTORY

La línea de comandos muestra el ID de la operación:

Waiting for operation [OPERATION_ID] to complete...done.
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID

Para ver el estado de la operación, ejecuta el comando gcloud healthcare operations describe y proporciona el OPERATION_ID de la respuesta:

gcloud healthcare operations describe OPERATION_ID \
  --dataset=DATASET_ID

Una vez que se completa el comando, se incluirá done en la respuesta.

metadata:
'@type': type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata
apiMethodName: google.cloud.healthcare.v1.fhir.FhirService.ExportFhirData
createTime: "CREATE_TIME"
endTime: "END_TIME"
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID
response:
'@type': type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ExportResourcesResponse
fhirStore: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID
resourceCount: 'RESOURCE_COUNT'

API

Para exportar recursos de FHIR, usa el método projects.locations.datasets.fhirStores.export.

  • Escribe en un bucket o un directorio de Cloud Storage, en lugar de en un objeto, ya que la API de Cloud Healthcare crea un archivo JSON delimitado por saltos de línea para cada tipo de recurso. En cada archivo JSON, cada línea es un recurso de FHIR.
  • Si el comando especifica un directorio que no existe, este se creará.

curl

Para exportar recursos de FHIR, realiza una solicitud POST y especifica la siguiente información:

  • El nombre del conjunto de datos superior
  • El nombre de la tienda de FHIR
  • El bucket de destino de Cloud Storage
  • Un token de acceso
  • Un campo opcional, _type, que solo exporta tipos de recursos específicos, definidos como una lista separada por comas de uno o más tipos de recursos de FHIR
  • Un campo opcional, _since, que solo exporta recursos actualizados después de un momento específico, definidos como YYYY-MM-DDThh:mm:ss.sss+zz:zz

En el siguiente ejemplo, se muestra una solicitud POST mediante curl.

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    --data "{
      'gcsDestination': {
        'uriPrefix': 'gs://BUCKET/DIRECTORY'
      },
    }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:export"

Si la solicitud tiene éxito, se mostrará la respuesta en formato JSON en el servidor:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

La respuesta contiene un nombre de operación. Para realizar un seguimiento del estado de la operación, puedes usar el método get de la operación:

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

Si la solicitud es exitosa, el servidor mostrará una respuesta con el estado de la operación en formato JSON:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ExportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ExportResourcesResponse",
  }
}

PowerShell

Para exportar recursos de FHIR, realiza una solicitud POST y especifica la siguiente información:

  • El nombre del conjunto de datos superior
  • El nombre de la tienda de FHIR
  • El bucket o el directorio de Cloud Storage de destino Escribe en un bucket o un directorio de Cloud Storage, en lugar de en un objeto, ya que la API de Cloud Healthcare crea un objeto para cada tipo de recurso. Cada objeto consiste en un JSON delimitado por saltos de línea, en el que cada línea es un recurso de FHIR.
  • Un token de acceso
  • Un campo opcional, _type, que solo exporta tipos de recursos específicos, definidos como una lista separada por comas de uno o más tipos de recursos de FHIR
  • Un campo opcional, _since, que solo exporta recursos actualizados después de un momento específico, definidos como YYYY-MM-DDThh:mm:ss.sss+zz:zz

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-WebRequest `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/json; charset=utf-8" `
  -Body "{
    'gcsDestination': {
      'uriPrefix': 'gs://BUCKET/DIRECTORY'
    },
  }" `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:export" | Select-Object -Expand Content

Si la solicitud tiene éxito, se mostrará la respuesta en formato JSON en el servidor:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

La respuesta contiene un nombre de operación. Para realizar un seguimiento del estado de la operación, puedes usar el método get de la operación:

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

Invoke-WebRequest `
  -Method Get `
  -Headers $headers `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID" | Select-Object -Expand Content

Si la solicitud es exitosa, el servidor mostrará una respuesta con el estado de la operación en formato JSON:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ExportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ExportResourcesResponse",
  }
}

Go

import (
	"context"
	"fmt"
	"io"
	"time"

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

// exportFHIRResource exports the resources in the FHIR store.
func exportFHIRResource(w io.Writer, projectID, location, datasetID, fhirStoreID, gcsURIPrefix string) error {
	ctx := context.Background()

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

	storesService := healthcareService.Projects.Locations.Datasets.FhirStores

	name := fmt.Sprintf("projects/%s/locations/%s/datasets/%s/fhirStores/%s", projectID, location, datasetID, fhirStoreID)
	req := &healthcare.ExportResourcesRequest{
		GcsDestination: &healthcare.GoogleCloudHealthcareV1FhirGcsDestination{
			UriPrefix: gcsURIPrefix,
		},
	}

	op, err := storesService.Export(name, req).Do()
	if err != nil {
		return fmt.Errorf("Export: %w", err)
	}

	operationsService := healthcareService.Projects.Locations.Datasets.Operations
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
			newOp, err := operationsService.Get(op.Name).Do()
			if err != nil {
				return fmt.Errorf("operationsService.Get(%q): %v", op.Name, err)
			}
			if newOp.Done {
				if newOp.Error != nil {
					return fmt.Errorf("export operation %q completed with error: %v", op.Name, newOp.Error)
				}
				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.CloudHealthcare.Projects.Locations.Datasets.FhirStores;
import com.google.api.services.healthcare.v1.CloudHealthcareScopes;
import com.google.api.services.healthcare.v1.model.ExportResourcesRequest;
import com.google.api.services.healthcare.v1.model.GoogleCloudHealthcareV1FhirGcsDestination;
import com.google.api.services.healthcare.v1.model.Operation;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.Collections;

public class FhirStoreExport {
  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 fhirStoreExport(String fhirStoreName, String gcsUri) throws IOException {
    // String fhirStoreName =
    //    String.format(
    //        FHIR_NAME, "your-project-id", "your-region-id", "your-dataset-id", "your-fhir-id");
    // String gcsUri = "gs://your-bucket-id/path/to/destination/dir"

    // Initialize the client, which will be used to interact with the service.
    CloudHealthcare client = createClient();

    // Configure where the store will be exported too.
    GoogleCloudHealthcareV1FhirGcsDestination gcsDestination =
        new GoogleCloudHealthcareV1FhirGcsDestination().setUriPrefix(gcsUri);
    ExportResourcesRequest exportRequest =
        new ExportResourcesRequest().setGcsDestination(gcsDestination);

    // Create request and configure any parameters.
    FhirStores.Export request =
        client.projects().locations().datasets().fhirStores().export(fhirStoreName, exportRequest);

    // Execute the request, wait for the operation to complete, and process the results.
    try {
      Operation operation = request.execute();
      while (operation.getDone() == null || !operation.getDone()) {
        // Update the status of the operation with another request.
        Thread.sleep(500); // Pause for 500ms between requests.
        operation =
            client
                .projects()
                .locations()
                .datasets()
                .operations()
                .get(operation.getName())
                .execute();
      }
      System.out.println("Fhir store export complete." + operation.getResponse());
    } catch (Exception ex) {
      System.out.printf("Error during request execution: %s", ex.toString());
      ex.printStackTrace(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();
  }
}

Node.js

const google = require('@googleapis/healthcare');
const healthcare = google.healthcare({
  version: 'v1',
  auth: new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  }),
});
const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

const exportFhirResourcesGcs = async () => {
  // 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 gcsUri = 'my-bucket/my-directory'
  const name = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/fhirStores/${fhirStoreId}`;
  const request = {
    name,
    resource: {
      gcsDestination: {
        // The destination location in Cloud Storage for the FHIR resources
        uriPrefix: `gs://${gcsUri}`,
      },
    },
  };

  const operation =
    await healthcare.projects.locations.datasets.fhirStores.export(request);
  const operationName = operation.data.name;

  // Wait ten seconds for the LRO to finish
  await sleep(10000);

  // Check the LRO's status
  const operationStatus =
    await healthcare.projects.locations.datasets.operations.get({
      name: operationName,
    });

  if (typeof operationStatus.data.metadata.counter !== 'undefined') {
    console.log('Exported FHIR resources successfully');
  } else {
    console.log('Export failed');
  }
};

exportFhirResourcesGcs();

Python

def export_fhir_store_gcs(project_id, location, dataset_id, fhir_store_id, gcs_uri):
    """Export resources to a Google Cloud Storage bucket by copying
    them from the FHIR store.

    See https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/healthcare/api-client/v1/fhir
    before running the sample."""
    # Imports the Google API Discovery Service.
    from googleapiclient import discovery

    api_version = "v1"
    service_name = "healthcare"
    # Instantiates an authorized API client by discovering the Healthcare API
    # and using GOOGLE_APPLICATION_CREDENTIALS environment variable.
    client = discovery.build(service_name, api_version)

    # 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
    # gcs_uri = 'my-bucket' # replace with a Cloud Storage bucket
    fhir_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, location, dataset_id
    )
    fhir_store_name = f"{fhir_store_parent}/fhirStores/{fhir_store_id}"

    body = {"gcsDestination": {"uriPrefix": f"gs://{gcs_uri}/fhir_export"}}

    request = (
        client.projects()
        .locations()
        .datasets()
        .fhirStores()
        .export(name=fhir_store_name, body=body)
    )

    response = request.execute()
    print(f"Exported FHIR resources to bucket: gs://{gcs_uri}")

    return response

Exportaciones incrementales

Puedes especificar una marca de tiempo para solo exportar los recursos de FHIR agregados a tu almacén de FHIR desde una exportación anterior que se realizó correctamente. Esto mejora el rendimiento y evita el costo de volver a exportar toda la tienda de FHIR, a la vez que garantiza que tus datos exportados siempre estén actualizados.

Cuando llames a fhirStores.export, especifica la marca de tiempo en el campo _since.

Soluciona problemas de solicitudes de importación y exportación de FHIR

Si ocurren errores durante una solicitud de importación o exportación de FHIR, estos se registrarán en Cloud Logging. Para obtener más información, consulta Visualiza los registros de errores en Cloud Logging.

Si toda la operación muestra un error, consulta Solución de problemas de operaciones de larga duración.

¿Qué sigue?