Zarządzanie zasobami FHIR przy użyciu biblioteki silnika FHIR

1. Zanim zaczniesz

Co utworzysz

W ramach tego ćwiczenia w Codelabs utworzysz aplikację na Androida przy użyciu biblioteki FHIR Engine. Aplikacja użyje biblioteki silnika FHIR do pobrania zasobów FHIR z serwera FHIR i przesłania wszelkich lokalnych zmian na serwer.

Czego się nauczysz

  • Jak utworzyć lokalny serwer FHIR HAPI przy użyciu Dockera
  • Jak zintegrować bibliotekę FHIR silnika z aplikacją na Androida
  • Jak za pomocą interfejsu Sync API skonfigurować jednorazowe lub okresowe zadanie pobierania i przesyłania zasobów FHIR
  • Jak korzystać z interfejsu Search API
  • Jak używać interfejsów API dostępu do danych do lokalnego tworzenia, odczytywania, aktualizowania i usuwania zasobów FHIR

Czego potrzebujesz

Jeśli nie masz jeszcze aplikacji na Androida, możesz zacząć od stworzenia pierwszej aplikacji.

2. Skonfiguruj lokalny serwer FHIR HAPI z danymi testowymi

HAPI FHIR to popularny serwer FHIR typu open source. W ramach ćwiczenia w Codelabs używamy lokalnego serwera FHIR HAPI, aby połączyć się z aplikacją na Androida.

Konfigurowanie lokalnego serwera FHIR HAPI

  1. Uruchom poniższe polecenie w terminalu, aby uzyskać najnowszy obraz FHIR HAPI
    docker pull hapiproject/hapi:latest
    
  2. Utwórz kontener FHIR HAPI, korzystając z Docker Desktop do uruchomienia wcześniej pobranego obrazu hapiproject/hapi lub z następującego polecenia:
    docker run -p 8080:8080 hapiproject/hapi:latest
    
    Więcej informacji
  3. Sprawdź serwer, otwierając adres URL http://localhost:8080/ w przeglądarce. Powinien wyświetlić się interfejs internetowy HAPI FHIR.Interfejs internetowy HAPI FHIR

Wypełnij lokalny serwer FHIR HAPI danymi testowymi

Aby przetestować naszą aplikację, potrzebujemy danych testowych na serwerze. Użyjemy danych syntetycznych wygenerowanych przez firmę Synthea.

  1. Najpierw musimy pobrać przykładowe dane z przykładów syntetycznych. Pobierz i rozpakuj plik synthea_sample_data_fhir_r4_sep2019.zip. Rozpakowane przykładowe dane zawierają wiele plików .json, z których każdy jest pakietem transakcji dla pojedynczego pacjenta.
  2. Prześlemy dane testowe 3 pacjentów na lokalny serwer FHIR HAPI. Uruchom podane niżej polecenie w katalogu zawierającym pliki 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. Aby przesłać na serwer dane testowe wszystkich pacjentów, uruchom polecenie
    for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
    
    Może to jednak zająć dużo czasu i nie jest konieczne w przypadku ćwiczeń z programowania.
  4. Sprawdź, czy dane testowe są dostępne na serwerze, otwierając adres URL http://localhost:8080/fhir/Patient/ w przeglądarce. Powinny być widoczne teksty HTTP 200 OK i sekcja Response Body na stronie zawierającej dane pacjentów w pakiecie FHIR jako wynik wyszukiwania z liczbą total.Dane testowe na serwerze

3. Konfigurowanie aplikacji na Androida

Pobierz kod

Aby pobrać kod do tego ćwiczenia z programowania, skopiuj repozytorium pakietu SDK FHIR na Androida: git clone https://github.com/google/android-fhir.git

Projekt startowy tego ćwiczenia z programowania znajduje się w regionie codelabs/engine.

Importowanie aplikacji do Android Studio

Najpierw zaimportujemy aplikację startową do Android Studio.

