مدیریت منابع FHIR با استفاده از کتابخانه موتور FHIR

۱. قبل از شروع

آنچه خواهید ساخت

در این آزمایشگاه کد، شما یک برنامه اندروید با استفاده از کتابخانه موتور FHIR خواهید ساخت. برنامه شما از کتابخانه موتور FHIR برای دانلود منابع FHIR از یک سرور FHIR و آپلود هرگونه تغییرات محلی به سرور استفاده خواهد کرد.

آنچه یاد خواهید گرفت

  • نحوه ایجاد یک سرور محلی HAPI FHIR با استفاده از Docker
  • نحوه ادغام کتابخانه موتور FHIR در برنامه اندروید شما
  • نحوه استفاده از API همگام‌سازی برای تنظیم یک کار یکباره یا دوره‌ای برای دانلود و آپلود منابع FHIR
  • نحوه استفاده از API جستجو
  • نحوه استفاده از API های دسترسی به داده برای ایجاد، خواندن، به‌روزرسانی و حذف منابع FHIR به صورت محلی

آنچه نیاز دارید

اگر قبلاً برنامه‌های اندروید نساخته‌اید، می‌توانید با ساخت اولین برنامه خود شروع کنید.

۲. یک سرور محلی HAPI FHIR با داده‌های آزمایشی راه‌اندازی کنید

HAPI FHIR یک سرور FHIR متن‌باز محبوب است. ما از یک سرور محلی HAPI FHIR در آزمایشگاه کد خود برای اتصال برنامه اندروید استفاده می‌کنیم.

سرور محلی HAPI FHIR را راه‌اندازی کنید

  1. برای دریافت آخرین ایمیج HAPI FHIR، دستور زیر را در ترمینال اجرا کنید.
    docker pull hapiproject/hapi:latest
    
  2. با استفاده از Docker Desktop برای اجرای تصویر hapiproject/hapi که قبلاً دانلود کرده‌اید، یا با اجرای دستور زیر، یک کانتینر HAPI FHIR ایجاد کنید.
    docker run -p 8080:8080 hapiproject/hapi:latest
    
    بیشتر بدانید.
  3. با باز کردن آدرس http://localhost:8080/ در مرورگر، سرور را بررسی کنید. باید رابط وب HAPI FHIR را ببینید. HAPI FHIR web interface

سرور محلی HAPI FHIR را با داده‌های آزمایشی پر کنید

برای آزمایش برنامه‌مان، به مقداری داده آزمایشی روی سرور نیاز داریم. ما از داده‌های مصنوعی تولید شده توسط Synthea استفاده خواهیم کرد.

  1. ابتدا، باید داده‌های نمونه را از synthea-samples دانلود کنیم. فایل synthea_sample_data_fhir_r4_sep2019.zip را دانلود و استخراج کنید. داده‌های نمونه‌ی از حالت فشرده خارج شده دارای فایل‌های .json متعددی هستند که هر کدام یک بسته‌ی تراکنش برای یک بیمار خاص هستند.
  2. ما داده‌های آزمایش سه بیمار را به سرور محلی HAPI FHIR آپلود خواهیم کرد. دستور زیر را در دایرکتوری حاوی فایل‌های 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. برای آپلود داده‌های آزمایش برای همه بیماران به سرور، دستور زیر را اجرا کنید:
    for f in *.json; do curl -X POST -H "Content-Type: application/json" -d @$f http://localhost:8080/fhir/ ; done
    
    با این حال، تکمیل این کار می‌تواند مدت زیادی طول بکشد و برای آزمایشگاه کد ضروری نیست.
  4. با باز کردن آدرس اینترنتی http://localhost:8080/fhir/Patient/ در مرورگر، تأیید کنید که داده‌های آزمایشی روی سرور موجود است. باید متن HTTP 200 OK و بخش Response Body صفحه حاوی داده‌های بیمار در یک FHIR Bundle را به عنوان نتیجه جستجو به همراه تعداد total مشاهده کنید. داده‌های آزمایشی روی سرور

۳. برنامه اندروید را تنظیم کنید

کد را دانلود کنید

برای دانلود کد این آزمایشگاه کد، مخزن Android FHIR SDK را کلون کنید: git clone https://github.com/google/android-fhir.git

پروژه اولیه این codelab در codelabs/engine قرار دارد.

وارد کردن برنامه به اندروید استودیو

ما با وارد کردن برنامه اولیه به اندروید استودیو شروع می‌کنیم.

اندروید استودیو را باز کنید، گزینه‌ی Import Project (Gradle، Eclipse ADT و غیره) را انتخاب کنید و پوشه‌ی codelabs/engine/ را از کد منبعی که قبلاً دانلود کرده‌اید، انتخاب کنید.

