FHIR サーバのカスタマイズ
FHIR® サーバを使用する場合、FHIR サーバの動作をカスタマイズするためのストラテジが 2 つあります。従来の FHIR テクノロジのように、相互運用プロダクションでロジックを使用して、サーバの動作を変更できます。ただし、FHIR サーバのアーキテクチャをカスタマイズして、カスタムの機能を実装するオプションもあります。このオプションは、相互運用プロダクションを使用しない FHIR サーバは、これを使用する FHIR サーバよりも著しく高速にできるため重要です。
サーバ・アーキテクチャをカスタマイズする場合は、サーバの環境に固有な部分のみをカスタマイズする、リソース・リポジトリの拡張が最も一般的です。稀なケースとして、FHIR サーバに完全なカスタム・バックエンドを記述する必要がある場合があります。FHIR サーバのアーキテクチャにより、このような柔軟性が与えられています。リソース・リポジトリを拡張するのか、カスタム・バックエンドを記述するのかに関係なく、FHIR サーバのカスタマイズ・プロセスはインストール前のサブクラスの作成から始まります。
FHIR サーバの一部の動作は、アーキテクチャのカスタマイズを必要としない構成オプションを通じて制御されます。これらのオプションの詳細は、"FHIR サーバの構成" を参照してください。
FHIR サーバをカスタマイズするときに、サーバの機能宣言書を更新できます。詳細は、"機能宣言書の変更" を参照してください。
インストール前のサブクラスの作成
FHIR サーバをカスタマイズするには、まず、IDE を使用してアーキテクチャのサブクラスを作成し、いくつかのパラメータを定義します。InteractionsStrategy はインストール時に指定されるため、この手順は、サーバのエンドポイントがインストール・プロセスで作成される前に実行する必要があります。
通常、FHIR サーバはリソース・リポジトリのアーキテクチャを拡張しています。このような場合は、IDE とサブクラスを開きます。
-
HS.FHIRServer.Storage.Json.Interactions
-
HS.FHIRServer.Storage.Json.InteractionsStrategy
-
HS.FHIRServer.Storage.Json.RepoManager
リソース・リポジトリを使用する代わりに FHIR サーバの完全なカスタム・バックエンドを記述している場合は、次のアーキテクチャのスーパークラス HS.FHIRServer.API.Interactions、HS.FHIRServer.API.InteractionsStrategy、および HS.FHIRServer.API.RepoManager のサブクラスを作成します。
サブクラスのパラメータ
IDE を使用して Interactions、InteractionsStrategy および RepoManager サブクラスを作成したら、InteractionsStrategy と RepoManager の以下のパラメータを変更する必要があります。
スーパークラス |
サブクラスのパラメータ |
HS.FHIRServer.API.InteractionsStrategy |
|
HS.FHIRServer.API.RepoManager |
|
サブクラスをコンパイルしたら、FHIR サーバをインストールする準備が整います。あとは、インストール中に、InteractionsStrategy サブクラスの名前を指定するだけです。
カスタム・コードの有効化
開発時にカスタムの Interactions または InteractionsStrategy コードに変更を加える場合は、次の FHIR 要求が行われるときに、[新しいサーバ・インスタンス] デバッグ・オプションを使用して新しいコードを有効化します。詳細は、"FHIR サーバのデバッグ" を参照してください。
リソース・リポジトリのカスタマイズ
リソース・リポジトリの FHIR サーバ・アーキテクチャのサブクラスを作成したら、サーバをカスタマイズする準備は完了です。通常、カスタマイズには、HS.FHIRServer.Storage.Json.Interactions のサブクラスのメソッドとパラメータのオーバーライドが含まれます。以下に、リソース・リポジトリを使用する FHIR サーバに実行できる最も一般的なカスタマイズについて説明します。
カスタマイズのクイック・スタート
目標 |
HS.FHIRServer.Storage.Json.Interactions のサブクラスのアクション |
特定の FHIR 相互作用のカスタマイズ |
相互作用に対応するメソッドをオーバーライドします。 |
すべての要求の処理 |
OnBeforeRequest をオーバーライドして、ユーザに透過的なロジックを実装します。このオーバーライドされたメソッドには、スーパー・クラスの呼び出しが含まれる必要があります。例えば、Do ##super(pFHIRService, pFHIRRequest, pTimeout) のようになります。
FHIR クライアントに要求の処理が異なることを認識させる場合は、カスタムの FHIR オペレーションを作成します。 |
すべての要求の後処理 |
OnAfterRequest をオーバーライドして、ユーザに透過的なロジックを実装します。このオーバーライドされたメソッドには、スーパー・クラスの呼び出しが含まれる必要があります。例えば、Do ##super(pFHIRService, pFHIRRequest, .pFHIRResponse) のようになります。
FHIR クライアントに要求の処理が異なることを認識させる場合は、カスタムの FHIR オペレーションを作成します。 |
Read 相互作用の結果の後処理 |
PostProcessRead をオーバーライドします (例)。 |
Search 相互作用の結果の後処理 |
PostProcessSearch をオーバーライドします (例)。 |
カスタムの FHIR オペレーションの追加 |
OperationHandlerClass パラメータをオーバーライドして、HS.FHIRServer.Storage.BuiltInOperations のサブクラスの名前を指定します。"カスタムの FHIR オペレーション" を参照してください。 |
バンドルの処理方法のカスタマイズ |
BatchHandlerClass パラメータをオーバーライドして、カスタム・クラスの名前を指定します。既定のハンドラ・クラスは HS.FHIRServer.DefaultBundleProcessor です。 |
OAuth トークンの処理方法のカスタマイズ |
OAuth2TokenHandlerClass パラメータをオーバーライドして、カスタム・クラスの名前を指定します。既定のハンドラ・クラスは HS.FHIRServer.Util.OAuth2Token です。 |
以下のコード・サンプルでは、リソース・リポジトリを使用する FHIR サーバに実行できるカスタマイズをいくつか示します。
結果の後処理
Read 相互作用や Search 相互作用の結果を操作したいことはよくあります。例えば、Read 相互作用によって返された Patient のデータを変更したり、検索結果から特定のリソースを除外したい場合などです。以下の例では、結果は同意ルールに基づいて変更されます。このサンプル・コードでは、同意処理に対応するために別個のクラスが記述されていることを前提としています。要求から抽出されるロールは InterSystems セキュリティ・ロールです。
Class MyCustom.FHIR.Interactions Extends HS.FHIRServer.Storage.Json.Interactions
{
Property RequestingUser As %String [ Private, Transient ];
Property RequestingUserRoles As %String [ Private, Transient ];
Method OnBeforeRequest(pFHIRService As HS.FHIRServer.API.Service,
pFHIRRequest As HS.FHIRServer.API.Data.Request,
pTimeout As %Integer)
{
//Extract the user and roles for this request
//so consent can be evaluated.
set ..RequestingUser = pFHIRRequest.Username
set ..RequestingUserRoles = pFHIRRequest.Roles
}
Method OnAfterRequest(pFHIRService As HS.FHIRServer.API.Service,
pFHIRRequest As HS.FHIRServer.API.Data.Request,
pFHIRResponse As HS.FHIRServer.API.Data.Response)
{
//Clear the user and roles between requests.
set ..RequestingUser = ""
set ..RequestingUserRoles = ""
}
Method PostProcessRead(pResourceObject As %DynamicObject) As %Boolean
{
//Evaluate consent based on the resource and user/roles.
//Returning 0 indicates this resource shouldn't be displayed - a 404 Not Found
//will be returned to the user.
if '##class(MyCustom.Consent).Consented(pResourceObject,
..RequestingUser,
..RequestingUserRoles) {
return 0
}
//Modify (anonymize) the resource being returned to the client if they don't have
//permission to see the full record.
if (pResourceObject.resourceType = "Patient") &&
##class(MyCustom.Consent).Anonymize(..RequestingUser, ..RequestingUserRoles) {
do pResourceObject.%Remove("name")
}
return 1
}
Method PostProcessSearch(pRS As HS.FHIRServer.Util.SearchResult,
pResourceType As %String) As %Status
{
//Iterate through each resource in the search set and evaluate
//consent based on the resource and user/roles.
//Each row marked as deleted and saved will be excluded from the Bundle.
do pRS.%SetIterator(0)
while(pRS.%Next()) {
set resourceObject = ..Read(pRS.ResourceType, pRS.ResourceId, pRS.VersionId)
if '##class(MyCustom.Consent).Consented(resourceObject, ..RequestingUser,
..RequestingUserRoles)
{
do pRS.MarkAsDeleted()
do pRS.%SaveRow()
}
}
do pRS.%SetIterator(0)
quit $$$OK
}
}
Tip:
FHIR サーバをカスタマイズする場合は、リソースが共有リソースかどうかを判断すると便利です。共有リソースには、Patient 情報は含まれません。FHIR の条件では、これらのリソース・タイプは Patient コンパートメントには存在しません。IsSharedResourceType メソッドを使用すると、リソースが共有されているかどうかを判断できます。例えば、カスタムの Interactions クラスには、以下の条件文を含めることができます。
Class MyCustom.FHIR.Interactions Extends HS.FHIRServer.Storage.Json.Interactions
Method OnBeforeRequest(pFHIRService As HS.FHIRServer.API.Service,
pFHIRRequest As HS.FHIRServer.API.Data.Request,
pFHIRResponse As HS.FHIRServer.API.Data.Response)
{
If pFHIRService.Schema.IsSharedResourceType(pFHIRRequest.Type) {
//Do x,y,z
}
カスタム ID のリソースへの割り当て
Create 相互作用を実行する際に、リソース・リポジトリ・サーバをカスタマイズして、各リソースにカスタム ID を割り当てることができます。以下の例では、リソースをリソース・リポジトリに格納するときに、ランダムな UUID をこのリソースに割り当てます。
Class MyCustom.FHIR.Interactions Extends HS.FHIRServer.Storage.Json.Interactions
{
Method Add(pResourceObj As %DynamicObject, pResourceIdToAssign As %String = "",
pHttpMethod = "POST") As %String
{
//Assign a random UUID for each new resource's ID, except for when processing an
//Update as Create (when a user uses the PUT method and explicitly defines the ID).
if pHttpMethod '= "PUT" {
set pResourceIdToAssign = $zconvert($system.Util.CreateGUID(), "L")
}
return ##super(pResourceObj, pResourceIdToAssign, pHttpMethod)
}
}
機能宣言書の変更
FHIR サーバの機能宣言書Opens in a new tabは、サーバの動作方法を記したクライアント向けのメタデータです。FHIR クライアントは、機能宣言書を取得して、サーバが予期する内容と FHIR 要求の処理方法を判断できます。FHIR サーバをカスタマイズするときに、機能宣言書を更新して FHIR クライアントがサーバのサポート内容に関する正確な記述を保持できるようにすることもできます。機能宣言書の更新には、次の 2 つのオプションがあります。
-
既存の機能宣言書を取得し、その JSON を編集して、サーバに戻します。簡単ではあるものの、この手法には限界があります。例えば、新しい検索パラメータの追加などの特定のアクションによって機能宣言書は自動的に再生成されるため、これらのアクションのいずれかの実行後に、カスタマイズした機能宣言書の復元が必要になる場合があります。詳細は、"機能宣言書の手動更新" を参照してください。
-
機能宣言書を生成するメソッドをオーバーライドして、InteractionsStrategy サブクラスを変更します。これにより、機能宣言書に対する制御が向上するため、再生成されても問題は発生しません。詳細は、"機能宣言書メソッドのオーバーライド" を参照してください。
機能宣言書の手動更新
REST クライアントまたはプログラムを使用して FHIR サーバの機能宣言書を取得し、テキスト・エディタまたはサードパーティのツールを使用してこれを編集して、サーバを新しいバージョンに更新できます。新しい検索パラメータの追加などの特定のアクションの実行後に、この手順を繰り返す必要がある場合があることに注意してください。したがって、必要に応じ、作成し直すのではなく改訂した機能宣言書のコピーを保存しておくことをお勧めします。
以下の例では、InterSystems サーバの IP アドレスが 172.16.144.98、スーパーサーバ・ポートが 52782、エンドポイントのベース URL が /fhirapp/r4 であると想定しています。
-
REST クライアントで機能宣言書を取得するには、GET 要求を base-url/metadata に送信します。例を以下に示します。
GET http://172.16.144.98:52782/fhirapp/r4/metadata
-
プログラムを使用して機能宣言書を取得し、JSON ファイルとして保存するには、以下のように入力します。
set strategy = ##class(HS.FHIRServer.API.InteractionsStrategy).GetStrategyForEndpoint("/fhirapp/r4")
set interactions = strategy.NewInteractionsInstance()
set capabilityStatement = interactions.LoadMetadata()
do capabilityStatement.%ToJSON("c:\localdata\MyCapabilityStatement.json")
機能宣言書を変更したら、改訂したバージョンを InterSystems ターミナルからサーバにプログラムによって送信します。以下の例では、/fhirapp/r4 はエンドポイントのベース URL で、MyCapabilityStatment.json は改訂したバージョンです。{}.%FromJson メソッドは JSON ファイルを取り、それをダイナミック・オブジェクトに配置します。
set strategy = ##class(HS.FHIRServer.API.InteractionsStrategy).GetStrategyForEndpoint("/fhirapp/r4")
set interactions = strategy.NewInteractionsInstance()
set newCapabilityStatement = {}.%FromJSON("c:\localdata\MyCapabilityStatement.json")
do interactions.SetMetadata(newCapabilityStatement)
機能宣言書のメソッドのオーバーライド
特定の FHIR サーバの動作を変更すると、機能宣言書が自動的に再生成されるため、手動更新するのではなく、サーバの機能宣言書の生成に使用するメソッドをオーバーライドすることもできます。これには、IDE の開発タスクが必要ですが、生成プロセスの制御は向上します。これらのタスクは、HS.FHIRServer.Storage.Json.InteractionsStrategy のサブクラスを作成して、リソース・リポジトリが拡張済みであると想定しています。このサブクラスでオーバーライドが必要となるメソッドは、サーバのパブリッシャのように基本のメタデータを編集するのか、サーバの機能の記述を変更するのかによって異なります。
機能宣言書内で、サーバ名など、サーバの基本メタデータを変更するだけの場合は、機能宣言書の生成元である JSON テンプレートを変更できます。この JSON テンプレートは、エンドポイントの InteractionsStrategy クラスの GetCapabilityTemplate() メソッドにあります。サーバのメタデータ文字列を変更するには、以下の手順に従います。
-
HS.FHIRServer.Storage.Json.InteractionsStrategy のサブクラスに GetCapabilityTemplate メソッドを作成し、そのメソッドをオーバーライドします。
-
HS.FHIRServer.Storage.Json.InteractionsStrategy.GetCapabilityTemplate() の内容をサブクラスの GetCapabilityTemplate() メソッドにコピーします。
-
メタデータ文字列を編集し、サブクラスをコンパイルします。
-
コンソール設定ユーティリティを使用して、機能宣言書を更新します。詳細は、"コマンド行オプション" を参照してください。
リソースでサポートされている相互作用など、機能宣言書の内容を変更する場合は、InteractionsStrategy の GetMetadataResource() メソッドをオーバーライドする必要があります。オーバーライド・メソッドで ##super を呼び出して HS.FHIRServer.Storage.Json.InteractionsStrategy.GetMetadataResource() を起動し、メソッドから返される機能宣言書を後処理することを強くお勧めします。返された機能宣言書をダイナミック・オブジェクトとして変更します。例えば、サブクラスは次のようになります。
Class Pkg.MyInteractionsStrategy Extends HS.FHIRServer.Storage.Json.InteractionsStrategy
{
Method GetMetadataResource()
{
set MyCapabilityStatement = ##super()
// manipulate MyCapabilityStatement as a DynamicObject
return MyCapabilityStatement
}
}
機能宣言書を生成するメソッドをオーバーライドしたら、コンソール設定を使用して機能宣言書を更新してください。詳細は、"コマンド行オプション" を参照してください。