Otwórz Android Studio, wybierz Importuj projekt (Gradle, Eclipse ADT itp.) i wybierz folder codelabs/engine/ z pobranego wcześniej kodu źródłowego.

Ekran startowy Android Studio

Synchronizowanie projektu z plikami Gradle

Dla Twojej wygody zależności biblioteki FHIR zostały już dodane do projektu. Pozwoli Ci to zintegrować bibliotekę silnika FHIR z aplikacją. Zwróć uwagę na te wiersze na końcu pliku app/build.gradle.kts projektu:

dependencies {
    // ...

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

Aby mieć pewność, że w przypadku aplikacji dostępne są wszystkie zależności, zsynchronizuj projekt z plikami Gradle.

Na pasku narzędzi Android Studio wybierz Sync Project with Gradle Files (Synchronizuj projekt z plikami Gradle) (Przycisk synchronizacji Gradle). Uruchomisz też aplikację jeszcze raz, aby sprawdzić, czy zależności działają prawidłowo.

Uruchom aplikację startową

Po zaimportowaniu projektu do Android Studio możesz uruchomić aplikację po raz pierwszy.

Uruchom emulator Android Studio i na pasku narzędzi Android Studio kliknij Uruchom (Przycisk Uruchom).

Aplikacja Hello World

4. Utwórz instancję silnika FHIR

Aby wdrożyć silnik FHIR w aplikacji na Androida, musisz użyć biblioteki silnika FHIR i zainicjować instancję silnika FHIR. Poniżej znajdziesz informacje o tym, jak to zrobić.

  1. Przejdź do klasy aplikacji, która w tym przykładzie to FhirApplication.kt, w lokalizacji app/src/main/java/com/google/android/fhir/codelabs/engine.
  2. W metodzie onCreate() dodaj ten kod, aby zainicjować silnik FHIR:
      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)
                },
            ),
          ),
      )
    
    Uwagi:
    • enableEncryptionIfSupported: włącza szyfrowanie danych, jeśli urządzenie obsługuje tę funkcję.
    • RECREATE_AT_OPEN: określa strategię dotyczącą błędów bazy danych. W takim przypadku, jeśli podczas otwierania wystąpi błąd, odtworzy bazę danych.
    • baseUrl w ServerConfiguration: to jest podstawowy adres URL serwera FHIR. Podany adres IP 10.0.2.2 jest specjalnie zarezerwowany dla hosta lokalnego i można uzyskać do niego dostęp za pomocą emulatora Androida. Więcej informacji
  3. W klasie FhirApplication dodaj ten wiersz, aby leniwie utworzyć instancję silnika FHIR:
      private val fhirEngine: FhirEngine by
          lazy { FhirEngineProvider.getInstance(this) }
    
    Dzięki temu instancja FhirEngine jest tworzona tylko przy pierwszym użyciu, a nie natychmiast po uruchomieniu aplikacji.
  4. Aby ułatwić dostęp do aplikacji w całej aplikacji, dodaj do klasy FhirApplication tę wygodną metodę:
    companion object {
        fun fhirEngine(context: Context) =
            (context.applicationContext as FhirApplication).fhirEngine
    }
    
    Ta metoda statyczna umożliwia pobieranie instancji silnika FHIR z dowolnego miejsca w aplikacji przy użyciu kontekstu.

