Importer et exporter des ressources FHIR à l'aide de Cloud Storage

Cette page explique comment exporter et importer des ressources FHIR depuis et vers Cloud Storage à l'aide des méthodes projects.locations.datasets.fhirStores.import et projects.locations.datasets.fhirStores.export.

Selon le format de vos données FHIR, vous pouvez utiliser la méthode projects.locations.datasets.fhirStores.import ou projects.locations.datasets.fhirStores.fhir.executeBundle pour charger des données dans un datastore FHIR. Pour obtenir des conseils sur le choix d'une méthode, consultez la section Importation FHIR.

Définir des autorisations Cloud Storage

Avant d'importer des ressources FHIR depuis Cloud Storage ou de les exporter vers ce service, vous devez accorder des autorisations supplémentaires au compte de service Agent de service Cloud Healthcare. Pour en savoir plus, consultez la section Autorisations Cloud Storage pour les datastores FHIR.

Générer des données patient simulées

Synthea™ est un simulateur permettant de générer les données patients pour une population donnée. Si vous n'utilisez pas SyntheaTM pour générer des données patients pour une population donnée, passez à la section Importer des ressources FHIR ou Exporter des ressources FHIR.

Vous ne pouvez importer des données que dans la version acceptée par la configuration de votre datastore FHIR.

Pour télécharger et installer SyntheaTM, procédez comme suit :

  1. Clonez le dépôt de l'outil Synthea™ à partir de GitHub :

    git clone https://github.com/synthetichealth/synthea.git
    
  2. Suivez la procédure d'installation.

Passez à l'une des sections suivantes pour générer des données pour une version FHIR spécifique :

Générer des données patient simulées pour R4

