Gérer les ressources FHIR à l'aide de la bibliothèque de moteurs FHIR

1. Avant de commencer

Ce que vous allez faire

Dans cet atelier de programmation, vous allez créer une application Android à l'aide de la bibliothèque FHIR Engine. Votre application utilisera la bibliothèque FHIR Engine pour télécharger des ressources FHIR à partir d'un serveur FHIR et télécharger les modifications locales sur le serveur.

Points abordés

  • Créer un serveur FHIR HAPI local à l'aide de Docker
  • Intégrer la bibliothèque FHIR Engine à votre application Android
  • Comment utiliser l'API Sync pour configurer un job ponctuel ou périodique afin de télécharger et d'importer des ressources FHIR
  • Utiliser l'API Search
  • Comment utiliser les API d'accès aux données pour créer, lire, mettre à jour et supprimer des ressources FHIR en local

Prérequis

  • Docker (obtenir Docker)
  • Une version récente d'Android Studio (v4.1.2+)
  • Android Emulator ou un appareil Android physique fonctionnant sous Android 7.0 Nougat ou version ultérieure
  • Exemple de code
  • Vous disposez de connaissances de base en développement Android en Kotlin.

Si vous n'avez pas encore créé d'application Android, vous pouvez commencer par créer votre première application.

2. Configurer un serveur FHIR HAPI local avec des données de test

HAPI FHIR est un serveur FHIR Open Source populaire. Nous utilisons un serveur FHIR HAPI local dans notre atelier de programmation pour que l'application Android se connecte.

Configurer le serveur FHIR HAPI local

  1. Exécutez la commande suivante dans un terminal pour obtenir la dernière image de HAPI FHIR
    docker pull hapiproject/hapi:latest
    
  2. Créez un conteneur FHIR HAPI en utilisant Docker Desktop pour exécuter l'image précédemment téléchargée hapiproject/hapi ou en exécutant la commande suivante :
    docker run -p 8080:8080 hapiproject/hapi:latest
    
    En savoir plus
  3. Pour inspecter le serveur, ouvrez l'URL http://localhost:8080/ dans un navigateur. L'interface Web FHIR HAPI doit s'afficher.Interface Web FHIR HAPI

Insérer les données de test dans le serveur FHIR HAPI local

Pour tester notre application, nous avons besoin de données de test sur le serveur. Nous allons utiliser des données synthétiques générées par Synthea.

  1. Nous devons d'abord télécharger des exemples de données à partir de synthea-samples. Téléchargez et extrayez synthea_sample_data_fhir_r4_sep2019.zip. Les exemples de données décompressés contiennent de nombreux fichiers .json, chacun constituant un groupe de transactions pour un patient donné.
  2. Nous importerons les données de test de trois patients sur le serveur HAPI FHIR local. Exécutez la commande suivante dans le répertoire contenant les fichiers JSON
    curl -X POST -H "Content-Type: application/json" -d @./Aaron697_Brekke496_2fa15bc7-8866-461a-9000-f739e425860a.json http://localhost:8080/fhir/
    curl -X POST -H "Content-Type: application/json" -d @./Aaron697_Stiedemann542_41166989-975d-4d17-b9de-17f94cb3eec1.json http://localhost:8080/fhir/
    curl -X POST -H "Content-Type: application/json" -d @./Abby752_Kuvalis369_2b083021-e93f-4991-bf49-fd4f20060ef8.json http://localhost:8080/fhir/
    
  3. Pour importer les données de test de tous les patients sur le serveur, exécutez
    for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
    
    . Toutefois, cette opération peut prendre beaucoup de temps et n'est pas nécessaire pour l'atelier de programmation.
  4. Vérifiez que les données de test sont disponibles sur le serveur en ouvrant l'URL http://localhost:8080/fhir/Patient/ dans un navigateur. Le texte HTTP 200 OK et la section Response Body de la page contenant les données des patients dans un bundle FHIR doivent apparaître comme résultat de recherche avec un nombre de total.Tester les données sur le serveur

3. Configurer l'application Android

Télécharger le code

Pour télécharger le code de cet atelier de programmation, clonez le dépôt du SDK Android FHIR: git clone https://github.com/google/android-fhir.git

Le projet de démarrage de cet atelier de programmation se trouve dans codelabs/engine.

Importer l'application dans Android Studio

