دات نت نیوک
Menu

رابط برنامه‌نویسی کاربردی FHIR

مقدمه

رابط برنامه‌نویسی کاربردی (API) مبتنی بر معماری REST در FHIR از بخش‌های زیر تشکیل شده است (شکل ۶٫۱):

  • رفتارهای مشترک
  • خدمت سامانه (System Service)
  • خدمت نوع (Type Service)
  • خدمت نمونه (Instance Service)
  • عملیات‌ها (Operations)
  • رهگیری نسخه‌ها (Version Tracking)

 

Fig. 6.1 FHIR API

رفتارهای مشترک

تمام بخش‌های API دارای مجموعه‌ای از رفتارهای مشترک هستند.

امنیت

رابط برنامه‌نویسی FHIR هیچ قاعده مشخصی درباره نوع سازوکار امنیتی که باید از عملیات‌ها محافظت کند تعیین نمی‌کند. اگرچه تقریباً در تمامی کاربردهای عملیاتی و واقعی انتظار می‌رود نوعی سازوکار امنیتی وجود داشته باشد، اما تنوع بسیار زیاد محیط‌ها و سناریوهایی کهFHIR API  در آن‌ها به کار می‌رود باعث می‌شود هیچ رویکرد امنیتی واحدی نتواند تمام نیازها را پوشش دهد. در واقع، برخی کاربردهای غیر بالینی، مانند توزیع اصطلاحات و واژگان استاندارد، ممکن است اساساً به هیچ نوع امنیت در سطح API نیاز نداشته باشند.

 

 

XML یا JSON

FHIR دو نوع محتوای اصلی برای منابع خود تعریف می‌کند:

  • application/xml+fhir
  • application/json+fhir

سرورهایی که از نمایش‌های XML و JSON برای منابع استفاده می‌کنند (که در ادامه توضیح داده خواهند شد)، باید از این نوع‌های محتوا در سربرگ‌های Accept  و Content-Type  استفاده نمایند.

سرورها می‌توانند انواع محتوای دیگری را نیز دریافت یا بازگردانند؛ از جمله قالب RDF/Turtle  که در استاندارد تعریف شده است. با این حال، این قالب عموماً برای تبادل عملیاتی اطلاعات مناسب نیست و بیشتر برای فعالیت‌های تحلیل داده کاربرد دارد. یکی از کاربردهای رایج سایر قالب‌ها، بازگرداندن نمایش‌های HTML  برای استفاده ساده در مرورگرها و انجام اشکال‌زدایی است که نوعی تسهیل برای پیاده‌سازان به شمار می‌آید. همچنین ممکن است سرور اطلاعات را در قالب‌های دیگری نظیر iCal  برای زمان‌بندی و قرار ملاقات‌ها و PDF  برای نسخه‌های قابل مشاهده و چاپ اسناد ارائه کند.

 

نسخه  HTTP

در حال حاضر چندین نسخه از HTTP در وب مورد استفاده قرار می‌گیرند: HTTP/1.0 ، HTTP/1.1  و HTTP/2.0  که از این نظر FHIR  به قابلیت‌های اختصاصی هیچ‌یک از این نسخه‌ها وابسته نیست و می‌تواند با همه آن‌ها مورد استفاده قرار گیرد. شایان توجه است که قابلیت‌های HTTP/2.0 عموماً برای رابط‌های RESTful مورد نیاز نیستند.

 

مدیریت خطاها

در تمامی تعاملات و عملیات‌ها -به استثنای عملیات دسته‌ای (Batch) - اگر عملیات با شکست مواجه شود، سرور یک پاسخ خطا بازمی‌گرداند. پاسخ خطا هر پاسخ HTTP با کد ۳۰۰ یا بیشتر است. در مقابل، کدهای HTTP بین ۲۰۰ تا ۲۹۹ نشان‌دهنده موفقیت عملیات هستند. هرگاه سرور یک خطا بازمی‌گرداند، باید یک منبع OperationOutcome  نیز همراه آن ارسال کند که شامل موارد زیر باشد: نمایش HTML قابل فهم برای انسان از خطا (ترجیحاً به زبان درخواست‌شده توسط کاربر) و یک یا چند شرح ساخت‌یافته از خطا (Issue) که شواهد و جزئیات دقیق علت بروز مشکل را ارائه می‌کنند.

 

خدمات پایه  RESTful API

خدمات ارائه‌شده توسط رابط RESTful API به سه دسته اصلی تقسیم می‌شوند:

خدمت

مسیر

شرح

خدمت سامانه

[base-url]

اقداماتی که به کل سامانه یا تمام محتوای آن مربوط می‌شوند

خدمت نوع

[base-url]/[type]

اقداماتی که به مجموعه‌ای از منابع هم‌نوع مربوط هستند؛ مانند جستجو و ایجاد منبع جدید

خدمت نمونه

[base-url]/[type]/[id]

اقداماتی که به یک رکورد مشخص (یک منبع) مربوط می‌شوند؛ مانند خواندن، به‌روزرسانی، حذف و مشاهده تاریخچه

 

 

خدمت سامانه (System Service)

خدمت سامانه در نشانی پایه سرور قرار دارد و قابلیت‌های زیر را ارائه می‌کند:

  • بازگرداندن بیانیه قابلیت‌های سامانه (Capability Statement)
  • مدیریت تراکنش‌ها و عملیات دسته‌ای
  • بازگرداندن تاریخچه سراسری سامانه (فهرست تغییرات همه منابع)
  • انجام عملیات جستجوی سراسری

 

بیانیه قابلیت‌ها (Capability Statement)

مشتری (Client) می‌تواند با اجرای درخواست GET [base-address]/metadata بیانیه قابلیت‌های سامانه را دریافت کند. پاسخ دریافتی، شرحی از قابلیت‌های سامانه و نحوه انطباق آن با استاندارد FHIR است و تمامی قابلیت‌های ارائه‌شده را مشخص می‌کند؛ از جمله:

  • چه نوع منابعی پشتیبانی می‌شوند.
  • چه تعاملات و عملیاتی برای هر نوع منبع پشتیبانی می‌شود.
  • چه پارامترهای جستجویی برای هر منبع پشتیبانی می‌شوند.
  • برای استفاده از سامانه چه الزامات امنیتی وجود دارد.

توجه شود که سامانه‌ها می‌توانند:

  • عملیات دریافت بیانیه قابلیت‌ها را محافظت‌شده کنند یا نکنند؛
  • یا در صورت شناخته‌شده بودن یا نبودن کاربر، بیانیه‌های متفاوتی ارائه دهند.

علاوه بر این، بیانیه قابلیت‌ها می‌تواند موارد زیر را نیز مشخص کند:

  • پروفایل‌های مورد پشتیبانی
  • مجموعه مقادیر (Value Sets)
  • و سایر مشخصات مرتبط

و توصیف جامعی از قابلیت‌های سرور ارائه دهد.

 

کاربردهای بیانیه قابلیت‌ها

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

  • تولید خودکار کد کارخواه و سناریوهای آزمون
  • ایجاد فرم‌های جستجو
  • مقایسه سامانه‌ها از نظر قابلیت هم‌کنش‌پذیری

 

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

خدمت سامانه می‌تواند یک منبعBundle  را دریافت کند که شامل مجموعه‌ای از عملیات است و همه آن‌ها در قالب یک عملیات HTTP  اجرا می‌شوند. این کار از طریق ارسال (POST) یک منبع Bundle به نشانی پایه سرور انجام می‌شود. این مجموعه عملیات در دو حالت اجرا می‌شود: حالت دسته‌ای (Batch Mode) و حالت تراکنشی (Transaction Mode).