Par défaut, les données Synthea™ générées utilisent la représentation des ressources JSON FHIR R4. Pour générer des données Synthea™ FHIR R4 et les importer dans un magasin FHIR de l'API Cloud Healthcare, procédez comme suit :

  1. Suivez les instructions pour générer des données patient synthétiques. Les données générées sont envoyées à synthea/output/fhir_r4 pour FHIR R4.

  2. Copiez les données générées dans un bucket Cloud Storage afin de pouvoir les importer dans un datastore FHIR de l'API Cloud Healthcare. Par exemple, pour copier les données dans un répertoire appelé synthea-data dans un bucket Cloud Storage existant, exécutez la commande gcloud storage cp suivante à partir du répertoire synthea :

    gcloud storage cp output/fhir_r4/* gs://BUCKET/synthea-data
  3. Suivez les instructions pour importer des ressources FHIR.

Générer des données patient simulées pour la spécification DSTU2 ou STU3

Pour générer des données Synthea™ FHIR DSTU2 ou STU3, puis les importer dans un magasin FHIR de l'API Cloud Healthcare, procédez comme suit :

  1. Dans le répertoire synthea, utilisez un éditeur de texte pour ouvrir le fichier src/main/resources/synthea.properties, puis apportez les modifications suivantes, selon que vous générez des données DSTU2 ou STU3.

    Pour générer des données FHIR STU3 :

    • Définissez toutes les valeurs *.fhir.export et *.fhir_dstu2.export sur false.
    • Définissez toutes les valeurs *.fhir_stu3.export sur "true".

    Pour générer des données FHIR DSTU2 :

    • Définissez toutes les valeurs *.fhir.export et *.fhir_stu3.export sur false.
    • Définissez toutes les valeurs *.fhir_dstu2.export sur "true".

    Par exemple, pour générer des données FHIR STU3 :

    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. Suivez les instructions pour générer des données patient synthétiques. Les données générées sont envoyées à synthea/output/fhir_stu3 pour FHIR STU3 ou au répertoire synthea/output/fhir_dstu2 pour FHIR DSTU2.

  3. Copiez les données générées dans un bucket Cloud Storage afin de pouvoir les importer dans un datastore FHIR de l'API Cloud Healthcare. Par exemple, pour copier les données dans un répertoire appelé synthea-data dans un bucket Cloud Storage existant, exécutez la commande gcloud storage cp suivante à partir du répertoire synthea :

    gcloud storage cp output/fhir_stu3/* gs://BUCKET/synthea-data
  4. Suivez les instructions pour importer des ressources FHIR.

Importer des ressources FHIR

Lorsque vous configurez le corps de la requête d'importation, définissez l'élément ContentStructure sur l'une des valeurs suivantes :

  • CONTENT_STRUCTURE_UNSPECIFIED
  • BUNDLE : le fichier source contient une ou plusieurs lignes de fichier JSON (ndjson) délimitées par un retour à la ligne. Chaque ligne correspond à un groupe contenant une ou plusieurs ressources. Si vous ne spécifiez pas ContentStructure, la valeur par défaut est BUNDLE.
  • RESOURCE : le fichier source contient une ou plusieurs lignes de fichier JSON (ndjson) délimitées par un retour à la ligne. Chaque ligne est une ressource unique.
  • BUNDLE_PRETTY : l'intégralité du fichier source est un groupe JSON. Le fichier JSON peut s'étendre sur plusieurs lignes.
  • RESOURCE_PRETTY : l'intégralité du fichier source est une ressource JSON. Le fichier JSON peut s'étendre sur plusieurs lignes.

Par exemple, supposons que vous importiez un fichier nommé resources.ndjson avec le contenu suivant :

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

Le fichier contient deux ressources "Encounter" et une ressource "Patient". Chaque ressource se trouve sur une ligne distincte. Vous devez donc définir ContentStructure sur RESOURCE.

Les données risquent de ne pas être importées correctement ou pas du tout si ContentStructure ne correspond pas au format de vos données. Par exemple, le fichier ci-dessus ne sera pas importé correctement, sauf si ContentStructure est défini sur RESOURCE dans la requête d'importation.

Les exemples suivants montrent comment importer des ressources FHIR depuis un bucket Cloud Storage.

Console

Pour importer des ressources FHIR à partir d'un bucket Cloud Storage, procédez comme suit :

  1. Dans la console Google Cloud, accédez à la page Ensembles de données.
    Accéder à la page "Ensembles de données"
  2. Cliquez sur l'ensemble de données contenant le store FHIR dans lequel vous importez des ressources FHIR.
  3. Dans la liste de datastores, sélectionnez Importer dans la liste Actions du magasin FHIR.

    La page Importation dans le magasin FHIR s'affiche.
  4. Dans la liste Projet, sélectionnez un projet Cloud Storage.
  5. Dans la liste Emplacement, sélectionnez un bucket Cloud Storage.
  6. Dans Paramètres d'importation FHIR, sélectionnez la structure de contenu appropriée.
  7. Cliquez sur Importer pour importer des ressources FHIR.
  8. Pour suivre l'état de l'opération, cliquez sur l'onglet Opérations. Une fois l'opération terminée, les indications suivantes s'affichent :
    • La section État de l'opération de longue durée est représentée par une coche verte sous l'en-tête OK.
    • La section Présentation comporte une coche verte et un indicateur OK sur la même ligne que l'ID de l'opération.
    Si vous rencontrez des erreurs, cliquez sur Actions, puis sur Afficher les détails dans Cloud Logging.

gcloud

Pour importer des ressources FHIR dans un datastore FHIR, utilisez la commande gcloud healthcare fhir-stores import gcs. Spécifiez les informations suivantes :

  • Nom de l'ensemble de données parent
  • Le nom du datastore FHIR
  • Emplacement de l'objet dans un bucket Cloud Storage. L'emplacement des fichiers dans le bucket est arbitraire et ne doit pas nécessairement respecter exactement le format spécifié dans l'exemple suivant. Lorsque vous spécifiez l'emplacement des ressources FHIR dans Cloud Storage, vous pouvez importer plusieurs fichiers depuis un ou plusieurs répertoires au moyen de caractères génériques. Les caractères génériques suivants sont acceptés :
    • Utilisez * pour correspondre à 0 ou plusieurs caractères non séparateurs. Par exemple, gs://BUCKET/DIRECTORY/Example*.ndjson correspond à "Example.ndjson" et "Example22.ndjson" dans DIRECTORY.
    • Utilisez ** pour correspondre à 0 caractère ou plus (séparateurs compris). Doit être utilisé à la fin d'un chemin d'accès et sans autres caractères génériques. Peut également être utilisé avec une extension de nom de fichier (.ndjson, par exemple), qui importe tous les fichiers portant l'extension dans le répertoire spécifié et ses sous-répertoires. Par exemple, gs://BUCKET/DIRECTORY/**.ndjson importe tous les fichiers portant l'extension .ndjson dans DIRECTORY et ses sous-répertoires.
    • Utilisez ? pour correspondre à 1 caractère. Par exemple, gs://BUCKET/DIRECTORY/Example?.ndjson correspond à "Example1.ndjson", mais ne correspond pas à "Example.ndjson" ou "Example01.ndjson".

L'exemple suivant montre la commande 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

Pour spécifier la structure des fichiers sources FHIR, utilisez l'option --content-structure.

La ligne de commande affiche l'ID de l'opération et, une fois l'opération terminée, 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

Pour afficher plus de détails sur l'opération, exécutez la commande gcloud healthcare operations describe en fournissant le OPERATION_ID spécifié dans la réponse :

gcloud healthcare operations describe OPERATION_ID \
  --dataset=DATASET_ID

La réponse inclut 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

Pour importer des ressources FHIR dans un magasin FHIR, utilisez la méthode projects.locations.datasets.fhirStores.import.

  • L'emplacement des fichiers dans le bucket est arbitraire et ne doit pas nécessairement respecter exactement le format spécifié dans les exemples suivants.
  • Lorsque vous spécifiez l'emplacement des ressources FHIR dans Cloud Storage, vous pouvez importer plusieurs fichiers depuis un ou plusieurs répertoires au moyen de caractères génériques. Les caractères génériques suivants sont acceptés :
    • Utilisez * pour correspondre à 0 ou plusieurs caractères non séparateurs. Par exemple, gs://BUCKET/DIRECTORY/Example*.ndjson correspond à "Example.ndjson" et "Example22.ndjson" dans DIRECTORY.
    • Utilisez ** pour correspondre à 0 caractère ou plus (séparateurs compris). Doit être utilisé à la fin d'un chemin d'accès et sans autres caractères génériques. Peut également être utilisé avec une extension de nom de fichier (.ndjson, par exemple), qui importe tous les fichiers portant l'extension dans le répertoire spécifié et ses sous-répertoires. Par exemple, gs://BUCKET/DIRECTORY/**.ndjson importe tous les fichiers portant l'extension .ndjson dans DIRECTORY et ses sous-répertoires.
    • Utilisez ? pour correspondre à 1 caractère. Par exemple, gs://BUCKET/DIRECTORY/Example?.ndjson correspond à "Example1.ndjson", mais ne correspond pas à "Example.ndjson" ou "Example01.ndjson".

curl

Pour importer des ressources FHIR dans un datastore FHIR, envoyez une requête POST et spécifiez les informations suivantes :

  • Nom de l'ensemble de données parent
  • Le nom du datastore FHIR
  • L'emplacement de l'objet dans un bucket Cloud Storage
  • Un jeton d'accès

L'exemple suivant montre comment importer un seul fichier à l'aide d'une requête POST à l'aide de 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 requête aboutit, le serveur renvoie la réponse au format JSON :

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

La réponse contient un nom d'opération. Pour suivre l'état de l'opération, vous pouvez utiliser la méthode get :

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 requête aboutit, le serveur renvoie une réponse avec l'état de l'opération au format 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

Pour importer des ressources FHIR dans un datastore FHIR, envoyez une requête POST et spécifiez les informations suivantes :

  • Nom de l'ensemble de données parent
  • Le nom du datastore FHIR
  • L'emplacement de l'objet dans un bucket Cloud Storage
  • Un jeton d'accès

L'exemple suivant montre une requête POST utilisant 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 requête aboutit, le serveur renvoie la réponse au format JSON :

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

La réponse contient un nom d'opération. Pour suivre l'état de l'opération, vous pouvez utiliser la méthode get :

$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 requête aboutit, le serveur renvoie une réponse avec l'état de l'opération au format 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

Exporter des ressources FHIR

Les exemples suivants montrent comment exporter des ressources FHIR vers un bucket Cloud Storage. Lorsque vous exportez des ressources FHIR depuis un datastore FHIR, toutes les ressources qu'il contient sont exportées.

Si vous exportez des ressources FHIR de manière planifiée, envisagez d'exporter vos données de manière incrémentielle. Pour savoir comment procéder, consultez Exporter des données de manière incrémentielle.

Lors de l'exportation, l'API Cloud Healthcare crée un fichier pour chaque type de ressource à partir du store FHIR. Le nom de fichier se compose de l'ID de l'opération et du type de ressource, séparés par un trait de soulignement. Chaque fichier est constitué d'un fichier JSON délimité par des retours à la ligne, où chaque ligne est une ressource FHIR correspondant au type de ressource dans le nom de fichier. Par exemple, si vous exportez plusieurs enregistrements Patient, le fichier de sortie sera appelé 1264567891234567_Patient ou quelque chose de semblable et contiendra une ligne pour chaque ressource Patient du store FHIR.

Console

Pour exporter des ressources FHIR vers Cloud Storage, procédez comme suit :

  1. Dans la console Google Cloud, accédez à la page Ensembles de données.
    Accéder à la page "Ensembles de données"
  2. Cliquez sur l'ensemble de données contenant le store FHIR à partir duquel vous exportez des ressources FHIR.
  3. Dans la liste des datastores, sélectionnez Exporter dans la liste Actions du magasin FHIR.

    La page Exporter des ressources FHIR s'affiche.
  4. Sélectionnez Bucket Google Cloud Storage.
  5. Dans la liste Projet, sélectionnez un projet Cloud Storage.
  6. Dans la liste Emplacement, sélectionnez un bucket Cloud Storage.
  7. Cliquez sur Exporter pour exporter des ressources FHIR vers l'emplacement défini dans Cloud Storage.
  8. Pour suivre l'état de l'opération, cliquez sur l'onglet Opérations. Une fois l'opération terminée, les indications suivantes s'affichent :
    • La section État de l'opération de longue durée est représentée par une coche verte sous l'en-tête OK.
    • La section Présentation comporte une coche verte et un indicateur OK sur la même ligne que l'ID de l'opération.
    Si vous rencontrez des erreurs, cliquez sur Actions, puis sur Afficher les détails dans Cloud Logging.

gcloud

Pour exporter des ressources FHIR vers un bucket Cloud Storage, utilisez la commande gcloud healthcare fhir-stores export gcs. Spécifiez les informations suivantes :

  • Nom de l'ensemble de données parent
  • Le nom du magasin FHIR
  • Nom du projet parent
  • Le bucket ou le répertoire Cloud Storage de destination. Écrivez dans un bucket ou un répertoire Cloud Storage plutôt que dans un objet, car l'API Cloud Healthcare crée un objet pour chaque type de ressource. Chaque objet est constitué d'un fichier JSON délimité par des retours à la ligne, où chaque ligne est une ressource FHIR. Si vous spécifiez un répertoire qui n'existe pas, celui-ci est créé.
  • Option facultative, --resource-type, qui n'exporte que des types de ressources spécifiques, définis comme une liste d'un ou de plusieurs types de ressources FHIR séparés par une virgule
  • Option facultative, --since, qui n'exporte que les ressources mises à jour après un délai spécifique, défini par YYYY-MM-DDThh:mm:ss.sss+zz:zz

L'exemple suivant montre la commande 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 ligne de commande affiche l'ID de l'opération :

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

Pour afficher l'état de l'opération, exécutez la commande gcloud healthcare operations describe en fournissant le OPERATION_ID spécifié dans la réponse :

gcloud healthcare operations describe OPERATION_ID \
  --dataset=DATASET_ID

Une fois la commande terminée, la réponse inclut done.

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

Pour exporter des ressources FHIR, utilisez la méthode projects.locations.datasets.fhirStores.export.

  • Écrivez dans un bucket ou un répertoire Cloud Storage plutôt que dans un objet, car l'API Cloud Healthcare crée un fichier JSON délimité par des retours à la ligne pour chaque type de ressource. Dans chaque fichier JSON, chaque ligne est une ressource FHIR.
  • Si la commande spécifie un répertoire qui n'existe pas, celui-ci est créé.

curl

Pour exporter des ressources FHIR, envoyez une requête POST et spécifiez les informations suivantes :

  • Nom de l'ensemble de données parent
  • Le nom du datastore FHIR
  • Le bucket Cloud Storage de destination
  • Un jeton d'accès
  • Champ facultatif, _type, qui n'exporte que des types de ressources spécifiques, définis comme une liste d'un ou de plusieurs types de ressources FHIR séparés par une virgule
  • Champ facultatif, _since, qui n'exporte que les ressources mises à jour après un délai spécifique, défini par YYYY-MM-DDThh:mm:ss.sss+zz:zz.

L'exemple suivant montre une requête POST utilisant 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 requête aboutit, le serveur renvoie la réponse au format JSON :

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

La réponse contient un nom d'opération. Pour suivre l'état de l'opération, vous pouvez utiliser la méthode get :

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 requête aboutit, le serveur renvoie une réponse avec l'état de l'opération au format 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

Pour exporter des ressources FHIR, envoyez une requête POST et spécifiez les informations suivantes :

  • Nom de l'ensemble de données parent
  • Le nom du datastore FHIR
  • Le bucket ou le répertoire Cloud Storage de destination. Écrivez dans un bucket ou un répertoire Cloud Storage plutôt que dans un objet, car l'API Cloud Healthcare crée un objet pour chaque type de ressource. Chaque objet est constitué d'un fichier JSON délimité par des retours à la ligne, où chaque ligne est une ressource FHIR.
  • Un jeton d'accès
  • Champ facultatif, _type, qui n'exporte que des types de ressources spécifiques, définis comme une liste d'un ou de plusieurs types de ressources FHIR séparés par une virgule
  • Champ facultatif, _since, qui n'exporte que les ressources mises à jour après un délai spécifique, défini par YYYY-MM-DDThh:mm:ss.sss+zz:zz.

L'exemple suivant montre une requête POST utilisant 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 requête aboutit, le serveur renvoie la réponse au format JSON :

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

La réponse contient un nom d'opération. Pour suivre l'état de l'opération, vous pouvez utiliser la méthode get :

$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 requête aboutit, le serveur renvoie une réponse avec l'état de l'opération au format 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

Exportations incrémentielles

Vous pouvez spécifier un code temporel pour n'exporter que les ressources FHIR ajoutées à votre magasin FHIR depuis une exportation précédente réussie. Cela améliore les performances et évite le coût de réexportation de l'ensemble du magasin FHIR, tout en vous assurant que vos données exportées sont toujours à jour.

Lorsque vous appelez fhirStores.export, spécifiez le code temporel dans le champ _since.

Résoudre les problèmes liés à l'importation et l'exportation de requêtes FHIR

Si des erreurs se produisent lors d'une requête d'importation ou d'exportation FHIR, elles sont consignées dans Cloud Logging. Pour en savoir plus, consultez la section Afficher les journaux d'erreurs dans Cloud Logging.

Si l'ensemble de l'opération renvoie une erreur, consultez la section Résoudre les problèmes d'opérations de longue durée.

Étape suivante