************** ## Reading material ************** ### 1. Chaining and reverse chaining #### 1.1 Chaining Chaining allows you to search on properties of a referenced resource. This means that you can go through a graph of connected resources and get back a result by using search parameters defined for the last resource type in a chain. To illustrate how chaining works in practice, let's go through an example. An Observation contains a reference to a Patient resource in the `subject` element. The search parameters `patient` and `subject` allow you to filter Observations on a specific subject (the difference being that the `patient` search parameter is restricted to the resource type Patient, while the `subject` search parameter searches for all resource types that can be the subject of the Observation). Now suppose you want to filter the Observations based on properties of the Observation's subject. To do so, you would only need to append the search parameter (e.g. `patient`) with a `.` followed by a valid search parameter for the referenced resource (e.g. `birthdate`). For example, to search for all Observations from Patients born since the 1st of January 2001, you would get: ``` GET [base]/Observation?patient.birthdate=ge2001-01-01 ``` Note that you could also use the `subject` search parameter, but in this case, you will still need to specify the resource type that you are looking for. It's not allowed to address multiple resource types at the same time (correctly implemented FHIR servers will reject searches in which this is the case). The correct syntax for the same search based on the `subject` parameter is as follows: ``` GET [base]/Observation?subject:Patient.birthdate=ge2001-01-01 ``` Without chaining you would have needed multiple search requests to perform this search: 1) Get all Patients with the specified birthdate 2) Get all Observations which contain a reference to the Patients that were gathered in the previous request. It would be nessesarry to do some kind of filtering and processing on the client side. Please note, you can only chain search parameters of the type `reference` that point to elements of type `Reference.reference`. In FHIR, references using so-called logical references (using `Reference.identifier`) are also allowed. However, because a FHIR Server cannot reasonably verify that the resources behind these references exist, chaining on these elements are not supported. Chaining can be very efficient as you can cross more than one resource in a single chain. For example, try to search for all Observations based on a MedicationRequest for a Medication that contains the ingredient Lorazepam (substance): ``` GET [base]/Observation?basedOn:MedicationRequest.medication.ingredient-code=387106007 ``` Note that except for the last parameter, all parameters are of the type `reference`. #### 1.2 Reverse chaining Instead of filtering resources based on properties of referenced resources, it's also possible to filter resources based on properties of resources referring to them. For example, you may want to select all Patients having an appointment today. In this case, you would need to use the `_has` parameter followed by: - the type of the referring resource (e.g. `Encounter`) - the name of the search parameter containing the reference to the base resource (e.g. `patient`) - the name of the search parameter you want to filter upon (e.g. `date`) and the comparison value These parts are separated by a `:`. The correct syntax of this search would be: ``` GET [base]/Patient?_has:Encounter:patient:date=[today] ``` Let's make it a bit more complex. Say you want to select all Patients having an Observation performed by a specific Organization, let's assume the identifier of this Organization is `1234`. ``` GET [base]/Patient_has:Observation:patient:performer:Organization.identifier=1234 ``` It's also possible to add more than one `_has` parameter to your search. But be aware that this would result in a joined set of two independently executed `_has` queries. For example, the following query: ``` GET [base]/Patient?_has:Encounter:patient:date=[today]&_has:Encounter:practitioner=1234 ``` will not result in a list of Patients having an appointment with Practitioner `1234` today. Instead, it will return all Patients having an appointment today as well as all Patients having an appointment with Practitioner `1234` at any point in time. ### 2. Filter A _filter expression can be used for more advanced searches in which multiple queries need to be combined. _filter provides a range of advantages compared to the regular way of using search parameters: * Being able to use logical OR and NOT operatiors * Use parentheses to form logical groups * Use aliases for commonly used Code Systems For example, you could use a filter to select all Patients from Organizations `1234` and `1235` with inactive records. ``` GET [base]/Patient?_filter=active eq false and ( organization eq 1234 and organization eq 1235 ) ``` Note that this expression is equivalent to: ``` GET Patient?active=false&organization=1234,1235 ``` It gets more challenging when you want to combine these queries with an `or`. For example, when you want to select all Patients with an inactive record as well as all Patients from Organizations `1234` or `1235` you will definitely need a filter. ``` GET [base]/Patient?_filter=active eq false or ( organization eq 1234 or organization eq 1235 ) ``` Would you have tried to define this expression as following: ``` GET Patient?active=false,organization=1234,1235 ``` The server would interpret this as a search for Patients where the value of `active` is either 'false', 'organization=1234' or '1235', which is obviously not what we try to achieve. All search parameters that are normally defined for resources can be used in a _filter expression. Additionally, negated expressions can be used in a filter search request. This feature can otherwise only be achieved with the `:not` modifier for token search parameters. For example, the following search request retrieves all Patient resources which contain a different name than "Sarah": ``` GET Patient?_filter=name ne Sarah ``` ### 3. Compartment search Another powerful search function is the compartment search. The syntax of a compartment search is as follows: ``` GET [base]/[compartment]/[id]/[ResourceWithOutgoingReference]?[SearchParam]= ``` Adding search parameters to a compartment search is optional. To return all resources in a compartment use a `*` instead. For example, use the following request to select all resources that have any reference to the Patient with id `1234`. ``` GET [base]/Patient/1234/* ``` You can also define the types of resources you want to retrieve using the `_type` parameter. For example, the following request will return all Observations and Encounters of the Patient with id “1234”. ``` GET [base]/Patient/1234/?_type=Observation,Encounter ``` Finally, you can add additional criteria to your compartment search. Let's say you want to retrieve all Observation resources that contain a reference to the Patient with the logical id `1234` and which have the observation status set to final. The following requests, of which the first one is the compartment search, are both valid and will produce the exact same results. ``` GET [base]/Patient/1234/Observation?status=final GET [base]/Observation?subject=Patient/1234&status=final ``` ### 4. Composite search parameters (pairs) Composite search parameters are parameters that take a combination of values to evaluate. For example, the composite search parameter `component-code-value-quantity` evaluates Observations against a pair of values for the elements `code` and `valueQuantity`. The values are separated by `$`. The request given below returns all Observations with the given LOINC code and a value greater than 80kg. ``` GET [base]/Observation?component-code-value-quantity=http://loinc.org|29463-7$gt80||kg ``` Note that this search would be equivalent to the following request using the `code` and `value-quantity` search parameters: ``` GET [base]/Observation?code=http://loinc.org|29463-7&value-quantity=gt80||kg ``` The power of composite search parameters becomes more clear in the following examples based on the composite search parameter `characteristic-value`, which searches for the pair of values for `characteristic` and `value`. ``` GET [base]/Group?characteristic-value=gender$mixed GET [base]/Group?characteristic-value=gender$mixed,owner$peter ``` The first one returns all Groups where the gender is mixed. In this case using the parameters `characteristics` and `value` (e.g. characteristic=gender&value=mixed) would not return the same results. Groups having the characteristic gender and the value female and having the value mixed for another key would be returned as well. The second one returns all Groups where gender is mixed as well as groups where the owner is peter. These kinds of searches would be impossible to express without composite search parameters. ### 5. Including other resources in result #### 5.1 Include Sometimes it can be useful to include related resources in your search results. For example, when you search for Observations, it can be useful to include the Patient resources that are subject of the returned Observations. ``` GET [base]/Observation?_include=Observation:patient GET [base]/Observation?_include=Observation:patient&patient=1234 ``` The first request returns all Observations and the related Patient resources. The second one returns all Observations for a specific Patient with id=1234 as well as the Patient resource itself. It is possible to include multiple related resources by repeating the `include` parameter. #### 6.2 Revinclude Instead of adding resources that are referenced from the returned resources in your search results, you may also want to add resources that refer to them. For example, when you are searching for Patients, you may want to add Observations and Conditions that have a reference to these Patients in their `subject` fields. The request below returns a specific Patient (the Patient with id=1234) and includes all Observation and Condition resources of this Patient in the search Bundle. ``` GET [base]/Patient?_revinclude=Observation:patient&_revinclude=Condition:patient&_id=1234 ``` A revinclude may come in handy in combination with a reverse chaining expression. You can get back the resources due to which the matches of the reverse chaining where included in the search results: ``` GET [base]/Patient?_has:Observation:patient:code=29463-7&_revinclude=Observation:patient ``` #### 6.3 Recursion The include and revinclude process can be recursive. With a `:recurse` modifier, resources can be included based on parameters defined for resources that were included through a different _include or _revinclude expression: ``` GET [base]/Patient?_has:Observation:patient:code=29463-7&_revinclude=Observation:patient&_revinclude:recurse=DiagnosticReport:result ``` ### 6. Operations FHIR provides a set of operations that can be invoked on the base endpoint, a resource type, a resource instance or a specific version of a resource instance. Usually, operations are invoked using a POST request, but in some cases, a GET request is allowed as well. To invoke an operation its name should be prefixed with a `$`. Below is an example of an operation that retrieves all resources related to Patient with ID=1234. Note that this is similar to a compartment search. ``` POST [base]/Patient/1234/$everything ``` The body of a request invoking an operation often contains a Parameters resource to specify the in parameters of the operation. For example, in the `everything` operation optional start and end dates can be provided. The body may also contain other resources, for example, the resource you want to validate by using the `validate` operation. Operations can be resource specific or apply to all resource types. In the last case, we speak about base operations. It is also possible for implementations to define their own operations using the [OperationDefintion](https://www.hl7.org/fhir/operationdefinition.html) resource. #### 6.1 Validate One operation that is often used is the `validate` operation. Let's say you want to validate a Patient resource against the daf-patient profile. You could do so by running the following request and adding your Patient resource in the request body. ``` POST [base]/Patient/$validate?profile=http://hl7.org/fhir/StructureDefinition/daf-patient ``` #### 6.2 Expand ValueSets are often composed of codes from other ValueSets or CodeSystems by using include and exclude filters. As you will learn (or already have learned) in the [Terminology] module, ValueSets contain both a `compose` element, which is used to create a ValueSet, and an `expansion` element, which can be used by a FHIR Terminology server to return all codes in a ValueSet. Below are a couple of example requests. ``` GET [base]/ValueSet/1234$expand POST [base]/ValueSet/$expand POST [base]/ValueSet/1234/$expand ``` The GET request can be used when a ValueSet is already known to the server. When a POST request is used, the request body contains a Parameters resource in which one or more in parameters are defined. The Parameters may include the ValueSet resource or contain a canonical url of an existing ValueSet. The returned result of the `expand` operation is the expanded ValueSet resource. Note that the expansion can change over time depending on changes in included ValueSets and CodeSystems.