حالت دسته‌ای (Batch Mode): در این حالت، بسته (Bundle) شامل مجموعه‌ای از درخواست‌ها است که سرور آن‌ها را به‌صورت ترتیبی و مستقل از یکدیگر اجرا می‌کند؛ گویی هرکدام یک درخواست جداگانه هستند. سرور نتیجه هر درخواست را دریافت کرده و آن را در یک بسته پاسخ واحد قرار می‌دهد و سپس آن را به کارخواه بازمی‌گرداند. این روش باعث کاهش تأخیرهای ناشی از شبکه می‌شود. در یک عملیات دسته‌ای، هر درخواست مستقل پردازش می‌شود، موفقیت یا شکست هر درخواست جداگانه گزارش می‌گردد و جزئیات کامل نتایج به کارخواه بازگردانده می‌شود.

حالت تراکنشی (Transaction Mode): در این حالت، تمامی عملیات به‌عنوان یک عملیات واحد پردازش می‌شوند. بنابراین یا همه عملیات با موفقیت انجام می‌شوند یا همه آن‌ها با شکست مواجه می‌شوند. علاوه بر این، سرور مسئول به‌روزرسانی ارجاعات داخلی میان منابع موجود در تراکنش و تبدیل آن‌ها به شناسه‌های نهایی است. این قابلیت به کارخواه اجازه می‌دهد مجموعه‌ای از منابع وابسته به یکدیگر را ارسال کند و سرور خود تمامی جزئیات ارتباطات و شناسه‌ها را مدیریت نماید. برای اطمینان از اینکه سرورها قادر به انجام این عملیات هستند، قواعد اضافی متعددی درباره محتوای مجاز در یک تراکنش تعریف شده است. این بخش یکی از پیچیده‌ترین قسمت‌های FHIR محسوب می‌شود و برای آگاهی از جزئیات کامل نحوه عملکرد تراکنش‌ها باید به متن اصلی مشخصات استاندارد مراجعه شود.

 

تاریخچه سراسری سامانه (System Wide History)

              کلاینت می‌تواند با اجرای درخواست زیر، تاریخچه کامل تغییرات اعمال‌شده بر تمامی منابع سامانه را دریافت کند:

GET [base-address]/_history

              پاسخ این درخواست یک منبعBundle  است که فهرستی از تمامی تغییرات سامانه را به ترتیب معکوس زمانی (جدیدترین تغییر در ابتدا) ارائه می‌کند. برای هر تغییر، سرور اطلاعات زیر را درج می‌کند:

  • تاریخ و زمان وقوع تغییر
  • نوع تغییر (ایجاد، حذف یا به‌روزرسانی)
  • محتوای نهایی منبع (در صورت ایجاد یا به‌روزرسانی)
  • نسخه منبع

              این قابلیت معمولاً در خدمات انتشار/اشتراک (Publication/Subscription) مورد استفاده قرار می‌گیرد تا یک سرور ثانویه بتواند محتوای یک سرور اصلی را بازتولید یا همگام‌سازی کند. بدیهی است که این فهرست ممکن است بسیار بزرگ شود. بنابراین کارخواه می‌تواند با استفاده از پارامتر lastUpdated  اندازه فهرست را کاهش دهد. مقدار این پارامتر معمولاً همان زمان ثبت‌شده در آخرین پاسخ دریافتی از سرور است:

GET [base-address]/_history?lastUpdated=2015-11-04T13:44:45

 

نکات پیاده‌سازی

  • نتایج حاصل از عملیات تاریخچه (history) می‌توانند صفحه‌بندی (Paging) شوند.
  • مرزهای تراکنش‌ها (Transaction Boundaries) در تاریخچه نمایش داده نمی‌شوند. بنابراین ممکن است کلاینت مشترک (Subscriber Client) ناچار باشد با مشکلات موقتی یکپارچگی ارجاعی (Transient Referential Integrity Issues) مواجه شود.
  • در مرز زمانی تعیین‌شده توسط lastUpdated، ممکن است یک رویداد بیش از یک بار برای کلاینت ارسال شود.
  • سرورها می‌توانند برای این عملیات از الگوی درخواست غیرهمزمان (Asynchronous Request Pattern) نیز پشتیبانی کنند.

 

جستجوی سراسری سامانه (System Search)

              خدمت سامانه علاوه بر تاریخچه، امکان جستجو در میان تمامی منابع موجود را نیز فراهم می‌کند. این کار از طریق اجرای درخواست GET روی مسیر [base-address]/_search  همراه با پارامترهای جستجو انجام می‌شود:

GET [base-address]/_search?_text=diabetes

              این درخواست تمامی منابعی را بازمی‌گرداند که در متن آن‌ها واژه «دیابت» (diabetes) یا واژه‌ای مرتبط با آن وجود داشته باشد. تشخیص واژه‌های مرتبط به صلاحدید سرور بستگی دارد. در جستجوی سراسری سامانه، فقط پارامترهای جستجویی که برای همه انواع منابع قابل اعمال هستند می‌توانند مورد استفاده قرار گیرند. توجه شود که تعداد اندکی از سرورها از چنین جستجوی بدون محدودیت و گسترده‌ای پشتیبانی می‌کنند.

 

خدمت نوع (Type Service)

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

[base-address]/[Type]

که در آنType  نام نوع منبع است؛ برای مثال: [base-address]/Patient. نکته مهم این است که در نام نوع، حساسیت به حروف بزرگ و کوچک (Case Sensitive) وجود دارد. بنابراین /Patient صحیح است، اما /patient صحیح نیست.

              خدمت نوع، مجموعه منابع هم‌نوع را مدیریت می‌کند و عملیات‌هایی مانند ایجاد منبع جدید، جستجو در میان منابع آن نوع و مشاهده تاریخچه تغییرات آن نوع از منابع را فراهم می‌سازد.

 

ایجاد منبع جدید

برای ایجاد یک منبع جدید، باید منبع مورد نظر از طریق عملیاتPOST  به مدیر نوع (Type Manager) ارسال شود:

POST [base-address]/[Type]

اگر منبع ارسال‌شده برای سرور قابل پذیرش باشد، سرور یک شناسه جدید به آن اختصاص می‌دهد، آن را در محل جدید ذخیره می‌کند و سپس نشانی جدید منبع را به کارخواه بازمی‌گرداند تا کارخواه بداند منبع در کجا ذخیره شده است. میزان اعتبارسنجی محتوا و بررسی قواعد کسب‌وکار (Business Rules) به تشخیص و سیاست‌های سرور بستگی دارد.

 

تاریخچه اختصاصی نوع

خدمت نوع قادر است فهرست کاملی از تغییرات اعمال‌شده بر تمامی منابع یک نوع مشخص را در سامانه بازگرداند. کلاینت می‌تواند این قابلیت را با اجرای درخواست GET  زیر فراخوانی کند:

GET [base-address]/[Type]/_history

پاسخ این درخواست یک منبع Bundle  است که فهرست تمامی تغییرات مربوط به همان نوع منبع را در سامانه ارائه می‌کند. برای مثال:

GET [base-address]/Patient/_history

فهرست تمامی تغییرات اعمال‌شده بر منابع نوع «بیمار» (Patient) را بازمی‌گرداند. سایر جزئیات این عملیات مشابه تاریخچه سراسری سامانه (System Wide History) است؛ از جمله:

  • زمان وقوع تغییر
  • نوع تغییر (ایجاد، حذف یا به‌روزرسانی)
  • محتوای منبع پس از تغییر
  • شماره نسخه منبع

نکته قابل توجه این است که مشخصات FHIR هیچ سازوکاری برای فیلتر کردن این تاریخچه بر اساس محتوای منابع (برای مثال با استفاده از پارامترهای جستجو) ارائه نمی‌کند. دلیل این موضوع مجموعه‌ای از مشکلات فنی است که در اثر موارد زیر ایجاد می‌شوند:

  • حذف شدن منابع و خارج شدن آن‌ها از دامنه جستجو
  • تغییر محتوای منابع در طول زمان
  • دشواری حفظ سازگاری نتایج تاریخچه با وضعیت‌های مختلف منابع در دوره‌های زمانی متفاوت

به همین دلیل، تاریخچه نوع صرفاً تمامی تغییرات مربوط به آن نوع منبع را بدون فیلتر مبتنی بر محتوا ارائه می‌کند.

جستجو