Commençons par importer l'application de démarrage dans Android Studio.

Ouvrez Android Studio, sélectionnez Import Project (Gradle, Eclipse ADT, etc.) (Importer un projet (Gradle, Eclipse ADT, etc.), puis sélectionnez le dossier codelabs/engine/ dans le code source que vous avez téléchargé précédemment.

Écran de démarrage d'Android Studio

Synchroniser votre projet avec les fichiers Gradle

Pour plus de commodité, les dépendances de la bibliothèque FHIR Engine ont déjà été ajoutées au projet. Cela vous permet d'intégrer la bibliothèque FHIR Engine à votre application. Observez les lignes suivantes à la fin du fichier app/build.gradle.kts de votre projet:

dependencies {
    // ...

    implementation("com.google.android.fhir:engine:0.1.0-beta05")
}

Pour vous assurer que toutes les dépendances sont disponibles pour votre application, synchronisez votre projet avec les fichiers Gradle à ce stade.

Sélectionnez Sync Project with Gradle Files (Synchroniser le projet avec les fichiers Gradle) (Bouton de synchronisation Gradle) dans la barre d'outils d'Android Studio. Vous pouvez également exécuter à nouveau l'application pour vérifier que les dépendances fonctionnent correctement.

Exécuter l'application de démarrage

Maintenant que vous avez importé le projet dans Android Studio, vous êtes prêt à exécuter l'application pour la première fois.

Lancez l'émulateur Android Studio, puis cliquez sur "Run" (Exécuter) (Bouton d'exécution) dans la barre d'outils d'Android Studio.

Application Hello World

4. Créer une instance FHIR Engine

Pour intégrer le moteur FHIR à votre application Android, vous devez utiliser la bibliothèque FHIR Engine et lancer une instance du moteur FHIR. Les étapes décrites ci-dessous vous guideront tout au long du processus.

  1. Accédez à la classe Application, qui dans cet exemple est FhirApplication.kt, située dans app/src/main/java/com/google/android/fhir/codelabs/engine.
  2. Dans la méthode onCreate(), ajoutez le code suivant pour initialiser FHIR Engine:
      FhirEngineProvider.init(
          FhirEngineConfiguration(
            enableEncryptionIfSupported = true,
            RECREATE_AT_OPEN,
            ServerConfiguration(
              baseUrl = "http://10.0.2.2:8080/fhir/",
              httpLogger =
                HttpLogger(
                  HttpLogger.Configuration(
                    if (BuildConfig.DEBUG) HttpLogger.Level.BODY else HttpLogger.Level.BASIC,
                  ),
                ) {
                  Log.d("App-HttpLog", it)
                },
            ),
          ),
      )
    
    Remarques:
    • enableEncryptionIfSupported: active le chiffrement des données si l'appareil est compatible.
    • RECREATE_AT_OPEN: détermine la stratégie d'erreur de la base de données. Dans ce cas, elle recrée la base de données si une erreur se produit à l'ouverture.
    • baseUrl dans ServerConfiguration: il s'agit de l'URL de base du serveur FHIR. L'adresse IP 10.0.2.2 fournie est spécialement réservée à localhost, accessible depuis Android Emulator. En savoir plus
  3. Dans la classe FhirApplication, ajoutez la ligne suivante pour instancier en différé le moteur FHIR:
      private val fhirEngine: FhirEngine by
          lazy { FhirEngineProvider.getInstance(this) }
    
    Ainsi, l'instance FhirEngine n'est créée que lors du premier accès, et non immédiatement au démarrage de l'application.
  4. Ajoutez la méthode pratique suivante à la classe FhirApplication pour faciliter l'accès à l'ensemble de votre application:
    companion object {
        fun fhirEngine(context: Context) =
            (context.applicationContext as FhirApplication).fhirEngine
    }
    
    Cette méthode statique vous permet de récupérer l'instance FHIR Engine n'importe où dans l'application en utilisant le contexte.