Android Studio start screen

پروژه خود را با فایل‌های Gradle همگام‌سازی کنید

برای راحتی شما، وابستگی‌های کتابخانه موتور FHIR از قبل به پروژه اضافه شده‌اند. این به شما امکان می‌دهد کتابخانه موتور FHIR را در برنامه خود ادغام کنید. خطوط زیر را در انتهای فایل app/build.gradle.kts پروژه خود مشاهده کنید:

dependencies {
    // ...

    implementation("com.google.android.fhir:engine:1.1.0")
}

برای اطمینان از اینکه همه وابستگی‌ها برای برنامه شما در دسترس هستند، باید پروژه خود را در این مرحله با فایل‌های gradle همگام‌سازی کنید.

پروژه همگام‌سازی با فایل‌های Gradle را انتخاب کنید ( Gradle sync button ) از نوار ابزار اندروید استودیو. همچنین می‌توانید برنامه را دوباره اجرا کنید تا بررسی کنید که وابستگی‌ها به درستی کار می‌کنند.

برنامه شروع کننده را اجرا کنید

حالا که پروژه را به اندروید استودیو وارد کرده‌اید، آماده‌اید تا برای اولین بار برنامه را اجرا کنید.

شبیه‌ساز اندروید استودیو را اجرا کنید و روی Run (اجرا) کلیک کنید. Run button ) در نوار ابزار اندروید استودیو.

برنامه سلام دنیا

۴. ایجاد نمونه موتور FHIR

برای گنجاندن موتور FHIR در برنامه اندروید خود، باید از کتابخانه موتور FHIR استفاده کنید و یک نمونه از موتور FHIR را راه‌اندازی کنید. مراحل ذکر شده در زیر شما را در این فرآیند راهنمایی می‌کند.

  1. به کلاس Application خود بروید که در این مثال FhirApplication.kt است و در مسیر app/src/main/java/com/google/android/fhir/codelabs/engine قرار دارد.
  2. درون متد onCreate() ، کد زیر را برای مقداردهی اولیه موتور 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)
                },
            ),
          ),
      )
    
    یادداشت‌ها:
    • enableEncryptionIfSupported : در صورت پشتیبانی دستگاه، رمزگذاری داده‌ها را فعال می‌کند.
    • RECREATE_AT_OPEN : استراتژی خطای پایگاه داده را تعیین می‌کند. در این حالت، اگر هنگام باز کردن خطایی رخ دهد، پایگاه داده را دوباره ایجاد می‌کند.
    • baseUrl در ServerConfiguration : این URL پایه سرور FHIR است. آدرس IP ارائه شده 10.0.2.2 به طور ویژه برای localhost رزرو شده است که از شبیه ساز اندروید قابل دسترسی است. اطلاعات بیشتر .
  3. در کلاس FhirApplication ، خط زیر را برای نمونه‌سازی تنبل از موتور FHIR اضافه کنید:
      private val fhirEngine: FhirEngine by
          lazy { FhirEngineProvider.getInstance(this) }
    
    این تضمین می‌کند که نمونه FhirEngine فقط زمانی ایجاد می‌شود که برای اولین بار به آن دسترسی پیدا می‌شود، نه بلافاصله پس از شروع برنامه.
  4. برای دسترسی آسان‌تر در سراسر برنامه، متد راحتی زیر را در کلاس FhirApplication اضافه کنید:
    companion object {
        fun fhirEngine(context: Context) =
            (context.applicationContext as FhirApplication).fhirEngine
    }
    
    این متد استاتیک به شما امکان می‌دهد نمونه موتور FHIR را از هر کجای برنامه با استفاده از context بازیابی کنید.