مدیر نوع به کلاینت اجازه می‌دهد در میان فهرست منابع جستجو کرده و فقط زیرمجموعه‌ای از منابع را که با معیارهای مشخصی مطابقت دارند بازگرداند. جستجو مهم‌ترین تعامل در FHIR محسوب می‌شود، زیرا ابزاری عمومی برای پیمایش میان منابع سامانه و ایجاد ارتباط میان آن‌ها فراهم می‌کند و در طول فرایند پیاده‌سازی توجه بسیار زیادی به آن شده است. برای جستجو در یک نوع منبع، کلاینت یک درخواست GET به مدیر نوع ارسال می‌کند:

GET [base-address]/Patient?gender=male

این درخواست در میان فهرست بیماران جستجو کرده و تمامی بیماران مرد را بازمی‌گرداند. امکان ارائه چندین پارامتر به‌صورت همزمان نیز وجود دارد:

GET [base-address]/Patient?name=peter&gender=male

کلاینت‌ها ملزم به ارائه هیچ پارامتری نیستند. برای مثال:

GET [base-address]/Patient

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

برای آنکه قابلیت جستجو در سمت سرور قابل پیاده‌سازی باشد، مشخصات FHIR میان «محتوای یک منبع» و «پارامتر جستجو» تمایز قائل می‌شود. کارخواهان مستقیماً در محتوای منابع جستجو نمی‌کنند و نمی‌توانند با استفاده از نگارش‌های مبتنی بر مسیر (مانند XPath) جستجوهای دلخواه خود را بر روی محتوای منبع ایجاد نمایند. در عوض، سرورها پارامترهای جستجوی قابل پشتیبانی را اعلام می‌کنند و مشخص می‌سازند که هر پارامتر به کدام ویژگی یا بخش از منبع مربوط است. سپس سرورها می‌توانند این پارامترها را با هر روش مناسبی که برای پیاده‌سازی آن‌ها مطلوب است نمایه‌سازی (Indexing) کنند تا امکان جستجوی سریع و کارآمد فراهم شود. اگرچه سرورها می‌توانند پارامترهای جستجوی اختصاصی خود را تعریف کنند، مشخصات FHIR مجموعه‌ای از پارامترهای جستجوی استاندارد و متداول را نیز ارائه می‌کند تا کارخواهان بتوانند از آن‌ها استفاده نمایند. بیشتر سرورها از همین نام‌های استاندارد استفاده کرده و اغلب یا تمامی این پارامترها را پیاده‌سازی می‌کنند.

برای هر نوع منبع، مشخصات FHIR مجموعه‌ای از پارامترهای جستجوی استاندارد ارائه می‌دهد. انتخاب این پارامترها بر اساس درخواست‌های کاربران در طول چرخه توسعه انجام شده و تمرکز ویژه‌ای بر فراهم کردن امکان برقراری ارتباط میان منابع مختلف داشته است. مشخصات FHIR برای پارامترهای جستجو، انواع داده‌ای متفاوت از انواع داده‌ای عناصر موجود در منابع تعریف می‌کند. تعریف این انواع داده صرفاً با هدف تعیین نحوه اعمال آن‌ها در جستجو بر روی مجموعه‌ای از عناصر در چندین منبع مختلف انجام شده است. جدول 6-1 انواع مختلف پارامترهای جستجو را خلاصه می‌کند.

جدول 6-1: انواع پارامترهای جستجو

مفهوم

نوع پارامتر

پارامتر جستجویی که به یک عنصر عددی اشاره دارد.

number

پارامتر جستجویی که به یک عنصر تاریخ یا زمان اشاره دارد.

date

پارامتر جستجویی که به یک رشته متنی ساده مانند بخشی از نام اشاره دارد. این پارامترها نسبت به حروف بزرگ و کوچک و نیز علائم آوایی حساس نیستند.

string

پارامتر جستجویی که به یک عنصر کدگذاری‌شده یا شناسه اشاره دارد. مقدار آن، بسته به اصلاح‌گر (Modifier) مورد استفاده، می‌تواند یا یک رشته متنی باشد و یا یک زوج شامل فضای نام (Namespace) و مقدار که با علامت «|» از یکدیگر جدا شده‌اند.

token

پارامتر جستجویی که به یک عنصر کمّی اشاره دارد.

quantity

پارامتر جستجویی که به یک ارجاع به منبع دیگر اشاره دارد.

reference

پارامتر جستجویی که به یک شناسه یکتای منبع (URI) اشاره دارد؛ مانند یک ارجاع خارجی.

uri

 

مشخصات کامل جستجو، فهرست جامعی از جزئیات مربوط به نحوه عملکرد هر نوع پارامتر جستجو و انواع داده‌ای قابل استفاده برای آن‌ها را ارائه می‌دهد. پس از آنکه مجموعه‌ای از منابع انتخاب شد، سرور باید مجموعه منابع منطبق را بازگرداند. نتایج جستجو ممکن است بسیار حجیم باشند؛ بنابراین نخستین راهکار بدیهی، بازگرداندن نتایج به صورت صفحات (Pages) است تا کاربر بتواند آن‌ها را به تدریج مشاهده کند. در FHIR، صفحه‌بندی به صورت مشارکتی میان کلاینت و سرور انجام می‌شود. کلاینت مجموعه نتایج مورد نظر خود را درخواست کرده و اندازه هر صفحه را مشخص می‌کند. سرور صفحه نخست نتایج را به همراه مجموعه‌ای از پیوندها به صفحات بعدی بازمی‌گرداند.

سرور می‌تواند پارامترهای اضافی اختصاصی خود را نیز به نشانی‌های صفحات بعدی اضافه کند تا هنگام پیمایش تدریجی کلاینت در میان مجموعه‌ای از منابع که ممکن است در طول زمان تغییر کنند، تداوم و یکپارچگی نتایج حفظ شود. در نتیجه، کلاینت نمی‌تواند مستقیماً به میانه نتایج یک جستجو وارد شود.

پارامترهای دیگری که کلاینت می‌تواند برای کنترل نحوه بازگرداندن نتایج جستجو استفاده کند، در جدول 6-2 ارائه شده‌اند.

جدول 6-2: سایر پارامترهای جستجو

مفهوم

پارامتر

مشخص می‌کند نتایج بر اساس پارامتر تعیین‌شده مرتب شوند. امکان تعیین چندین پارامتر مرتب‌سازی وجود دارد.

_sort

درخواست بازگرداندن تنها زیرمجموعه‌ای محدود از نتایج به منظور کاهش حجم انتقال داده.

_summary

گونه‌ای از حالت خلاصه که در آن کارخواه دقیقاً مشخص می‌کند کدام عناصر در پاسخ بازگردانده شوند.

_elements

 

به سرورها توصیه می‌شود پارامترهایی را که نمی‌شناسند نادیده بگیرند. دلیل این توصیه آن است که ممکن است برخی پارامترها توسط واسطه‌های HTTP به درخواست اضافه شده باشند. با این حال، سرورها می‌توانند درخواست‌هایی را که شامل پارامترهای شناخته‌شده اما پیاده‌سازی‌نشده هستند رد کنند. کلاینت می‌تواند پیوندself  موجود در پاسخ جستجو را بررسی کند تا مطمئن شود سرور هنگام پردازش نتایج از کدام پارامترهای جستجو استفاده کرده است.

 

اتصال منابع از طریق جستجو (Joining Using Search)

یکی از تکنیک‌های بسیار مفید، برقراری ارتباط میان منابع مختلف از طریق ارجاعات (References) موجود بین آن‌ها است. دو روش اصلی برای انجام این نوع اتصال وجود دارد: زنجیره‌سازی پارامترها (Parameter Chaining) و شمول منابع مرتبط (Include).

زنجیره‌سازی پارامترها زمانی مجاز است که نوع پارامتر جستجو از نوع «ارجاع» (Reference) باشد. نخستین روش استفاده از پارامترهای ارجاعی، جستجو بر اساس مقدار مستقیم ارجاع است:

GET [base-address]/Observation?subject=Patient/345

