_include, _revinclude, _with

Include associated resources

Configuration

Include Conformant Mode

Since 2402, Aidbox has a FHIR-compliant behavior for _include and _revinclude parameters. It is recommended to turn it on.

To toggle on:

BOX_SEARCH_INCLUDE_CONFORMANT=true

Also, there's a way to set the maximum number of iterations for :iterate modifier:

BOX_SEARCH_INCLUDE_ITERATE__MAX=5

Differences between FHIR-conformant and Aidbox mode

Due to historical reasons Aidbox treats the _include and _revinclude parameters slightly differently from the behavior described in the specification (without FHIR-conformant mode on).

  1. The _(rev)include search parameter without the :iterate or :recurse modifier should only be applied to the initial ("matched") result. However, in Aidbox mode, it is also applied to the previous _(rev)include.

  2. The _(rev)include parameter with the :iterate(:recurse) modifier should be repeatedly applied to the result with included resources. However, in Aidbox mode, it only resolves cyclic references.

  3. In Aidbox mode, it is possible to search without specifying source type: GET /Patient?_include=general-practitioner, but in the FHIR-conformant mode it is not possible.

Authorize Inline Requests Mode

Aidbox provides access control for inline requests (_include & _revinclude) to ensure users can only retrieve resources they are authorized to view. When a search request contains an inline query, Aidbox verifies access by performing an authorization check against a search query for the included resource. If the requesting user lacks the necessary access rights to the included resource, the entire request is denied with a 403 status. To enable access control for inline requests, set the following environment variable:

.env
BOX_SEARCH_AUTHORIZE_INLINE_REQUESTS=true

AccessPolicy Examples with Authorize Inline Requests Mode

Below are examples of AccessPolicy configurations that allow requests such as:

/fhir/Patient?_include=Patient:organization

With this AccessPolicy, the user can use any _include parameters that result in Organization resources being included. However, the query will be rejected if it attempts to include any other resource types.

  operation:
    id: "FhirSearch"
  params:
    resource/type: "Patient"
  user:
    id: "my-user-1"
    resourceType: "User"

  operation:
    id: "FhirSearch"
  params:
    resource/type: "Organization"
  user:
    id: "my-user-1"
    resourceType: "User"

AccessPolicy Examples without Authorize Inline Requests Mode

If this mode is not enabled, you must define the specific _include or _revinclude parameters allowed in an AccessPolicy, as shown in the example below. However, this method can be inflexible, and we recommend using Authorize Inline Requests Mode in most cases.

  operation:
    id: "FhirSearch"
  params:
    resource/type: "Patient"
    _include: "Patient:organization"
  user:
    id: "my-user-1"
    resourceType: "User"

_include

Syntax for the _include search parameter:

 _include(:reverse|:iterate|:logical)=source-type:search-param:(:target-type)

Here search-param is a name of the search parameter with the type reference defined for source-type.

This query can be interpreted in the following manner. For the source-type resources in the result include all target-type resources, which are referenced by the search-param.

target-type is optional for not chained includes and means all referenced resource-types:

GET /Encounter?_include=Encounter:subject 
=> GET /Encounter?_include=Encounter:subject:*

For more explicit interpretation and for performance reason, client must provide target-type for chained includes!

_include=*

You can include all resources referenced from the search result using *. This is considered bad practice because it's too implicit.

This feature is only implemented for conformance with the FHIR specification.

Please avoid using it!

GET /Encounter?_include=*
GET /Encounter?_include=Encounter:*

_revinclude

Syntax for revinclude:

_revinclude(:reverse|:iterate|:logical)=source-type:search-param(:target-type)

Interpretation: include all source-type resources, which refer target-type resources by search-param in the result set.

Chained (rev)includes

Client can chain (rev)includes to load next level of references. (Rev)includes should go in a proper loading order. According to the FHIR specification, for chained includes a client must specify the :iterate modifier. However, in Aidbox mode this modifier is optional.