۵. همگام‌سازی داده‌ها با سرور FHIR

  1. یک کلاس جدید DownloadWorkManagerImpl.kt ایجاد کنید. در این کلاس، نحوه‌ی دریافت منبع بعدی از لیست برای دانلود توسط برنامه را تعریف خواهید کرد:
      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
        }
      }
    
    این کلاس صفی از انواع منابع دارد که می‌خواهد دانلود کند. این کلاس پاسخ‌ها را پردازش کرده و منابع را از بسته‌ی بازگشتی استخراج می‌کند که در پایگاه داده‌ی محلی ذخیره می‌شوند.
  2. یک کلاس جدید AppFhirSyncWorker.kt ایجاد کنید. این کلاس نحوه همگام‌سازی برنامه با سرور FHIR از راه دور را با استفاده از یک worker پس‌زمینه تعریف می‌کند.
    class AppFhirSyncWorker(appContext: Context, workerParams: WorkerParameters) :
      FhirSyncWorker(appContext, workerParams) {
    
      override fun getDownloadWorkManager() = DownloadWorkManagerImpl()
    
      override fun getConflictResolver() = AcceptLocalConflictResolver
    
      override fun getFhirEngine() = FhirApplication.fhirEngine(applicationContext)
    
      override fun getUploadStrategy() =
        UploadStrategy.forBundleRequest(
          methodForCreate = HttpCreateMethod.PUT,
          methodForUpdate = HttpUpdateMethod.PATCH,
          squash = true,
          bundleSize = 500,
        )
    }
    
    در اینجا، ما تعریف کرده‌ایم که از کدام مدیر دانلود، حل‌کننده تداخل و نمونه موتور FHIR برای همگام‌سازی استفاده کنیم.
  3. در ViewModel خود، PatientListViewModel.kt ، یک مکانیزم همگام‌سازی یک‌باره راه‌اندازی خواهید کرد. این کد را پیدا کرده و به تابع triggerOneTimeSync() اضافه کنید:
    viewModelScope.launch {
          Sync.oneTimeSync<AppFhirSyncWorker>(getApplication())
            .shareIn(this, SharingStarted.Eagerly, 10)
            .collect { _pollState.emit(it) }
        }
    
    این کوروتین با استفاده از AppFhirSyncWorker که قبلاً تعریف کردیم، یک همگام‌سازی یک‌باره با سرور FHIR آغاز می‌کند. سپس رابط کاربری را بر اساس وضعیت فرآیند همگام‌سازی به‌روزرسانی می‌کند.
  4. در فایل PatientListFragment.kt ، بدنه‌ی تابع handleSyncJobStatus را به‌روزرسانی کنید:
    when (syncJobStatus) {
        is SyncJobStatus.Finished -> {
            Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show()
            viewModel.searchPatientsByName("")
        }
        else -> {}
    }
    
    در اینجا، هنگامی که فرآیند همگام‌سازی به پایان می‌رسد، یک پیام Toast به کاربر اطلاع می‌دهد و سپس برنامه با فراخوانی جستجو با نام خالی، تمام بیماران را نمایش می‌دهد.

حالا که همه چیز تنظیم شده است، برنامه خود را اجرا کنید. روی دکمه Sync در منو کلیک کنید. اگر همه چیز به درستی کار کند، باید ببینید که بیماران از سرور محلی FHIR شما دانلود شده و در برنامه نمایش داده می‌شوند.

فهرست بیماران

۶. اصلاح و بارگذاری اطلاعات بیمار

در این بخش، شما را در فرآیند اصلاح داده‌های بیمار بر اساس معیارهای خاص و آپلود داده‌های به‌روز شده در سرور FHIR شما راهنمایی خواهیم کرد. به طور خاص، شهرهای آدرس را برای بیماران ساکن در Wakefield و Taunton تغییر خواهیم داد.

مرحله 1 : تنظیم منطق اصلاح در PatientListViewModel

کد موجود در این بخش به تابع triggerUpdate در PatientListViewModel اضافه می‌شود.

  1. دسترسی به موتور FHIR : با دریافت ارجاع به موتور FHIR در PatientListViewModel.kt شروع کنید.
    viewModelScope.launch {
       val fhirEngine = FhirApplication.fhirEngine(getApplication())
    
    این کد یک کوروتین را در محدوده ViewModel راه‌اندازی می‌کند و موتور FHIR را مقداردهی اولیه می‌کند.
  2. جستجوی بیماران از ویکفیلد : از موتور FHIR برای جستجوی بیمارانی که آدرس آنها شهر Wakefield است استفاده کنید.
    val patientsFromWakefield =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Wakefield"
             }
           )
         }
    
    در اینجا، ما از روش search موتور FHIR برای فیلتر کردن بیماران بر اساس شهر محل سکونت آنها استفاده می‌کنیم. نتیجه، فهرستی از بیماران ویکفیلد خواهد بود.
  3. جستجوی بیماران از تاونتون : به طور مشابه، بیمارانی را با آدرس شهر Taunton جستجو کنید.
    val patientsFromTaunton =
         fhirEngine.search<Patient> {
           filter(
             Patient.ADDRESS_CITY,
             {
               modifier =  StringFilterModifier.MATCHES_EXACTLY
               value = "Taunton"
             }
           )
         }
    
    حالا دو لیست از بیماران داریم - یکی از ویکفیلد و دیگری از تاونتون.
  4. اصلاح آدرس‌های بیمار : هر بیمار را در لیست patientsFromWakefield بررسی کنید، شهر آنها را به Taunton تغییر دهید و آنها را در موتور FHIR به‌روزرسانی کنید.
    patientsFromWakefield.forEach {
         it.resource.address.first().city = "Taunton"
         fhirEngine.update(it.resource)
    }
    
    به طور مشابه، هر بیمار را در لیست patientsFromTaunton به‌روزرسانی کنید تا شهرش به Wakefield تغییر کند.
    patientsFromTaunton.forEach {
         it.resource.address.first().city = "Wakefield"
         fhirEngine.update(it.resource)
    }
    
  5. شروع همگام‌سازی : پس از تغییر داده‌ها به صورت محلی، یک همگام‌سازی یک‌باره را آغاز کنید تا از به‌روزرسانی داده‌ها در سرور FHIR اطمینان حاصل شود.
    triggerOneTimeSync()
    }
    
    علامت بسته شدن } نشان‌دهنده‌ی پایان کوروتینی است که در ابتدا اجرا شده است.