این درخواست تمامی مشاهدات (Observations) مربوط به بیمار شماره ۳۴۵ را بازمی‌گرداند. اما کلاینت می‌تواند یک گام فراتر رفته و تمامی مشاهدات مربوط به مجموعه‌ای از بیماران را انتخاب کند:

GET [base-address]/Observation?subject:patient.gender=male

این درخواست تمامی مشاهدات مربوط به بیماران مرد را بازمی‌گرداند.

اگرچه این مثال به تنهایی چندان کاربردی نیست، اما پارامترهای زنجیره‌ای یکی از اجزای بنیادی و بسیار مهم در طراحی جستجوهای پیچیده محسوب می‌شوند.

نمونه‌ای کاربردی‌تر:

GET [base-address]/DiagnosticReport?subject=Patient/123143&observation.code=http://loinc.org|1234-5

این درخواست تمامی گزارش‌های تشخیصی مربوط به بیمار شماره 123143 را که یکی از مشاهدات تشخیصی آن‌ها دارای کد LOINC برابر با 1234-5  باشد، بازیابی می‌کند.

روش دیگر برای برقراری ارتباط میان منابع، درخواست از سرور برای بازگرداندن منابع مرتبط با منابع منطبق‌شده است.

برای مثال:

GET [base-address]/Observation?code=1234-5&_include=Observation

:subject

این درخواست به منظور بازیابی تمامی مشاهدات (Observations) که مجموعه‌ای از معیارها را برآورده می‌کنند صادر می‌شود و علاوه بر آن، تمامی موضوع‌ها (Subjects) مربوط به آن مشاهدات نیز بازگردانده می‌شوند. هدف از این قابلیت آن است که کلاینت مجبور نباشد بلافاصله پس از دریافت نتایج جستجو، منابع مرتبط را در درخواست‌های جداگانه بازیابی کند تا بتواند نتایج را به‌درستی نمایش دهد؛ زیرا این کار موجب افزایش تأخیر شبکه (Network Latency) خواهد شد. در مواردی که نتایج جستجو به صورت صفحه‌بندی‌شده (Paging) ارائه می‌شوند، سرور باید منابعِ «شامل‌شده» (Included Resources) مرتبط با منابع منطبق در هر صفحه را نیز همراه همان صفحه بازگرداند؛ در غیر این صورت، صرفه‌جویی مورد انتظار در هزینه‌های ارتباطی شبکه حاصل نخواهد شد.

لازم به ذکر است که روش‌های دیگری نیز برای ایجاد پیوند میان منابع وجود دارد که در این مقال مورد بحث قرار نگرفته‌اند و در حال حاضر نیز به‌طور گسترده پیاده‌سازی نشده‌اند؛ از جمله استفاده ازGraphQL  و GraphDefinition .

 

آنچه جستجو نیست (What Search Is Not)

در طول سال‌ها، قابلیت‌های جستجوی موجود در FHIR بسیار قدرتمند شده‌اند، هرچند تعداد اندکی از سرورها تمامی این قابلیت‌ها را پیاده‌سازی می‌کنند. با این حال، دامنه عملکرد جستجو همچنان به بازگرداندن مجموعه‌ای از منابع (Resources) محدود است. جستجو یک زبان پرس‌وجوی عمومی (General-Purpose Query Language) نیست که به کلاینت اجازه دهد مجموعه‌های دلخواه و سفارشی از داده‌ها را برای نمایش یا تحلیل بازیابی کند. جامعه FHIR در حال آزمایش و نمونه‌سازی چندین زبان پرس‌وجوی مختلف برای پشتیبانی از تحلیل داده‌ها است. یکی از قدرتمندترین این زبان‌ها، زبان پرس‌وجوی بالینی (Clinical Query Language  - CQL) است که در چارچوب HL7  در حال توسعه می‌باشد. ()

 

خدمت نمونه (Instance Service)

خدمت نمونه، تعاملاتی را فراهم می‌کند که امکان مدیریت یک نمونه منفرد از یک منبع را فراهم می‌سازد. این خدمت از عملیات زیر پشتیبانی می‌کند: خواندن (Read): دریافت محتوای فعلی منبع، به‌روزرسانی (Update): تغییر محتوای منبع، حذف (Delete): حذف منبع و تاریخچه نسخه‌ها (Version History): مشاهده نسخه‌های مختلف و سوابق تغییرات منبع. به عبارت دیگر، خدمت نمونه برای مدیریت یک رکورد مشخص از یک منبع FHIR به کار می‌رود و عملیات پایه مدیریت چرخه عمر آن منبع را در اختیار قرار می‌دهد.

 

خواندن (Read)

این ساده‌ترین عملیات در رابط برنامه‌نویسی RESTful است: دریافت یک منبع از طریق شناسه آن با استفاده از درخواست GET:

GET [base-address]/[Type]/[id]

که در آن [id]  شناسه منطقی (Logical ID) منبع است.

برای مثال:

GET [base-address]/Patient/345

این درخواست منبع بیمار (Patient) با شناسه منطقی 345  را از سرور دریافت می‌کند. توجه داشته باشید که شناسه منطقی و در واقع تمامی شناسه‌ها در FHIR می‌توانند از هر ترکیبی از موارد زیر تشکیل شوند: حروف بزرگ انگلیسی (A تا Z)، حروف کوچک انگلیسی (a تا z)، ارقام (0 تا 9)  و (کاراکتر) نویسه‌های ویژه «-»  و «.» . طول شناسه نیز باید حداقل1  و حداکثر 64  نویسه باشد. همچنین شناسه‌ها در FHIR نسبت به بزرگی و کوچکی حروف حساس هستند (Case Sensitive)؛ بنابراین: Patient/ABC و Patient/abc دو شناسه متفاوت محسوب می‌شوند و ممکن است به دو منبع کاملاً مجزا اشاره داشته باشند.

 

به‌روزرسانی (Update)

برای تغییر محتوای یک منبع (Resource)، سرویس‌گیرنده (Client) محتوای به‌روزشدهآن منبع را با استفاده از روشPUT  به نشانی‌ای که همان شناسه منبع است ارسال می‌کند:

PUT [base-address]/Patient/345
<body: new patient record>

سرورها ممکن است به یک سرویس‌گیرنده اجازه دهند که یک منبع را در مکانی که هنوز اشغال نشده است قرار دهد؛ به عبارت دیگر، به جای آنکه سرور شناسه را از طریق عملیاتCreate  (ایجاد) اختصاص دهد، سرویس‌گیرنده بتواند خود شناسه را تعیین کند. این قابلیت در بسیاری از زمینه‌ها مفید است، به‌ویژه زمانی که مجموعه‌ای از منابع از یک سرور به سرور دیگر منتقل می‌شوند. با این حال، این امر مستلزم آن است که سرور بتواند به سرویس‌گیرنده یا سرویس‌گیرندگان اعتماد کند که شناسه‌هایی واقعاً یکتا و معتبر اختصاص می‌دهند. به همین دلیل، سرورها در بیانیه انطباق (Conformance Statement) خود اعلام می‌کنند که آیا چنین امکانی را برای سرویس‌گیرندگان فراهم می‌کنند یا خیر. انتظار می‌رود سرورها پیش از پذیرش یک به‌روزرسانی، قواعد کسب‌وکار مناسب را اعمال کنند؛ برای مثال:

  • بررسی کنند که منبع معتبر (Valid) است؛
  • اطمینان حاصل کنند که عناصر غیرقابل تغییر (Immutable Elements) تغییر نکرده‌اند؛
  • یکپارچگی ارجاعی (Referential Integrity) حفظ شده است.

قواعد دقیق مورد استفاده از یک سامانه به سامانه دیگر متفاوت است. سامانه‌های اطلاعاتی سازمانی مانند پرونده الکترونیک سلامت  (EHR) معمولاً یکپارچگی ارجاعی را به‌طور کامل اعمال می‌کنند، در حالی که برخی سرورهای تحلیل داده‌های ثانویه، مانند مخازن داده‌های بالینی (Clinical Data Repositories)، ممکن است تصمیم بگیرند چنین محدودیتی را اعمال نکنند.