5. Synchroniser les données avec un serveur FHIR

  1. Créez une classe DownloadWorkManagerImpl.kt. Dans cette classe, vous allez définir la manière dont l'application extrait la ressource suivante de la liste à télécharger :
      class DownloadWorkManagerImpl : DownloadWorkManager {
        private val urls = LinkedList(listOf("Patient"))
    
        override suspend fun getNextRequest(): DownloadRequest? {
          val url = urls.poll() ?: return null
          return DownloadRequest.of(url)
        }
    
        override suspend fun getSummaryRequestUrls() = mapOf<ResourceType, String>()
    
        override suspend fun processResponse(response: Resource): Collection<Resource> {
          var bundleCollection: Collection<Resource> = mutableListOf()
          if (response is Bundle && response.type == Bundle.BundleType.SEARCHSET) {
            bundleCollection = response.entry.map { it.resource }
          }
          return bundleCollection
        }
      }
    
    Cette classe comporte une file d'attente de types de ressources qu'elle souhaite télécharger. Il traite les réponses et extrait les ressources du bundle renvoyé, qui sont enregistrées dans la base de données locale.
  2. Créer une classe AppFhirSyncWorker.kt. Cette classe définit la manière dont l'application se synchronisera avec le serveur FHIR distant à l'aide d'un nœud de calcul en arrière-plan.
    class AppFhirSyncWorker(appContext: Context, workerParams: WorkerParameters) :
      FhirSyncWorker(appContext, workerParams) {
    
      override fun getDownloadWorkManager() = DownloadWorkManagerImpl()
    
      override fun getConflictResolver() = AcceptLocalConflictResolver
    
      override fun getFhirEngine() = FhirApplication.fhirEngine(applicationContext)
    }
    
    Ici, nous avons défini le gestionnaire de téléchargement, le résolveur de conflit et l'instance de moteur FHIR à utiliser pour la synchronisation.
  3. Dans votre ViewModel, PatientListViewModel.kt, vous allez configurer un mécanisme de synchronisation unique. Recherchez le code suivant et ajoutez-le à la fonction triggerOneTimeSync():
    viewModelScope.launch {
          Sync.oneTimeSync<AppFhirSyncWorker>(getApplication())
            .shareIn(this, SharingStarted.Eagerly, 10)
            .collect { _pollState.emit(it) }
        }
    
    Cette coroutine lance une synchronisation unique avec le serveur FHIR à l'aide de l'AppFhirSyncWorker défini précédemment. L'interface utilisateur sera ensuite mise à jour en fonction de l'état du processus de synchronisation.
  4. Dans le fichier PatientListFragment.kt, mettez à jour le corps de la fonction handleSyncJobStatus:
    when (syncJobStatus) {
        is SyncJobStatus.Finished -> {
            Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show()
            viewModel.searchPatientsByName("")
        }
        else -> {}
    }
    
    Ici, une fois le processus de synchronisation terminé, un toast s'affiche pour avertir l'utilisateur. L'application affiche alors tous les patients en effectuant une recherche sans nom.

Maintenant que tout est configuré, exécutez votre application. Cliquez sur le bouton Sync dans le menu. Si tout fonctionne correctement, vous devriez voir les patients de votre serveur FHIR local être téléchargés et affichés dans l'application.

Liste des patients

6. Modifier et télécharger les données du patient

Dans cette section, nous allons vous guider tout au long du processus de modification des données des patients en fonction de critères spécifiques et de l'importation des données mises à jour sur votre serveur FHIR. Plus précisément, nous allons échanger les villes d'adresse pour les patients résidant dans Wakefield et Taunton.

Étape 1: Configurer la logique de modification dans PatientListViewModel

Le code de cette section est ajouté à la fonction triggerUpdate dans PatientListViewModel

  1. Accéder au moteur FHIR:commencez par obtenir une référence au moteur FHIR dans PatientListViewModel.kt.
    viewModelScope.launch {
       val fhirEngine = FhirApplication.fhirEngine(getApplication())
    
    Ce code lance une coroutine dans le champ d'application du ViewModel et initialise le moteur FHIR.
  2. Rechercher des patients depuis Wakefield:utilisez le moteur FHIR pour rechercher des patients dont la ville d'adresse est Wakefield.
    val patientsFromWakefield =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Wakefield"
             }
           )
         }
    
    Ici, nous utilisons la méthode search du moteur FHIR pour filtrer les patients en fonction de leur ville d'adresse. Le résultat sera une liste de patients de Wakefield.
  3. Rechercher des patients à Taunton:de la même manière, recherchez les patients dont la ville d'adresse est Taunton.
    val patientsFromTaunton =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Taunton"
             }
           )
         }
    
    Nous avons maintenant deux listes de patients, l'une de Wakefield et l'autre de Taunton.
  4. Modifier les adresses des patients:parcourez chaque patient dans la liste patientsFromWakefield, remplacez sa ville par Taunton et mettez-les à jour dans le moteur FHIR.
    patientsFromWakefield.forEach {
         it.resource.address.first().city = "Taunton"
         fhirEngine.update(it.resource)
    }
    
    De même, mettez à jour chaque patient de la liste patientsFromTaunton pour que sa ville soit définie sur Wakefield.
    patientsFromTaunton.forEach {
         it.resource.address.first().city = "Wakefield"
         fhirEngine.update(it.resource)
    }
    
  5. Lancer la synchronisation:après avoir modifié les données localement, déclenchez une synchronisation unique pour vous assurer qu'elles sont mises à jour sur le serveur FHIR.
    triggerOneTimeSync()
    }
    
    L'accolade fermante } indique la fin de la coroutine lancée au début.

