You are on page 1of 31

Building a FHIR Facade

Theo Stolker

November 20-22, Amsterdam | @HL7 @FirelyTeam | #fhirdevdays | www.devdays.com

HL7®, FHIR® and the flame Design mark are the registered trademarks of Health Level Seven International and are used with per mission.
Agenda
• Intro
• Setting the Stage
• Where to start?

• Q&R
Intro
• Theo Stolker
• Principal Integration Architect at
Philips VitalHealth.
• Electrical Engineer by training
• Active in Software Development
since 1987
• Active in Application Integration
since 1998
• Implementing FHIR since 2014
Why this presentation?
• As part of my work I am involved in building
facades for a number of applications
• Goals:
• Share Findings
• Define Best Practices
Setting the Stage
Assumptions: (Smart)
• You want to expose Your HealthCare App Bridge/Broker Client
through a FHIR REST API App

• The data model of the app can’t change


Query; Update?
Types of interactions will use your id

a) Client Read-only Facade


b) Client Read-write (dedicated app)
c) Batch processing/Application Integration Your
Posts batch bundles;
Healthcare DB
Can’t use your id
App
Alternative: FHIR Store with event channel
• Use a FHIR Store as secondary storage
• Works great for read-only scenarios
• Might works also for read-write FHIR Client
scenario’s – but certainly has some risks

Your
FHIR Event
Healthcare DB
Store Channel
App
Internal structure
• Dynamically loaded “plugin” class to implement
mapping to/from internal storage per FHIR
resource
1. void Read(FHIRRequestContext FRC, FHIRResponse FR);
2. Resource GetResourceFromObject(XmlObject
bodyMeasurement);
3. bool AddSearchColumn(TypeMetadata typeMetadata,
List<ISearchFilterItem> LSC, QueryParam queryParam);
4. void InsertOrUpdate(FHIRRequestContext FRC, FHIRResponse
FR, Resource ResourceToBeUpdated, XmlObject Observation);
5. void InvokeOperation(FHIRRequestContext FRC, FHIRResponse
FR, Parameters parameters);
What FHIR version(s) are you going to support?
• Current version = R4
• Markets and/or partners may
require supporting a previous
version
• Support multiple versions if
needed
• Be ready for known/planned
changes in later version(s)!
Resource Mapping – What resources
1. What data / resources must be exposed?
Start identifying key resources!
2. Be as specific as possible
 Not everything is an Observation,
QuestionnaireResponse or Basic resource
3. FHIR is about Healthcare resources
 Not everything maps to FHIR
Resource Mapping – Be predictable!
• Imperfections:
• Multiple internal object types map to
the same FHIR resource
• A single internal object type maps to
multiple FHIR resources
Reduce the supported scope to
something that works consistently
Imperfect Mapping Example 1 – Vital Signs
• Blood pressure - diastolic and systolic
values stored as 2 separate records
• GET /Observation without code
would lead to duplicate BP resources
being returned.
• Possible solutions
• Always require client to filter for a [set
of] specific codes
• Filter so that by default only diastolic
values are returned
Imperfect Mapping Example 2 – Observation flavors
• Labs might be stored different from
patient self measurements, vitals or
device measurements.
• Works as long as supported codes for
each subset are unique
• Use “micro-facades” where each
data type is represented using a
different endpoint
Element Mapping – it is not just semantics
• Only use an element if the
meaning of the data matches
according to the spec.
 Use an extension instead of
incorrectly using an existing
element.
Guidelines for Resource Mapping – Choose your profile
• Use existing profiles as much as
possible
• Standard (e.g. vital-signs)
• (Inter)national e.g.
https://simplifier.net/NictizSTU3-
Zib2017/ZIB-BloodPressure
• Define / extend profiles with peers
& partners when nothing suitable
exists; try to avoid app-specific
profiles
Using contained resources
• Only when the contained
resources have no life outside the
resource these are contained in
• Examples:
• DiagnosticReport with contained
Observations (matching HL7v2 ORU
etc.)
• …
Resource.meta, tags and security labels
• Does your application have a:
• Version
• Last modified timestamp
• Source
If so fill in Resource.meta
• Tags and Security Labels
• Adding and removing should not
affect the resource version
 so store separately.