سرورها ملزم نیستند پس از یک به‌روزرسانی، دقیقاً همان منبع ارسال‌شده را در پاسخ به عملیات خواندن (Read) بازگردانند. ممکن است سرور به دلیل قواعد کسب‌وکار یا محدودیت‌های سامانه‌های زیربنایی (که در سامانه‌های قدیمی بسیار رایج است) محتوای ذخیره‌شده را اندکی با نسخه ارسالی متفاوت نگه دارد. با این حال، سرورها باید این تغییرات را تا حد امکان به حداقل برسانند تا تبادل اطلاعات پایدار و قابل پیش‌بینی باقی بماند.

سرورها همچنین ممکن است یکپارچگی نسخه‌ها (Version Integrity) را در هنگام به‌روزرسانی اعمال کنند؛ برای مثال، تنها زمانی اجازه به‌روزرسانی بدهند که سرویس‌گیرنده آخرین نسخه منبع را در اختیار داشته باشد و تغییرات خود را بر مبنای همان نسخه انجام داده باشد.

 

حذف (Delete)

یک کلاینت با ارسال یک عملیات HTTP DELETE به نشانی هویتی (Identity) یک منبع، از یک سرور درخواست می‌کند که آن منبع را حذف کند. سپس سرور می‌تواند تصمیم بگیرد که منبع را حذف کند. پس از حذف، دیگر نمی‌توان یک منبع را «خواند» (مطابق توضیحات بالا) یا از طریق یک عملیات جست‌وجو آن را پیدا کرد. منابع حذف‌شده را می‌توان با به‌روزرسانی آن‌ها به برخی منابع معتبر، دوباره فعال کرد.

توجه داشته باشید که در بسیاری از کاربردهای حوزه سلامت، امکان حذف سوابق موجود وجود ندارد؛ در عوض، سوابق باید نگهداری شوند و به نحوی علامت‌گذاری شوند که نشان دهد دیگر جاری (Current) نیستند. به همین دلیل، عملیات حذف در بسیاری از موارد اصلاً پشتیبانی نمی‌شود؛ هرچند این موضوع ممکن است بسته به نوع سابقه متفاوت باشد.

 

سرویس تاریخچه منبع (Resource History Service)

این سرویس امکان دسترسی به نسخه‌های تاریخی یک منبع را فراهم می‌کند. یک کلاینت می‌تواند تاریخچه کامل یک منبع مشخص را درخواست کند:

GET [base-address]/Patient/345/_history

یا برای دسترسی به یک نسخه خاص از تاریخچه:

GET [base-address]/Patient/345/_history/2

توجه داشته باشید که شناسه نسخه (Version ID) الزاماً نباید یک عدد متوالی و افزایشی باشد. هیچ راهی برای به‌روزرسانی یک نسخه قبلی از یک منبع وجود ندارد.

 

سرویس‌های اضافی (Additional Services)

عملیات (Operations)

تمام تعاملاتی که تاکنون شرح داده شدند، بخشی از مشخصات پایه FHIR هستند و برای همه انواع منابع کاربرد دارند. علاوه بر این، FHIR  نوع خاصی از تعامل را با عنوان عملیات (Operation) تعریف می‌کند. یک کلاینت یک عملیات را فراخوانی می‌کند تا از سرور بخواهد اقدام خاصی را اجرا کند. نتیجه این اقدام ممکن است بازگرداندن مجموعه‌ای از منابع باشد، بدون آنکه تأثیر ماندگاری بر منابع سیستم مبدأ داشته باشد (به‌جز ورودی‌های ثبت‌شده در ردپای حسابرسی (Audit Trail))؛ برای مثال، بازگرداندن کل پرونده بیمار. یا ممکن است این اقدام بر چندین منبع مختلف تأثیر بگذارد؛ برای مثال، رزرو نزدیک‌ترین نوبت غیراضطراریِ در دسترس برای بیمار X.

یک عملیات از طریقPOST‌کردن مجموعه‌ای از پارامترها به یک نقطه پایانی عملیات (Operation Endpoint) فراخوانی می‌شود. نقاط پایانی عملیات از الگوی زیر پیروی می‌کنند: [manager-url]/$[name] که در آن،manager-URL  یکی از مدیران سرویس تعریف‌شده در بالا (یعنی system، type  یا instance) است وname  همان نامی است که برای عملیات تعریف شده است.

بنابراین، برای درخواست اجرای عملیات ValueSet expand:

POST [base-address]/ValueSet/[id]/$expand

<body: parameters>

منبعParameters  یک منبع ویژه است که شامل فهرستی از زوج‌های نام/مقدار (name/value) است. هنگامی که تمام پارامترها دارای نمایش‌هایی از نوع داده‌های ابتدایی (Primitive Type) باشند و عملیات از نوع عملیات خواندن (Read-Type Operation) باشد، می‌توان همه پارامترها را به‌صورت پارامترهای URL ارسال کرد و عملیات را به‌عنوان یک عملیات GET فراخوانی نمود:

GET [base-address]/ValueSet/[id]/$expand? Filter=text

پاسخ حاصل از فراخوانی یک عملیات، یا فهرستی از پارامترهاست، یا اگر تنها یک پارامتر خروجی با نامresult  وجود داشته باشد، در این صورت خود منبع مستقیماً بازگردانده می‌شود (که ممکن است یک Bundle شامل منابع دیگر باشد).

 

تعاریف عملیات (Operation Definitions)

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

  • عملیات چه کاری انجام می‌دهد؟
  • آیا عملیات در سطح سیستم (System)، نوع (Type) یا نمونه (Instance) فراخوانی می‌شود؟
  • پارامترهای ورودی چیستند؟
  • پارامترهای خروجی چیستند؟

منبعOperationDefinition  شامل تمام این اطلاعات است. کلاینت‌ها می‌توانند بیانیه انطباق (Conformance Statement) سرور را بررسی کنند تا ببینند چه عملیات‌هایی در دسترس هستند و سپس از آنجا به تعریف عملیاتی دسترسی پیدا کنند که نحوه فراخوانی آن را توصیف می‌کند.

خود مشخصات FHIR نیز چندین عملیات را توصیف می‌کند. جدول ۶.۳ موارد مهم آن‌ها را شامل می‌شود:

جدول ۶.۳ عملیات FHIR

شرح

عملیات

مشخص می‌کند که آیا سرور، یک منبع را معتبر (Valid) تلقی می‌کند یا خیر.

$validate

یک پیام FHIR را پردازش می‌کند.

$process-message

یک فهرست جاری را پیدا می‌کند؛ برای مثال، فهرست جاری مشکلات یک بیمار

$find

مجموعه کامل منابع مرتبط با یک بیمار یا صرفاً مرتبط با یک دوره درمانی (Episode) را بازیابی می‌کند.

$everything

با دریافت یک پرسشنامه، تا حد امکان پاسخ‌های آن را بر اساس داده‌های ذخیره‌شده تکمیل می‌کند.

$populate

با دریافت یک Composition، یک سند کامل ایجاد می‌کند.

$document

 

علاوه بر این فهرست، چندین عملیات مرتبط با اصطلاح‌شناسی (Terminology) نیز تعریف شده‌اند؛ از جمله $expand، $validate-code، $translate، $lookup  و $closure.

همچنین، علاوه بر عملیات‌هایی که در خود مشخصات FHIR تعریف شده‌اند، بسیاری از راهنماهای پیاده‌سازی (Implementation Guides) عملیات‌های خاص خود را تعریف می‌کنند و سرورهای منفرد نیز می‌توانند عملیات‌های اختصاصی خود را تعریف کنند. یک سرور معمولی FHIR مجموعه‌ای از تعاملات پایه FHIR را ارائه می‌دهد و در کنار آن، چند عملیات اضافی نیز فراهم می‌کند که ابزاری برای انتقال عملیات‌های متداول از کلاینت به سرور فراهم می‌سازند.

 