Étape 2: Testez la fonctionnalité

  1. Test de l'interface utilisateur:exécutez votre application. Cliquez sur le bouton Update dans le menu. Vous devriez voir les adresses des patients Aaron697 et Abby752 échangés.
  2. Validation du serveur:ouvrez un navigateur et accédez à http://localhost:8080/fhir/Patient/. Vérifiez que la ville de l'adresse des patients Aaron697 et Abby752 est mise à jour sur le serveur FHIR local.

En suivant ces étapes, vous avez mis en place un mécanisme permettant de modifier les données des patients et de synchroniser les modifications avec votre serveur FHIR.

7. Rechercher des patients par nom

La recherche de patients par leur nom peut fournir un moyen convivial d'obtenir des informations. Nous allons vous guider tout au long du processus de mise en œuvre de cette fonctionnalité dans votre application.

Étape 1: Mettez à jour la signature de la fonction

Accédez au fichier PatientListViewModel.kt et recherchez la fonction nommée searchPatientsByName. Nous allons ajouter du code à cette fonction.

Pour filtrer les résultats en fonction de la requête de nom fournie et émettre les résultats pour que l'interface utilisateur soit mise à jour, intégrez le bloc de code conditionnel suivant:

    viewModelScope.launch {
      val fhirEngine = FhirApplication.fhirEngine(getApplication())
      if (nameQuery.isNotEmpty()) {
        val searchResult = fhirEngine.search<Patient> {
          filter(
            Patient.NAME,
            {
              modifier = StringFilterModifier.CONTAINS
              value = nameQuery
            },
          )
        }
        liveSearchedPatients.value  =  searchResult.map { it.resource }
      }
    }

Ici, si nameQuery n'est pas vide, la fonction de recherche filtre les résultats pour n'inclure que les patients dont les noms contiennent la requête spécifiée.

Étape 2: Testez la nouvelle fonctionnalité de recherche

  1. Relancez l'application:une fois ces modifications effectuées, recompilez et exécutez votre application.
  2. Rechercher des patients: utilisez la fonctionnalité de recherche dans la liste des patients. Vous devriez maintenant pouvoir saisir un nom (ou une partie d'un nom) pour filtrer la liste des patients en conséquence.

Une fois ces étapes terminées, vous avez amélioré votre application en permettant aux utilisateurs de rechercher efficacement les patients par leur nom. Cela peut considérablement améliorer l'expérience utilisateur et l'efficacité de la récupération des données.

8. Félicitations !

Vous avez utilisé la bibliothèque FHIR Engine pour gérer les ressources FHIR de votre application:

  • Utiliser l'API de synchronisation pour synchroniser des ressources FHIR avec un serveur FHIR
  • Utiliser l'API d'accès aux données pour créer, lire, mettre à jour et supprimer des ressources FHIR locales
  • Utiliser l'API Search pour rechercher des ressources FHIR locales

Points abordés

  • Comment configurer un serveur FHIR HAPI local
  • Comment importer des données de test sur le serveur FHIR HAPI local
  • Créer une application Android à l'aide de la bibliothèque FHIR Engine
  • Comment utiliser l'API de synchronisation, l'API d'accès aux données et l'API de recherche dans la bibliothèque FHIR Engine

Étapes suivantes

  • Consulter la documentation sur la bibliothèque FHIR Engine
  • Découvrez les fonctionnalités avancées de l'API Search
  • Appliquer la bibliothèque FHIR Engine à votre propre application Android

En savoir plus