5. Synchronizowanie danych z serwerem FHIR

  1. Utwórz nowe zajęcia DownloadWorkManagerImpl.kt. W tej klasie określisz, jak aplikacja będzie pobierać następny zasób z listy do pobrania:
      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
        }
      }
    
    Te zajęcia mają kolejkę typów zasobów, które chcą pobrać. Przetwarza odpowiedzi i wyodrębnia zasoby ze zwróconego pakietu, które są zapisywane w lokalnej bazie danych.
  2. Utwórz nową klasę AppFhirSyncWorker.kt Ta klasa określa sposób synchronizacji aplikacji ze zdalnym serwerem FHIR przy użyciu instancji roboczej w tle.
    class AppFhirSyncWorker(appContext: Context, workerParams: WorkerParameters) :
      FhirSyncWorker(appContext, workerParams) {
    
      override fun getDownloadWorkManager() = DownloadWorkManagerImpl()
    
      override fun getConflictResolver() = AcceptLocalConflictResolver
    
      override fun getFhirEngine() = FhirApplication.fhirEngine(applicationContext)
    }
    
    Zdefiniowaliśmy tu menedżera pobierania, narzędzie do rozwiązywania konfliktów i instancję silnika FHIR do synchronizacji.
  3. W modelu widoku danych PatientListViewModel.kt skonfigurujesz mechanizm jednorazowej synchronizacji. Znajdź i dodaj ten kod do funkcji triggerOneTimeSync():
    viewModelScope.launch {
          Sync.oneTimeSync<AppFhirSyncWorker>(getApplication())
            .shareIn(this, SharingStarted.Eagerly, 10)
            .collect { _pollState.emit(it) }
        }
    
    Ta współprogram inicjuje jednorazową synchronizację z serwerem FHIR przy użyciu zdefiniowanego wcześniej obiektu AppFhirSyncWorker. Następnie zaktualizuje interfejs na podstawie stanu procesu synchronizacji.
  4. W pliku PatientListFragment.kt zaktualizuj treść funkcji handleSyncJobStatus:
    when (syncJobStatus) {
        is SyncJobStatus.Finished -> {
            Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show()
            viewModel.searchPatientsByName("")
        }
        else -> {}
    }
    
    W tym miejscu po zakończeniu procesu synchronizacji zostanie wyświetlony toast z powiadomieniem dla użytkownika, a aplikacja wyświetli wszystkich pacjentów, wywołując wyszukiwanie z pustą nazwą.

Wszystko gotowe, uruchom aplikację. Kliknij przycisk Sync w menu. Jeśli wszystko działa prawidłowo, pacjentki z lokalnego serwera FHIR powinny być pobierane i wyświetlane w aplikacji.

Lista pacjentów

6. Modyfikowanie i przesyłanie danych pacjentów

W tej sekcji przeprowadzimy Cię przez proces modyfikowania danych pacjentów na podstawie określonych kryteriów i przesyłania zaktualizowanych danych na serwer FHIR. W szczególności zmienimy miasta adresowe w przypadku pacjentów mieszkających w tych miastach: Wakefield i Taunton.

Krok 1. Skonfiguruj logikę modyfikacji w PatientListViewModel

Kod z tej sekcji został dodany do funkcji triggerUpdate w PatientListViewModel

  1. Dostęp do silnika FHIR: zacznij od uzyskania odniesienia do silnika FHIR w PatientListViewModel.kt.
    viewModelScope.launch {
       val fhirEngine = FhirApplication.fhirEngine(getApplication())
    
    Ten kod uruchamia współrzędną w zakresie ViewModel i inicjuje silnik FHIR.
  2. Wyszukiwanie pacjentów z Wakefield: użyj silnika FHIR do wyszukania pacjentów z miastem adresowym Wakefield.
    val patientsFromWakefield =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Wakefield"
             }
           )
         }
    
    W tym przypadku używamy metody search mechanizmu FHIR do filtrowania pacjentów na podstawie ich miasta adresowego. Wynikiem będzie lista pacjentów z Wakefield.
  3. Wyszukiwanie pacjentów z Taunton: analogicznie, wyszukaj pacjentów z miastem adresowym Taunton.
    val patientsFromTaunton =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Taunton"
             }
           )
         }
    
    Mamy teraz dwie listy pacjentów – jedną z Wakefielda i drugą z Tunton.
  4. Modyfikuj adresy pacjentów:przejrzyj każdego pacjenta na liście patientsFromWakefield, zmień jego miasto na Taunton i zaktualizuj go w silniku FHIR.
    patientsFromWakefield.forEach {
         it.resource.address.first().city = "Taunton"
         fhirEngine.update(it.resource)
    }
    
    W podobny sposób zaktualizuj nazwę każdego pacjenta na liście patientsFromTaunton, tak aby jego miejscowość została zmieniona na Wakefield.
    patientsFromTaunton.forEach {
         it.resource.address.first().city = "Wakefield"
         fhirEngine.update(it.resource)
    }
    
  5. Zainicjuj synchronizację: po lokalnej modyfikacji danych uruchom jednorazową synchronizację, aby mieć pewność, że dane zostaną zaktualizowane na serwerze FHIR.
    triggerOneTimeSync()
    }
    
    Nawias zamykający } oznacza koniec współprogramu uruchomionego na początku.