محفظه‌ها (Compartments)

به‌عنوان بخشی از مشخصات، منابع در تعدادی «محفظه (Compartment)» تخصیص داده می‌شوند. یک محفظه، یک گروه‌بندی منطقی از منابع است که بر اساس روابط میان آن‌ها تعیین می‌شود. مهم‌ترین محفظه، «محفظه بیمار یا Patient Compartment» است که تمام منابع مربوط به یک بیمار را در کنار یکدیگر گروه‌بندی می‌کند. همچنین یک محفظه کاربر حرفه‌ای سلامت (Practitioner Compartment) نیز وجود دارد که بر اساس نویسندگی محتوا یا انتساب تصمیم‌ها/اقدامات زیربنایی مراقبت سلامت شکل می‌گیرد.

تعریفPatient Compartment  نه‌تنها مشخص می‌کند که چنین محفظه‌ای وجود دارد، بلکه همچنین مشخص می‌کند کدام عناصر در یک منبع، آن منبع را به Patient Compartment مرتبط می‌کنند. برای مثال، تعریف منبعObservation  بیان می‌کند که یکObservation  در یک Patient Compartment قرار می‌گیرد اگر subject  یا performer  آن به آن بیمار ارجاع دهد:

Observation subject or performer

محفظه‌ها از دو جهت مفید هستند:

  1. می‌توان از آن‌ها به‌عنوان یک میان‌بُر نحوی  (Syntactical Shortcut) در URLها استفاده کرد.
  2. آن‌ها مبنای زیربنایی برای اتخاذ تصمیم‌های کنترل دسترسی امنیتی را تشکیل می‌دهند.

 

میان‌بُر نحوی در URLها ظاهر می‌شود. برای مثال، برای دسترسی به تمام منابعCondition  مربوط به یک بیمار:

GET [base]/Condition? Patient=333

از آنجا کهPatient Compartment  تعریف شده است، می‌توان از URL جایگزین زیر نیز استفاده کرد که طبق مشخصات، دقیقاً همان معنا را دارد:

GET [base]/Patient/333/Condition

این شکل دوم URL برای توسعه‌دهندگان سامانه‌های پرونده سلامت شخصی که زندگی را تا حد زیادی در قالب پرونده‌های سلامت کاملاً تفکیک‌شده و محفظه‌بندی‌شده می‌بینند، بسیار طبیعی به نظر می‌رسد.

بااین‌حال، برای سوابق سازمانی (Institutional Records)، این مفهوم کاملاً ناآشناست؛ زیرا پایگاه داده رابطه‌ای کامل، یک گراف یکپارچه و پیوسته است که به‌طور معمول بیماران را به یکدیگر پیوند می‌دهد، زیرا مراقبت از آن‌ها با یکدیگر ارتباط دارد. چند نمونه از این موارد عبارت‌اند از: مادر و کودک، شرکای دریافت خدمات مشاوره و درمان بیماری‌های مقاربتی (STD)، پیوند اعضا، کنترل عفونت برای بیمارانی که در یک مکان مشترک حضور دارند و موارد مشابه.

برای یک منبع یکسان، ممکن است یک منبع در چند Patient Compartment مختلف قرار داشته باشد. برای مثال، یک Composition که دارای چندPractitioner  به‌عنوان نویسنده باشد، در محفظه مربوط به هر یک از نویسندگان قرار خواهد گرفت. به همین دلیل، URL زیر معتبر نیست:

[base]/Patient/333/Condition/2344

زیرا خود منبعCondition  همواره به شکل زیر است:

[base]/Condition/2344

دومین کاربرد محفظه، یعنی استفاده از آن به‌عنوان روشی برای مدیریت دسترسی به منابع، به‌صورت صریح در API نمایان نمی‌شود؛ بلکه صرفاً به‌صورت ضمنی، به‌عنوان عاملی برای تصمیم‌گیری در تفسیر یک توکن SMART on FHIR عمل می‌کند.

برنامه‌های کاربردی ملزم نیستند از تعریف رسمی محفظه‌ها استفاده کنند، زیرا تمام برنامه‌های قدیمی (Legacy Applications) پیش‌تر این مسئله را به روش خود حل کرده‌اند؛ بااین‌حال، در صورت تمایل می‌توانند از آن استفاده کنند.

 

 

اشتراک (Subscription)

رابط RESTful API در FHIR همچنین روشی را برای اشتراک در یک زیرمجموعه منتخب از داده‌های موجود در سرور فراهم می‌کند؛ به‌گونه‌ای که سرور، از طریق کانال‌های مختلف، اعلان‌هایی را درباره منابع جدیدی که با محدودیت‌ها (Constraints) مطابقت دارند، برای یک کلاینت ارسال کند. رویکردSubscription  در حال حاضر از طریق یک فرآیند مبتنی بر جامعه FHIR در حال بازطراحی است که می‌توان روند پیشرفت این فرآیند بازنگری را از طریق بحث‌های جامعه FHIR  دنبال کرد. ()

 

ردیابی نسخه‌ها (Version Tracking)

بخش مهمی از API، مدیریت نسخه‌ها و تعارضات ویرایشی (Editorial Contention) است. برای حفظ یکپارچگی سوابق، مهم است که از ویرایش هم‌زمان یک سابقه توسط دو کاربر جلوگیری شود؛ زیرا در غیر این صورت، کاربری که کار خود را دیرتر به پایان می‌رساند، تغییرات کاربر دیگر را بازنویسی می‌کند و در نتیجه، یک به‌روزرسانی از بین می‌رود.

به‌طور کلی‌تر، در سامانه‌هایی که دارای چندین برنامه کاربردی در یک اکوسیستم هستند و این برنامه‌ها مستقیماً با یکدیگر ارتباط دارند، لازم است به‌روز بودن اطلاعات (Information Currency) با دقت بیشتری ردیابی شود. علاوه بر این، امکان مشاهده نسخه‌های قبلی یک منبع برای اهداف بازبینی و حسابرسی (Review and Audit) اهمیت دارد. در FHIR، یک منبع به‌عنوان یک موجودیت منطقی در نظر گرفته می‌شود که توسط مجموعه‌ای از نسخه‌های متوالی نمایش داده می‌شود؛ یکی از این نسخه‌ها، نسخه «جاری (Current)» است. انجام یک به‌روزرسانی، یک ورودی جدید در فهرست نسخه‌های متوالی ایجاد می‌کند و آن را به‌عنوان نسخه جاری تعیین می‌کند. توجه داشته باشید که نسخه جاری باید جدیدترین نسخه باشد؛ هیچ راهی برای بازگرداندن تغییرات (Roll Back) وجود ندارد.

عملیات حذف، در مواردی که مجاز باشد، به همین شکل عمل می‌کند: حذف، یک ورودی در تاریخچه نسخه ایجاد می‌کند که به‌عنوان حذف‌شده (Deleted) علامت‌گذاری می‌شود و همان ورودی را به‌عنوان نسخه جاری منطقی تعیین می‌کند. یک تاریخچه کامل نسخه ممکن است شامل چندین چرخه حذف/به‌روزرسانی باشد، هرچند این وضعیت در عمل بسیار غیرمعمول خواهد بود.

FHIR  از نسخه‌بندی سوابق با علامت‌گذاری صریح هر منبع توسط دو مقدار مرتبط با نسخه پشتیبانی می‌کند: meta.versionId و meta.lastUpdated. در RESTful API، هرگاه محتوای یک منبع توسط یک کلاینت یا یک فرآیند داخلی سرور تغییر کند، این دو عنصر توسط سرور به‌روزرسانی می‌شوند. سرور هر مقداری را که کلاینت برای این عناصر ارائه کرده باشد نادیده می‌گیرد و آن‌ها را با مقادیر اختصاص‌یافته توسط خود جایگزین می‌کند.

versionId  شامل هر نوع نشانگر داخلی نسخه است که سرور تصمیم بگیرد آن را اختصاص دهد؛ با این حال، این مقدار باید یک id معتبر باشد؛ یعنی دارای ۱ تا ۶۴ نویسه و شامل حروف بزرگ و کوچک a تا z، ارقام، و نویسه‌های-  یا.  باشد.

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