مرحله ۲ : تست عملکرد

  1. تست رابط کاربری : برنامه خود را اجرا کنید. روی دکمه Update در منو کلیک کنید. باید ببینید که آدرس شهرهای بیمار Aaron697 و Abby752 با هم عوض شده است.
  2. تأیید سرور : یک مرورگر باز کنید و به آدرس http://localhost:8080/fhir/Patient/ بروید. تأیید کنید که آدرس شهر برای بیماران Aaron697 و Abby752 در سرور محلی FHIR به‌روز شده باشد.

با دنبال کردن این مراحل، شما با موفقیت مکانیزمی را برای تغییر داده‌های بیمار و همگام‌سازی تغییرات با سرور FHIR خود پیاده‌سازی کرده‌اید.

۷. جستجوی بیماران بر اساس نام

جستجوی بیماران بر اساس نام آنها می‌تواند روشی کاربرپسند برای بازیابی اطلاعات فراهم کند. در اینجا، شما را در فرآیند پیاده‌سازی این ویژگی در برنامه‌تان راهنمایی خواهیم کرد.

مرحله ۱ : به‌روزرسانی امضای تابع

به فایل PatientListViewModel.kt خود بروید و تابعی با نام searchPatientsByName را پیدا کنید. ما کدی را به این تابع اضافه خواهیم کرد.

برای فیلتر کردن نتایج بر اساس نام کوئری ارائه شده، و انتشار نتایج برای به‌روزرسانی رابط کاربری، بلوک کد شرطی زیر را وارد کنید:

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

در اینجا، اگر nameQuery خالی نباشد، تابع جستجو نتایج را فیلتر می‌کند تا فقط بیمارانی را شامل شود که نام آنها شامل عبارت جستجوی مشخص شده باشد.

مرحله ۲ : عملکرد جستجوی جدید را آزمایش کنید

  1. برنامه را دوباره اجرا کنید : پس از انجام این تغییرات، برنامه خود را دوباره بسازید و اجرا کنید.
  2. جستجوی بیماران : در صفحه لیست بیماران، از قابلیت جستجو استفاده کنید. اکنون باید بتوانید یک نام (یا بخشی از نام) را وارد کنید تا لیست بیماران بر اساس آن فیلتر شود.

با تکمیل این مراحل، شما با فراهم کردن امکان جستجوی کارآمد بیماران بر اساس نامشان برای کاربران، برنامه خود را ارتقا داده‌اید. این امر می‌تواند به طور قابل توجهی تجربه کاربری و کارایی در بازیابی داده‌ها را بهبود بخشد.

۸. تبریک می‌گویم!

شما از کتابخانه موتور FHIR برای مدیریت منابع FHIR در برنامه خود استفاده کرده‌اید:

  • استفاده از API همگام‌سازی برای همگام‌سازی منابع FHIR با یک سرور FHIR
  • استفاده از API دسترسی به داده برای ایجاد، خواندن، به‌روزرسانی و حذف منابع محلی FHIR
  • استفاده از API جستجو برای جستجوی منابع محلی FHIR

آنچه ما پوشش داده‌ایم

  • نحوه راه اندازی یک سرور محلی HAPI FHIR
  • نحوه آپلود داده‌های آزمایشی به سرور محلی HAPI FHIR
  • نحوه ساخت یک برنامه اندروید با استفاده از کتابخانه موتور FHIR
  • نحوه استفاده از API همگام‌سازی، API دسترسی به داده و API جستجو در کتابخانه موتور FHIR

مراحل بعدی

  • مستندات کتابخانه موتور FHIR را بررسی کنید
  • ویژگی‌های پیشرفته‌ی Search API را بررسی کنید
  • کتابخانه موتور FHIR را در برنامه اندروید خود اعمال کنید

اطلاعات بیشتر