GET /RequestGroup?_include=encounter\
  &_include=patient:Patient\
  &_include=Patient:organization\
  &_revinclude=AllergyIntolerance:patient:Patient\
  &_revinclude=Condition:subject:Patient\
  &_include=author:PractitionerRole\
  &_include=PractitionerRole:practitioner:Pracitioner\
  &_include=PractitionerRole:location\
  &_revinclude=Contract:subject:PractitionerRole\
  &_include=MedicationRequest:medication\
  &_include=MedicationRequest:requester:PractitionerRole\
  &_include=MedicationRequest:intended-performer:Organization\
  &_include=MedicationRequest:intended-performer:Organization

Client must always specify target-type and source-type for intermediate (rev)includes because this is explicit and allows Aidbox to prepare dependency graph before query!

Here is the discussion in the FHIR chat about the :iterate ambiguity. We appreciate your opinion!

Recursive (rev)includes

For self-referencing resources, you can specify the :recurse or :iterate modifier with source-type=target-type to recursively get all children or parents:

GET /Observation?_include:recurse=Observation:has-member
GET /Observation?_include:iterate=Observation:has-member:Observation
# get all children
GET /Organization?_revinclude:recurse=Organization:partof

(rev)include and _elements

You can use the extended elements parameter to control elements of (rev)included resources by prefixing desired elements with the resource type:

GET /Encounter?_include=patient&_elements=id,status,Patient.name,Patient.birthDate

:logical modifier

If you provide :logical modifier, Aidbox will include logically referenced resources as well. Logical reference means reference with attribute type set to resource-type and identifier attribute set to one of identifier of referenced resource.

Example:

GET /Encounter?_include:logical=Encounter:patient
GET /Encounter?_with=patient:logical
GET /Patient?_revinclude:logical=Encounter:patient:Patient
GET /Patient?_with=Encounter.patient:logical

Using the _with parameter

FHIR (rev)include syntax is non-DRY and sometimes confusing. We introduced the _with parameter that is a simple (like GraphQL) DSL to describe includes in a more compact way.

expr = param-expr (space param-expr)*
param-expr = param  ( '{' typed-ref-expr (space typed-ref-expr)* '}')?
typed-ref-expr = resource-type | resource-type '{' expr '}'
param = resource-type '.' param-name  (':recur' | ':logical') ? | param-name (':recur' | ':logical') ?
space = ',' | ' ' | '\n'
param-name = ALPAHNUM

Examples:

Encounter?_with=patient
=> Encounter?_include=Encounter:patient
---
Encounter?_with=patient,participant
=> Encounter?_include=Encounter:patient,Encounter:participant
---
Encounter?_with=patient{Patient}
=> Encounter?_include=Encounter:patient:Patient
---
Encounter?_with=patient{Patient{organization}}
=> Encounter?_include=Encounter:patient:Patient&
             _include(:iterate)=Patient:organization
---            
Encounter?_with=patient{Patient{organization{Organization{partof:recur}}}}
=> Encounter?_include=Encounter:patient:Patient&
             _include(:iterate)=Patient:organization
             _include(:recurse)=Organization:parto-of           
---             
Patient?_with=organization,Condition.patient,MedicationStatement.patient{medication}
=> Patient?_include=Patient:organization&
           _revinclude=Condition:patient:Patient
           _revinclude=MedicationStatement:patient:Patient
           _include=MedicationStatement:medication
---             
RequestGroup?_with=
 author
 patient{Patient{organization,AllergyIntolerance.patient}}
 target{
  MedicationRequest{
    medication
    intended-performer{Organization}
    requester{PractitionerRole{practitioner,location}}}}
=>
RequestGroup?_include=patient,author
    &_include:iterate=RequestGroup:target:MedicationRequest
    &_include:iterate=MedicationRequest:medication
    &_include:iterate=MedicationRequest:requester:PractitionerRole
    &_include:iterate=MedicationRequest:intended-performer:Organization
    &_include:iterate=PractitionerRole:practitioner
    &_include:iterate=Patient:organization
    &_include:iterate=PractitionerRole:location
    &_revinclude:iterate=AllergyIntolerance:patient
 ---
 Organization?partof:recur{Organization}
 => Organization?_include:recurse=partof:Organization

Last updated