عنصرlastUpdated  نشانگری برای کاربر انسانی است که مشخص می‌کند اطلاعات موجود در منبع تا چه اندازه قدیمی است. این عنصر برای ردیابی نسخه استفاده نمی‌شود و لازم نیست دقتی بیشتر از نزدیک‌ترین ثانیه داشته باشد. این اطلاعات همچنین هنگام خواندن منبع، در هدرهای HTTP نیز نمایش داده می‌شوند (جدول ۶.۴).

جدول ۶.۴ - اطلاعات نسخه (Version Information)

معنا

مقدار

هدر HTTP ETag. مقدار versionId یک ETag  ضعیف (Weak ETag) است؛ بنابراین، برای مثال، مقدار versionId  برابر با 3141  به شکل زیر نمایش داده می‌شود:

 ETag: W/"3141"

meta.versionId

هدرHTTP Last-Modified. برای مثال، مقدار lastUpdated  برابر با 2015-11-30T13:04:20Z  به شکل زیر نمایش داده می‌شود:

 Last-Modified: Mon, 30 Nov 2015 12:04:20 GMT

meta.lastUpdated

مشخصات FHIR سرورها را تشویق می‌کند که پشتیبانی کامل از نسخه‌ها  (Full Version Support) را ارائه دهند؛ زیرا این قابلیت بخش مهمی از حفظ سازگاری سوابق و اطمینان از ثبت و لحاظ شدن صحیح تمامی تغییرات است. اما از آنجا که بسیاری از سامانه‌های سلامت، نسخه‌بندی را به‌صورت داخلی پیاده‌سازی نمی‌کنند، قادر نیستند آن را در رابط FHIR خود ارائه کنند. به همین دلیل، ردیابی نسخه‌ها  (Version Tracking) اجباری نیست؛ هرچند برخی راهنماهای پیاده‌سازی آن را الزامی خواهند کرد.

به‌روزرسانی‌های ازدست‌رفته (Lost Updates) را می‌توان با استفاده ترکیبی از هدرهایETag  وIf-Match  پیشگیری کرد. هنگامی که کلاینت یک منبع را می‌خواند، versionId  را هم در هدر و هم در خود منبع دریافت می‌کند:

HTTP 200 OK

Date: Sat, 09 Feb 2013 16:09:50 GMT

Content-Type: application/json+fhir

Last-Modified: Sat, 02 Feb 2013 12:02:47 GMT

ETag: W/"23"

{

  "resourceType" : "Patient",

  "id" : "347",

  "meta" : {

    "versionId" : "23",

    "lastUpdated" : "2013-02-02T12:02:47Z"

  },

  etc.

}

هنگامی که کلاینت منبع را به‌روزرسانی می‌کند، درخواست را همراه با یک هدرIf-Match  ارسال می‌کند که در آن، مقدار ETag دریافت‌شده از سرور قرار دارد:

PUT /Patient/347 HTTP/1.1

If-Match: W/"23"

اگر شناسه نسخه‌ای که در هدرIf-Match  ارائه شده است با نسخه موجود مطابقت نداشته باشد، سرور به‌جای به‌روزرسانی منبع، کد وضعیت 409 Conflict  را بازمی‌گرداند.

برخی سرورها تصمیم‌گیری درباره اینکه آیا کلاینت می‌خواهد یک به‌روزرسانی وابسته به نسخه (Version-Specific Update) انجام دهد یا خیر را به خود کلاینت واگذار می‌کنند؛ در حالی که برخی دیگر این کار را الزامی می‌دانند و اگر هدرIf-Match  وجود نداشته باشد، کد وضعیت 412 Pre-condition Failed  را بازمی‌گردانند.

 

API داده‌های حجیم (Bulk Data API)

API  شرح‌داده‌شده در بالا برای استفاده در فرآیندهای سلامت بسیار مناسب است و کنترل بسیار دقیق در سطح رکورد را فراهم می‌کند. بااین‌حال، این APIها برای کار با مجموعه‌های بزرگ رکوردها عملی نیستند؛ درحالی‌که کار با مجموعه‌های بزرگ داده، به‌طور معمول در عملیات پشتیبان‌کننده از فعالیت‌های بالینی مورد نیاز است، به‌ویژه در تحلیل داده‌های مرتبط با پژوهش و هوش کسب‌وکار (Business Intelligence).

در پاسخ به این نیاز، FHIR R4، Bulk Data API  را معرفی می‌کند. این API شامل سه بخش است:

  • قالبnd-json  برای نمایش کارآمد حجم زیادی از داده‌ها
  • الگویی برای فراخوانی ناهمگام عملیات  HTTP
  • مجموعه‌ای از عملیات برای آسان‌تر کردن درخواست مجموعه داده موردنظر

استفاده از این قابلیت‌ها در راهنمای پیاده‌سازی Bulk Data در حال تکمیل و تشریح بیشتر است و جزئیاتی که در اینجا مشخص می‌شوند، در نسخه بعدی مشخصات FHIR وارد خواهند شد.

 

قالب  ND-JSON

قالبND-JSON  یا Newline Delimited JSON قالب ترجیحی برای داده‌های حجیم است. این قالب از یک فایل متنی تشکیل می‌شود که شامل مجموعه‌ای از منابع است که با استفاده از قالب JSON نمایش داده شده‌اند و هر یک با یک خط جدید از دیگری جدا می‌شود (کاراکترهای ASCII شماره 13 و 10).

JSON مربوط به منابع، هیچ‌گونه فضای خالی غیرضروری (Unnecessary Whitespace) ندارد و نمی‌تواند شامل کاراکترهای خط جدید باشد. هر فایل متنی ND-JSON فقط شامل یک نوع منبع (Resource Type) است تا وارد کردن آن به قالب‌های پردازش پایین‌دستی (Downstream Processing) یا پایگاه‌های داده‌ای مانندApache Parquet  آسان باشد؛ هرچند این فایل‌ها را می‌توان به هر روش دلخواه دیگری نیز پردازش کرد.

 

فراخوانی ناهمگام عملیات  HTTP

یک عملیات معمولی HTTP، یک عملیات ساده درخواست/پاسخ (Request/Response) است؛ کلاینت یک اتصال TCP به سرور باز می‌کند، یک درخواست ارسال می‌کند و اتصال TCP را باز نگه می‌دارد تا پاسخ را دریافت کند. اگر پیش از دریافت پاسخ، اتصال از بین برود، کلاینت نمی‌تواند پاسخ را دریافت کند و سرور نیز آن را کنار می‌گذارد. در چنین شرایطی، کلاینت به‌سادگی درخواست اولیه را مجدداً ارسال می‌کند.

این الگو زمانی به‌خوبی عمل می‌کند که میزان کاری که سرور برای پردازش درخواست و بازگرداندن پاسخ انجام می‌دهد، حداقل باشد. با افزایش میزان کار و زمان موردنیاز، احتمال از دست رفتن اتصال TCP افزایش می‌یابد و در نتیجه، هزینه تکرار درخواست نیز بیشتر می‌شود. علاوه بر این، هیچ راهی وجود ندارد که کلاینت متوجه شود فرآیند پردازش درخواست در چه مرحله‌ای قرار دارد و برای مثال، یک نوار پیشرفت درصدی (Percentage Progress Bar) را برای کاربر انسانی نمایش دهد.

به همین دلایل، مشخصات FHIR روشی را برای فراخوانی ناهمگام یک عملیات (Asynchronous Operation) تعریف می‌کند:

  • کلاینت، درخواست را به‌عنوان یک درخواست ناهمگام علامت‌گذاری می‌کند.
  • سرور به‌جای پردازش درخواست، بررسی می‌کند که آیا انجام درخواست مجاز و قابل قبول است یا خیر، و سپس کلاینت را به یک مکان جدید هدایت می‌کند.
  • کلاینت چندین درخواست به آن مکان ارسال می‌کند و هر بار پاسخی دریافت می‌کند که نشان می‌دهد پردازش در چه وضعیتی قرار دارد.
  • در نهایت، پاسخی دریافت خواهد کرد که نشان می‌دهد پردازش به پایان رسیده است. اگر پردازش با موفقیت انجام شده باشد، علاوه بر آن، فهرستی از URLها را دریافت خواهد کرد که حاوی منابعی هستند که پاسخ درخواست اولیه محسوب می‌شوند.