Krok 2. Przetestuj funkcje

  1. Testowanie interfejsu:uruchom aplikację. Kliknij przycisk Update w menu. Powinny wyświetlić się zamienione miasta adresowe pacjenta Aaron697 i Abby752.
  2. Weryfikacja serwera:otwórz przeglądarkę i wejdź na stronę http://localhost:8080/fhir/Patient/. Sprawdź, czy miasto adresowe pacjentów Aaron697 i Abby752 jest zaktualizowane na lokalnym serwerze FHIR.

Dzięki wykonaniu tych czynności udało Ci się wdrożyć mechanizm modyfikacji danych pacjentów i synchronizowania zmian z serwerem FHIR.

7. Wyszukaj pacjentów według imienia i nazwiska

Wyszukiwanie pacjentów według ich imion i nazwisk może stanowić łatwy w obsłudze sposób pobierania informacji. Przeprowadzimy Cię przez proces wdrażania tej funkcji w aplikacji.

Krok 1. Zaktualizuj podpis funkcji

Przejdź do pliku PatientListViewModel.kt i znajdź funkcję o nazwie searchPatientsByName. Dodamy do tej funkcji kod.

Aby filtrować wyniki na podstawie podanego zapytania o nazwę i przesyłać wyniki do aktualizacji interfejsu użytkownika, uwzględnij ten warunkowy blok kodu:

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

W tym przypadku, jeśli pole nameQuery nie jest puste, funkcja wyszukiwania przefiltruje wyniki, aby uwzględnić tylko pacjentów, których imiona i nazwiska zawierają określone zapytanie.

Krok 2. Przetestuj nową funkcję wyszukiwania

  1. Uruchom ponownie aplikację:po wprowadzeniu tych zmian przebuduj i uruchom aplikację.
  2. Wyszukiwanie pacjentów: na ekranie z listą pacjentów użyj funkcji wyszukiwania. Możesz teraz wpisać imię i nazwisko (lub ich część), aby odpowiednio przefiltrować listę pacjentów.

Po wykonaniu tych czynności aplikacja została wzbogacona o możliwość efektywnego wyszukiwania pacjentów według ich imion i nazwisk. Może to znacznie zwiększyć wygodę użytkowników i efektywność pobierania danych.

8. Gratulacje!

Biblioteka silnika FHIR została przez Ciebie użyta do zarządzania zasobami FHIR w aplikacji:

  • Używanie interfejsu Sync API do synchronizowania zasobów FHIR z serwerem FHIR
  • Używanie interfejsu Data Access API do tworzenia, odczytywania, aktualizowania i usuwania lokalnych zasobów FHIR
  • Użyj interfejsu Search API do wyszukiwania lokalnych zasobów FHIR

Omówione zagadnienia

  • Jak skonfigurować lokalny serwer FHIR HAPI
  • Jak przesłać dane testowe na lokalny serwer FHIR HAPI
  • Jak utworzyć aplikację na Androida przy użyciu biblioteki FHIR Engine
  • Jak używać interfejsów API synchronizacji, interfejsu Data Access API i Search API w bibliotece wyszukiwarki FHIR

Następne kroki

  • Zapoznaj się z dokumentacją biblioteki FHIR
  • Poznaj zaawansowane funkcje interfejsu Search API
  • Zastosuj bibliotekę FHIR Engine we własnej aplikacji na Androida

Więcej informacji