Study the spec (1) - RESTful API – http.html
What interactions do you
need to support?
• delete – medical history
should remain with a status
e.g. “entered-in-error”
• history – who needs it?
• patch – too many options
• system-wide search – not
so hard, use _type
Study the spec (2) - search.html

• Filtering
• Choose standard parameters ()
• _id to search for specific Resource.id
• Incremental queries e.g.
?_lastUpdated=gt2019-11-01
• Choose resource-specific parameters
• ?identifier={system}|{identifier}
• ?patient={id} etc.
• Chaining examples:
• Observation?patient.name=Smith
• Observation?patient.general-practitioner.name=Jones
Our implementation loads target plugin for chained search
Paging – an undervalued part of the specification
• Paging is of critical importance for
building performant and scalable
solutions
• Choose a relatively low default
value for _count (our choice: 20)
• Repeat _count in the returned
paging links
• Returning OperationOutcome to
say “there are more results” is
lame.
Including resources is very powerful!
• Examples
• Observation?_include=Observation:patient
• Observation?_revinclude=Provenance:target
• Parameter values have three parts, separated by a : character:
• The name of the source resource from which the join comes
• The name of the search parameter which must be of type reference
(can be *)
• (Optional) A specific of type of target resource (for when the search
parameter refers to multiple possible target types)
• Use “_include:iterate” for deep inclusion (STU3 had “:recurse”)
Conditional create, update and delete
• External applications will not know
and use your Resource.id
• Avoid expensive tight coupling
(search/update etc.)
• Conditional create, update or
delete allow to use identifiers for
resource matching
 Use Conditional Create unless you
want to explicitly overwrite data in an
integration
Managing Resource Contention – see concurrency
• How to avoid changes made by one
client be overwritten by another?
• FHIR supports version-aware
updates
• Doesn’t work so good for batch
requests from a loosely coupled
system.
Implementing Referential Integrity
• Do you need to enforce it?
• Use logical references for loose coupling
<Observation>
<subject>
<identifier>
<system value="http://hl7.org/fhir/sid/us-ssn" />
<value value="000111111" />
</identifier>
</subject>

• Special type of logical reference:


<Observation>
<subject>
<reference value="Patient?identifier=12345"/>
</subject>

 Always use this type of reference?


Dealing with transactions and batches
• Consider early; use Bundle.request
to express all request
• Special ordering rules
• Extra logic needed for reference
resolution within the bundle
Setting up the CapabilityStatement
• It is your “business card”, make
sure it is there!
• GET /metadata is a great way of
testing connectivity (“ping”)
• Our server implementation uses it
locally to control what is exposed.
• Some clients may use it for
dynamic behavior
Error Handling is an absolute must!
• Return detailed
OperationOutcome resources that
include a clear code, message and
location.
• Do not abort at first error but
continue checking to return a
more comprehensive error report
• Batch/Transaction: Base location
must be passed in and extended.
FHIR Subscriptions & Notifications
• Great way for decoupling
applications
• Sending the payload has obvious
security implications
 Leave Subscription.channel.payload empty
• Lots of granular subscriptions can
lead to performance issues.
• Expect significant changes in R5
API Security and Authorization
• Make sure your data is sufficiently
protected
• Basic Auth
• OAuth2/OIDC
• Consider multiple factors
• Client-side certificate
• IP filter
• Leverage [3rd party] IAM or API
Gateway if possible
Implementation - tips
• Use an existing FHIR library
• FHIR.NET.API is very powerful
• Handles _summary; _format
• Use a FHIR server framework that
supports facades (e.g. Vonk)
• Robust coding is an absolute must
• Anything can be null
• Configuration is unavoidable
• System to be used for MRN
• Profiles (take from CapabilityStatement)
www.devdays.com

You might also like