این الگو را می‌توان برای هر یک از تعاملات و عملیات شرح‌داده‌شده در بالا استفاده کرد، هرچند برای بیشتر آن‌ها واقعاً منطقی نیست.

سرورها معمولاً درخواست‌های ناهمگام را برای منابع ساده نادیده می‌گیرند یا رد می‌کنند، هرچند ملزم به انجام این کار نیستند. در مورد درخواست‌هایی که نیازمند پردازش قابل‌توجهی هستند، سرورها معمولاً از کلاینت انتظار دارند که از نشانگر ناهمگام (Asynchronous Flag) استفاده کند و در صورت وجود نداشتن آن، خطا بازمی‌گردانند.

از آنجا که سرورها می‌توانند بر اساس تشخیص خود یکی از این رویکردها را انتخاب کنند، یک کتابخانه کلاینت مناسب (Good Client Library) باید بتواند در هر دو حالت کار کند.

 

آغاز فرآیند (Initiation)

یک درخواست ناهمگام با استفاده از درخواستی شامل هدر Prefer آغاز می‌شود:

GET /Patient/234/$export? Output Format=application/fhir+json

HTTP/1.1

Prefer: response-async

Accept: application/fhir+json

این درخواست، تمامی سوابق مربوط به بیمار 234 را با قالبnd-json  درخواست می‌کند (مطابق توضیحات زیر). اگر به‌جای آن خطایی بازگردانده شود، درخواست شده است که خطا در قالب JSON  بازگردانده شود. سرور در پاسخ به چنین درخواستی، مکان فرآیند پاسخ را به شکل زیر اعلام می‌کند:

HTTP 202 Accepted

Content-Location: http://random-url/6985c520-8de0-40fc-9ee8-0c9b2

b9d3470

مکان محتوا (Content-Location) لزوماً نباید روی همان سرور قرار داشته باشد، هرچند اغلب چنین است.

 

پیشرفت (Progress)

پس از آن، کلاینت درخواست‌های تکراری به این مکان ارسال می‌کند تا وضعیت پیشرفت فرآیند را بررسی کند:

GET /6985c520-8de0-40fc-9ee8-0c9b2b9d3470 HTTP/1.1

Accept: application/Json

سرور می‌تواند به یکی از سه شکل زیر پاسخ دهد:

  • پردازش همچنان در حال انجام است: کد وضعیت 202 Accepted، همراه با یک هدر اختیاریX-Progress  که می‌تواند جزئیات بیشتری را برای نمایش به کاربر انسانی ارائه کند.
  • پردازش با شکست مواجه شده است: یک کد وضعیت HTTP از نوع 5XX، همراه با یک OperationOutcome اختیاری (در قالبJSON) که شامل جزئیات بیشتری است.
  • پردازش با موفقیت انجام شده است: یک پاسخ 200 OK  همراه با یک قطعه JSON که نتیجه فرآیند را توصیف می‌کند (جدول ۶.۵).

برای هر فایل (File) موجود در خروجی (جدول ۶.۶): هیچ راهنمایی مشخصی درباره اینکه کلاینت در هنگام در حال انجام بودن کار، هر چند وقت یک‌بار باید وضعیت را پرس‌وجو کند، وجود ندارد. سرور ممکن است تعداد دفعاتی را که کلاینت می‌تواند برای دریافت به‌روزرسانی وضعیت درخواست ارسال کند، محدود کند.

کلاینت‌های مناسب، تعداد دفعات این درخواست‌ها را بر اساس مدت زمان مورد انتظار برای انجام کار و با استفاده از درخواست‌های مشابه قبلی و/یا پیکربندی تنظیم خواهند کرد و ممکن است دفعات درخواست‌ها را با مقادیری که در هدرX-Progress  اعلام شده است نیز مرتبط کنند؛ هرچند کلاینت‌ها ملزم به انجام هیچ‌یک از این اقدامات نیستند.

 

جدول ۶.۵ پیشرفت (Progress)

معنا

مقدار Progress

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

transactionTime

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

request

فهرستی از فایل‌هایی که در نتیجه پردازش درخواست تولید شده‌اند. اگر هیچ خروجی‌ای وجود نداشته باشد، این فهرست خالی است.

output

یک مقدار Boolean که مشخص می‌کند آیا برای دسترسی به خروجی، توکن دسترسی مورد استفاده برای ایجاد درخواست نیز موردنیاز خواهد بود یا خیر؛ معمولاً، اما نه همیشه، مقدار آن true است.

requiresAccessToken

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

error

جدول ۶.۶  -  مقادیر خروجی (Output Values)

شرح

مقدار

نوع منابع موجود در این فایل؛ هر فایل فقط شامل منابعی از یک نوع واحد است.

type

مسیر فایل، که در صورت نیاز می‌تواند روی سرور دیگری قرار داشته باشد.

url

تعداد منابع موجود در فایل؛ اختیاری است.

count

 

تمهیدات امنیتی پیرامون عملیات ناهمگام می‌تواند تا حدی پیچیده باشد، به‌ویژه اگر سرور، برای مثال، نتایج را در یک S3 Bucket قرار دهد که برای دسترسی به آن به توکنی متفاوت از توکنی که درخواست با آن ارسال شده است نیاز باشد؛ جزئیاتی از این دست هنوز توسط جامعه FHIR در حال بررسی و تکمیل است. جزئیات فعلی در راهنمای پیاده‌سازی Bulk Data موجود است.

 

عملیات (Operations)

یک عملیات ویژه با نام $export  تعریف شده است تا به کلاینت اجازه دهد درخواست یک مجموعه داده حجیم را ارائه کند.

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

GET [base]/Patient/234/$export?params

GET [base]/Group/acme-1/$export?params

GET [base]/$export?params

این درخواست‌ها به سرور اجازه می‌دهند یکی از موارد زیر را صادر (Export) کند: تمام داده‌های مربوط به یک بیمار خاص؛ برای مثال، «me» در یک زمینه خاص مربوط به بیمار. تمام داده‌های مربوط به یک گروه از بیماران که از پیش توافق شده است؛ برای مثال، «تمام بیماران یک پزشک عمومی خاص (GP)». تمام داده‌های موجود در سرور، شامل داده‌هایی که به بیماران مرتبط نیستند؛ مانند اصطلاح‌شناسی (Terminology)، منابع انطباق (Conformance Resources)، پرسشنامه‌ها (Questionnaires) و سایر تنظیمات.

این عملیات دارای سه پارامتر اختیاری است (جدول ۶.۷):

جدول ۶.۷ - پارامترهای اختیاری برای عملیات داده‌های حجیم

در صورت عدم وجود

معنا

نام

به‌صورت پیش‌فرض application/fhir+ndjson

قالب فایل‌های درخواستی

_outputFormat

تمام منابع موجود تا آن زمان

فقط منابعی را شامل می‌شود که از این زمانِ سرور تغییر کرده‌اند؛ این زمان از transactionTime که در بالا توضیح داده شد گرفته می‌شود.

_since

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

فهرست جداشده با کاما از انواع منابعی که باید بازگردانده شوند

_type

در تمام موارد، این موضوع که چه داده‌ای بازگردانده شود، بنا بر تشخیص سرور و با توجه به محدودیت‌های عملیاتی و امنیتی تعیین می‌شود. یک کلاینت نمی‌تواند داده‌ای را بازیابی کند که کاربر مجوز دسترسی به آن را ندارد، یا در صورتی که ازOAuth  استفاده می‌شود، داده‌ای را که کاربر به کلاینت اجازه دسترسی به آن را نداده است.