SlideShare a Scribd company logo
FHIR® is the registered trademark of HL7 and is used with the permission of HL7. The Flame Design mark is the registered trademark of HL7 and is used with the permission of HL7.
Amsterdam, 15-17 November | @fhir_furore | #fhirdevdays17 | www.fhirdevdays.com
Easy FHIR Persistence with FireKit for iOS
Ryan Baldwin, eHealth Innovation @ University Health Network
About Me
• Name: Ryan Baldwin
• Background
• Software Developer of 16 years
• Accidentally created
• FireKit
• Restivus
• Author
• Clojure Web Development Essentials
• Hates Shaving
Quick Assessment
• Who here knows FHIR?
• Who here knows Realm?
• Good news!
• Familiarity is beneficial, but not required
• However, you should be familiar with
• Swift
Agenda
• Origin Story
• What FireKit can do
• What FireKit cannot do
• How to Persist Your FHIR Data
• Serializing Your FHIR Data
• Working with a FHIR Server
Origin Story
Or How I Accidentally Find Myself in Amsterdam
What Is FireKit?
• A FHIR DSTU2 implementation in
Swift
• Full CRUD support with Realm
• Full Serialization to/from JSON
• Swift 4 Codable compliant
• NSCopying compliant
• Realm CRUD helper functions
• Distributed under Apache 2 license
FireKit Limitations
• No API client… yet
• BYOC: Bring Your Own Client
• More on this later
• Beholden to Realm’s “Rules of Engagement”
• No implicit sharing of FHIR resources across thread
boundaries
• Writes must occur in a transaction
• No List of primitives
Creating a FHIR Resource
• Import FireKit; Import RealmSwift
• FireKit contains the FHIR DSTU2
schema
• RealmSwift is the Realm Swift API
Creating a FHIR Resource
• Import FireKit; Import RealmSwift
• FireKit contains the FHIR DSTU2
schema
• RealmSwift is the Realm Swift API
• Create a new Patient
Creating a FHIR Resource
• Import FireKit; Import RealmSwift
• FireKit contains the FHIR DSTU2
schema
• RealmSwift is the Realm Swift API
• Create a new Patient
• Give that Patient a name!
Creating a FHIR Resource
• Import FireKit; Import RealmSwift
• FireKit contains the FHIR DSTU2
schema
• RealmSwift is the Realm Swift API
• Create a new Patient
• Give that Patient a name!
• Finally, save that patient
• FireKit provides the primary key
• String property called pk
Retrieving Realm Objects
• Realm provides query mechanics
• objects<T>(_: T.Type) -> Results<T>
• filter
• Sorted
• object<T>(_: T.Type, forPrimaryKey) -> T?
• FireKit provides 2 extensions:
• resources<T>(_: T.Type, withIds: [String]) -> Results<T>
• resource<T>(_: T.Type, withId: String) -> T?
Retrieving All Objects for a Type
• Use objects(_:) to retrieve a
Results list of those objects
Retrieving All Objects for a Type
• Use objects(_:) to retrieve a
Results list of those objects
Filter Results
• Use objects(_:) to retrieve a
Results list of those objects
• Use filter(_:) to filter the results.
Sort Results
• Use objects(_:) to retrieve a
Results list of those objects
• Use filter(_:) to filter the results.
• Use sorted(_:) to sort the results
by field
See more filter options at
https://academy.realm.io/posts/nspredicate-
cheatsheet/
Get an Object by Primary Key
• object(ofType:, forPrimaryKey)
• Returns the object, or nil
• Remember: Every FireKit object has
a primary key
FireKit Extension: Getting Resources
• Query for type where id is in list
• This is a convenience function
• Wraps around realm.objects and
filter
FireKit Extension: Getting Resources
• Query for type where id is in list
• This is a convenience function
• Wraps around realm.objects and
filter
• Can also apply filter and sorted
FireKit Extension: Get Single Resource by id
• Get a single resource of a given
type by it’s resource id
Managed vs. Unmanaged Realm Objects
• Unmanaged Objects are not in a
Realm
• New, unsaved objects
Managed vs. Unmanaged Realm Objects
• An object becomes managed
when it’s persisted to a realm
Managed vs. Unmanaged Realm Objects
• An object becomes managed
when it’s persisted to a realm
• Once managed, the object cannot
be modified outside a write
transaction.
Managed vs. Unmanaged Realm Objects
• An object becomes managed
when it’s persisted to a realm
• Once managed, the object cannot
be modified outside a write
transaction.
• Wrap the edit in a write block
• Alternatively, use beginWrite() and
commitWrite()
Editing a Resource
• 4 ways to edit a FHIR Resource
• Edit individual properties
• upsert a property
• Use copy/populate technique
• Bonus Jonus! realm.upsert<T>(:)
• All must be performed inside a write transaction
Editing a Resource – Individual Properties
• We’ve already seen this
• Update individual properties in write
transaction
Editing a Resource – Individual Properties
• We’ve already seen this
• Update individual properties in write
transaction
Editing a Resource – Upserting a property
• upsert(:)
• To update or insert
• Create a template of what you
want
• Blindly assign template property
• Spouses will not share status
Editing a Resource – Copy/Populate
• copy()
• provides unmanaged copy of the
source
• Does not duplicate primary keys
• populate(from:)
• migrates values from source to
target
• Complete replacement;
• does not perform intelligent merge
Editing a Resource – Bonus Jonus!
• What to do with downloaded
Resources?
• Update? Create a new one?
• Neither! You upsert it!
• Logic based on the Resource’s id
• Will insert or update appropriately
Editing a Resource – Bonus Jonus!
• What to do with remote
Resources?
• Update? Create a new one?
• Neither! You upsert it!
• Logic based on the Resource’s id
• Will insert or update appropriately
• Also handles arrays of Resources
Deleting a Resource
• Don’t use Realm’s realm.delete(:)
on Resources or Elements
• Does not cascade
• Risks orphans
• Use FireKit’s cascadeDelete()
• Properly deletes
Resources/Elements
• No more orphans
JSON Serialization
• All FireKit classes conform to Swift
4’s Codable protocol
JSON Serialization
• All FireKit classes conform to Swift
4’s Codable protocol
• Serialize using Swift 4’s JSONEncoder
JSON Serialization
• All FireKit classes conform to Swift
4’s Codable protocol
• Serialize using Swift 4’s JSONEncoder
• Deserialize using Swift 4’s
JSONDecoder
Integrating with a FHIR Server
• No API client in FireKit
• Yet?
• Use Restivus as a simple
alternative
https://ryanbaldwin.github.io/Restivus
• Protocol-oriented
• Works around Swift 4’s Encodable
and Decodable protocols
• Focus on structure, not on
infrastructure
An Example Restivus Request
• Get the contents of the Google
Home Page
• Model the request
An Example Restivus Request
• Get the contents of the Google
Home Page
• Model the request
• Conform it to the proper Protocol
• Gettable
• Postable
• Puttable
• Patchable
• Deletable
An Example Restivus Request
• Get the contents of the Google
Home Page
• Model the request
• Conform it to the proper Protocol
• Gettable
• Postable
• Puttable
• Patchable
• Deletable
• What are we expecting back? Where
are we fetching from?
An Example Restivus Request
• Get the contents of the Google
Home Page
• Model the request
• Conform it to the proper Protocol
• Gettable
• Postable
• Puttable
• Patchable
• Deletable
• What are we expecting back? Where
are we fetching from?
• Submit it!
Another Example – Download a Patient
• Create the request
Another Example – Download a Patient
• Create the request
• Conform the request to Gettable
• We are expecting a Patient
• Use String interpolation to construct
the path dynamically
Another Example – Download a Patient
• Create the request
• Conform the request to Gettable
• We are expecting a Patient
• Use String interpolation to construct
the path dynamically
• Submit it!
Last Example – Post a Patient
• Create the request
Last Example – Post a Patient
• Create the request
• Conform to Postable
• Expect an OperationOutcome
Last Example – Post a Patient
• Create the request
• Conform to Postable
• Expect an OperationOutcome
• Conform to Encodable
• Populates the request body with
JSON
• Single Value Container for just the
Patient JSON
Last Example – Post a Patient
• Create the request
• Conform to Postable
• Expect an OperationOutcome
• Conform to Encodable
• Populates the request body with
JSON
• Single Value Container for just the
Patient JSON
• Submit it!
FireKit + Restivus = Easy Basic Client
• FireKit Codables
• Much more to Restivus than presented
• Should be enough to get you started
Summary
• FireKit
• Provides a Realm-ready FHIR DSTU2 spec
• Easily update and delete complex FHIR models in Realm
• Codable Conformant – Easily Serialize/Deserialze your data
• NSCopying Conformant – Easily copy your data
• Restivus
• Easily create and submit Requests to a Server
• Automatically inflates ready-to-use responses from JSON
• Stays out of your way
That’s all she wrote!
FireKit:
https://github.com/ryanbaldwin/FireKit
Restivus:
https://ryanbaldwin.github.io/Restivus
Codable:
http://apple.co/2AqcloL
http://bit.ly/2znNuSn
http://bit.ly/2yes7kU

More Related Content

PPTX
Profiling with clin fhir
PPTX
Furore devdays 2017- rdf1(solbrig)
PPTX
Transforming other content (grahame)
PPTX
Furore devdays 2017- profiling academy - profiling guidelines v1
PPTX
Furore devdays 2017 - implementation guides (lloyd)
PPTX
Fhir dev days_basic_fhir_terminology_services
PPTX
Furore devdays2017 tdd-2-advanced
PPTX
fhir-documents
Profiling with clin fhir
Furore devdays 2017- rdf1(solbrig)
Transforming other content (grahame)
Furore devdays 2017- profiling academy - profiling guidelines v1
Furore devdays 2017 - implementation guides (lloyd)
Fhir dev days_basic_fhir_terminology_services
Furore devdays2017 tdd-2-advanced
fhir-documents

What's hot (20)

PPTX
Mohannad hussain dicom and imaging tools
PPTX
Fhir dev days_advanced_fhir_terminology_services
PPTX
FHIR Server internals - sqlonfhir
PDF
Searching SNOMED CT
PDF
Ephedra: efficiently combining RDF data and services using SPARQL federation
ODP
Search Solutions 2015: Towards a new model of search relevance testing
PPT
Introduction to CrossRef Text and Data Mining Webinar
PDF
PharoDAYS 2015: Pharo Status - by Markus Denker
PDF
JSON-LD and SHACL for Knowledge Graphs
PPTX
Semantically-Enabled Digital Investigations
PDF
Elasticsearch
PPTX
Data FAIRport Prototype & Demo - Presentation to Elsevier, Jul 10, 2015
PPTX
Hybrid Enterprise Knowledge Graphs
PDF
Approaching Join Index: Presented by Mikhail Khludnev, Grid Dynamics
PDF
Grails And The Semantic Web
PPTX
Text and Data Mining
PDF
Intro to Elasticsearch
PDF
USUGM 2014 - Kevin Clark (Genentech): Searching Project Team Documents with D...
PDF
ICIC 2014 Chemical Patent Curation and Management – New Tools and Capabilities
Mohannad hussain dicom and imaging tools
Fhir dev days_advanced_fhir_terminology_services
FHIR Server internals - sqlonfhir
Searching SNOMED CT
Ephedra: efficiently combining RDF data and services using SPARQL federation
Search Solutions 2015: Towards a new model of search relevance testing
Introduction to CrossRef Text and Data Mining Webinar
PharoDAYS 2015: Pharo Status - by Markus Denker
JSON-LD and SHACL for Knowledge Graphs
Semantically-Enabled Digital Investigations
Elasticsearch
Data FAIRport Prototype & Demo - Presentation to Elsevier, Jul 10, 2015
Hybrid Enterprise Knowledge Graphs
Approaching Join Index: Presented by Mikhail Khludnev, Grid Dynamics
Grails And The Semantic Web
Text and Data Mining
Intro to Elasticsearch
USUGM 2014 - Kevin Clark (Genentech): Searching Project Team Documents with D...
ICIC 2014 Chemical Patent Curation and Management – New Tools and Capabilities
Ad

Similar to Fire kit ios (r-baldwin) (20)

PDF
Building APIs in an easy way using API Platform
PDF
Integrating the Solr search engine
PPTX
Build your datatypes
PDF
Fedora4
PPTX
PHP Starter Application
PPTX
Why do they call it Linked Data when they want to say...?
PDF
Api FUNdamentals #MHA2017
KEY
Scotch On The Rocks 2011
KEY
drupal 7 amfserver presentation: integrating flash and drupal
PDF
Workshop "Building Modern Web Applications with Firebase (and Angular)", Arm...
PDF
"Easy and scalable serverless backend for your next mobile or web app", Arman...
PDF
Planidoo & Zotonic
PDF
Api fundamentals
PDF
Ferret A Ruby Search Engine
PPTX
Docs as Part of the Product - Open Source Summit North America 2018
PPTX
Introduction to FIWARE IoT
KEY
SOTR 2012
PPTX
Vonk fhir facade (christiaan)
PDF
Stop coding start testing
PPTX
Xplore Group - Flashtalk (Fabric8, Neo4j, GraphQL, OpenID Connect)
Building APIs in an easy way using API Platform
Integrating the Solr search engine
Build your datatypes
Fedora4
PHP Starter Application
Why do they call it Linked Data when they want to say...?
Api FUNdamentals #MHA2017
Scotch On The Rocks 2011
drupal 7 amfserver presentation: integrating flash and drupal
Workshop "Building Modern Web Applications with Firebase (and Angular)", Arm...
"Easy and scalable serverless backend for your next mobile or web app", Arman...
Planidoo & Zotonic
Api fundamentals
Ferret A Ruby Search Engine
Docs as Part of the Product - Open Source Summit North America 2018
Introduction to FIWARE IoT
SOTR 2012
Vonk fhir facade (christiaan)
Stop coding start testing
Xplore Group - Flashtalk (Fabric8, Neo4j, GraphQL, OpenID Connect)
Ad

More from DevDays (20)

PPTX
Consent dev days
PDF
Integrating with the epic platform fhir dev days 17
PPTX
Mohannad hussain community track - siim dataset & dico mweb proxy
PPTX
Fhir dev days 2017 fhir profiling - overview and introduction v07
PPTX
final Keynote (grahame)
PPTX
Validation in net and java (ewout james)
PPTX
Structure definition 101 (ewout)
PPTX
Quality improvement dev days-2017
PPTX
Furore devdays 2017-sdc (lloyd)
PPTX
Furore devdays 2017- rdf2(solbrig)
PPTX
Furore devdays 2017- oai
PPTX
Dev days 2017 questionnaires (brian postlethwaite)
PPTX
Devdays 2017 implementation guide authoring - ardon toonstra
PPTX
Dev days 2017 advanced directories (brian postlethwaite)
PPTX
Connectathon opening 2017
PPTX
Building bridges devdays 2017- powerpoint template
PPTX
20171127 rene spronk_messaging_the_unloved_paradigm
PPTX
Security overview (grahame)
PPTX
Opening student track
PPTX
Furore devdays 2017- continua implementing fhir
Consent dev days
Integrating with the epic platform fhir dev days 17
Mohannad hussain community track - siim dataset & dico mweb proxy
Fhir dev days 2017 fhir profiling - overview and introduction v07
final Keynote (grahame)
Validation in net and java (ewout james)
Structure definition 101 (ewout)
Quality improvement dev days-2017
Furore devdays 2017-sdc (lloyd)
Furore devdays 2017- rdf2(solbrig)
Furore devdays 2017- oai
Dev days 2017 questionnaires (brian postlethwaite)
Devdays 2017 implementation guide authoring - ardon toonstra
Dev days 2017 advanced directories (brian postlethwaite)
Connectathon opening 2017
Building bridges devdays 2017- powerpoint template
20171127 rene spronk_messaging_the_unloved_paradigm
Security overview (grahame)
Opening student track
Furore devdays 2017- continua implementing fhir

Recently uploaded (20)

PPTX
Microbial diseases, their pathogenesis and prophylaxis
PPTX
202450812 BayCHI UCSC-SV 20250812 v17.pptx
DOC
Soft-furnishing-By-Architect-A.F.M.Mohiuddin-Akhand.doc
PDF
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
PDF
Weekly quiz Compilation Jan -July 25.pdf
PPTX
Introduction-to-Literarature-and-Literary-Studies-week-Prelim-coverage.pptx
PPTX
Tissue processing ( HISTOPATHOLOGICAL TECHNIQUE
PDF
2.FourierTransform-ShortQuestionswithAnswers.pdf
PDF
FourierSeries-QuestionsWithAnswers(Part-A).pdf
PPTX
Cell Types and Its function , kingdom of life
PPTX
master seminar digital applications in india
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PDF
A systematic review of self-coping strategies used by university students to ...
PDF
Chinmaya Tiranga quiz Grand Finale.pdf
PDF
A GUIDE TO GENETICS FOR UNDERGRADUATE MEDICAL STUDENTS
PPTX
Cell Structure & Organelles in detailed.
PDF
Yogi Goddess Pres Conference Studio Updates
PDF
RTP_AR_KS1_Tutor's Guide_English [FOR REPRODUCTION].pdf
PDF
Abdominal Access Techniques with Prof. Dr. R K Mishra
PPTX
Pharmacology of Heart Failure /Pharmacotherapy of CHF
Microbial diseases, their pathogenesis and prophylaxis
202450812 BayCHI UCSC-SV 20250812 v17.pptx
Soft-furnishing-By-Architect-A.F.M.Mohiuddin-Akhand.doc
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
Weekly quiz Compilation Jan -July 25.pdf
Introduction-to-Literarature-and-Literary-Studies-week-Prelim-coverage.pptx
Tissue processing ( HISTOPATHOLOGICAL TECHNIQUE
2.FourierTransform-ShortQuestionswithAnswers.pdf
FourierSeries-QuestionsWithAnswers(Part-A).pdf
Cell Types and Its function , kingdom of life
master seminar digital applications in india
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
A systematic review of self-coping strategies used by university students to ...
Chinmaya Tiranga quiz Grand Finale.pdf
A GUIDE TO GENETICS FOR UNDERGRADUATE MEDICAL STUDENTS
Cell Structure & Organelles in detailed.
Yogi Goddess Pres Conference Studio Updates
RTP_AR_KS1_Tutor's Guide_English [FOR REPRODUCTION].pdf
Abdominal Access Techniques with Prof. Dr. R K Mishra
Pharmacology of Heart Failure /Pharmacotherapy of CHF

Fire kit ios (r-baldwin)

  • 1. FHIR® is the registered trademark of HL7 and is used with the permission of HL7. The Flame Design mark is the registered trademark of HL7 and is used with the permission of HL7. Amsterdam, 15-17 November | @fhir_furore | #fhirdevdays17 | www.fhirdevdays.com Easy FHIR Persistence with FireKit for iOS Ryan Baldwin, eHealth Innovation @ University Health Network
  • 2. About Me • Name: Ryan Baldwin • Background • Software Developer of 16 years • Accidentally created • FireKit • Restivus • Author • Clojure Web Development Essentials • Hates Shaving
  • 3. Quick Assessment • Who here knows FHIR? • Who here knows Realm? • Good news! • Familiarity is beneficial, but not required • However, you should be familiar with • Swift
  • 4. Agenda • Origin Story • What FireKit can do • What FireKit cannot do • How to Persist Your FHIR Data • Serializing Your FHIR Data • Working with a FHIR Server
  • 5. Origin Story Or How I Accidentally Find Myself in Amsterdam
  • 6. What Is FireKit? • A FHIR DSTU2 implementation in Swift • Full CRUD support with Realm • Full Serialization to/from JSON • Swift 4 Codable compliant • NSCopying compliant • Realm CRUD helper functions • Distributed under Apache 2 license
  • 7. FireKit Limitations • No API client… yet • BYOC: Bring Your Own Client • More on this later • Beholden to Realm’s “Rules of Engagement” • No implicit sharing of FHIR resources across thread boundaries • Writes must occur in a transaction • No List of primitives
  • 8. Creating a FHIR Resource • Import FireKit; Import RealmSwift • FireKit contains the FHIR DSTU2 schema • RealmSwift is the Realm Swift API
  • 9. Creating a FHIR Resource • Import FireKit; Import RealmSwift • FireKit contains the FHIR DSTU2 schema • RealmSwift is the Realm Swift API • Create a new Patient
  • 10. Creating a FHIR Resource • Import FireKit; Import RealmSwift • FireKit contains the FHIR DSTU2 schema • RealmSwift is the Realm Swift API • Create a new Patient • Give that Patient a name!
  • 11. Creating a FHIR Resource • Import FireKit; Import RealmSwift • FireKit contains the FHIR DSTU2 schema • RealmSwift is the Realm Swift API • Create a new Patient • Give that Patient a name! • Finally, save that patient • FireKit provides the primary key • String property called pk
  • 12. Retrieving Realm Objects • Realm provides query mechanics • objects<T>(_: T.Type) -> Results<T> • filter • Sorted • object<T>(_: T.Type, forPrimaryKey) -> T? • FireKit provides 2 extensions: • resources<T>(_: T.Type, withIds: [String]) -> Results<T> • resource<T>(_: T.Type, withId: String) -> T?
  • 13. Retrieving All Objects for a Type • Use objects(_:) to retrieve a Results list of those objects
  • 14. Retrieving All Objects for a Type • Use objects(_:) to retrieve a Results list of those objects
  • 15. Filter Results • Use objects(_:) to retrieve a Results list of those objects • Use filter(_:) to filter the results.
  • 16. Sort Results • Use objects(_:) to retrieve a Results list of those objects • Use filter(_:) to filter the results. • Use sorted(_:) to sort the results by field See more filter options at https://academy.realm.io/posts/nspredicate- cheatsheet/
  • 17. Get an Object by Primary Key • object(ofType:, forPrimaryKey) • Returns the object, or nil • Remember: Every FireKit object has a primary key
  • 18. FireKit Extension: Getting Resources • Query for type where id is in list • This is a convenience function • Wraps around realm.objects and filter
  • 19. FireKit Extension: Getting Resources • Query for type where id is in list • This is a convenience function • Wraps around realm.objects and filter • Can also apply filter and sorted
  • 20. FireKit Extension: Get Single Resource by id • Get a single resource of a given type by it’s resource id
  • 21. Managed vs. Unmanaged Realm Objects • Unmanaged Objects are not in a Realm • New, unsaved objects
  • 22. Managed vs. Unmanaged Realm Objects • An object becomes managed when it’s persisted to a realm
  • 23. Managed vs. Unmanaged Realm Objects • An object becomes managed when it’s persisted to a realm • Once managed, the object cannot be modified outside a write transaction.
  • 24. Managed vs. Unmanaged Realm Objects • An object becomes managed when it’s persisted to a realm • Once managed, the object cannot be modified outside a write transaction. • Wrap the edit in a write block • Alternatively, use beginWrite() and commitWrite()
  • 25. Editing a Resource • 4 ways to edit a FHIR Resource • Edit individual properties • upsert a property • Use copy/populate technique • Bonus Jonus! realm.upsert<T>(:) • All must be performed inside a write transaction
  • 26. Editing a Resource – Individual Properties • We’ve already seen this • Update individual properties in write transaction
  • 27. Editing a Resource – Individual Properties • We’ve already seen this • Update individual properties in write transaction
  • 28. Editing a Resource – Upserting a property • upsert(:) • To update or insert • Create a template of what you want • Blindly assign template property • Spouses will not share status
  • 29. Editing a Resource – Copy/Populate • copy() • provides unmanaged copy of the source • Does not duplicate primary keys • populate(from:) • migrates values from source to target • Complete replacement; • does not perform intelligent merge
  • 30. Editing a Resource – Bonus Jonus! • What to do with downloaded Resources? • Update? Create a new one? • Neither! You upsert it! • Logic based on the Resource’s id • Will insert or update appropriately
  • 31. Editing a Resource – Bonus Jonus! • What to do with remote Resources? • Update? Create a new one? • Neither! You upsert it! • Logic based on the Resource’s id • Will insert or update appropriately • Also handles arrays of Resources
  • 32. Deleting a Resource • Don’t use Realm’s realm.delete(:) on Resources or Elements • Does not cascade • Risks orphans • Use FireKit’s cascadeDelete() • Properly deletes Resources/Elements • No more orphans
  • 33. JSON Serialization • All FireKit classes conform to Swift 4’s Codable protocol
  • 34. JSON Serialization • All FireKit classes conform to Swift 4’s Codable protocol • Serialize using Swift 4’s JSONEncoder
  • 35. JSON Serialization • All FireKit classes conform to Swift 4’s Codable protocol • Serialize using Swift 4’s JSONEncoder • Deserialize using Swift 4’s JSONDecoder
  • 36. Integrating with a FHIR Server • No API client in FireKit • Yet? • Use Restivus as a simple alternative https://ryanbaldwin.github.io/Restivus • Protocol-oriented • Works around Swift 4’s Encodable and Decodable protocols • Focus on structure, not on infrastructure
  • 37. An Example Restivus Request • Get the contents of the Google Home Page • Model the request
  • 38. An Example Restivus Request • Get the contents of the Google Home Page • Model the request • Conform it to the proper Protocol • Gettable • Postable • Puttable • Patchable • Deletable
  • 39. An Example Restivus Request • Get the contents of the Google Home Page • Model the request • Conform it to the proper Protocol • Gettable • Postable • Puttable • Patchable • Deletable • What are we expecting back? Where are we fetching from?
  • 40. An Example Restivus Request • Get the contents of the Google Home Page • Model the request • Conform it to the proper Protocol • Gettable • Postable • Puttable • Patchable • Deletable • What are we expecting back? Where are we fetching from? • Submit it!
  • 41. Another Example – Download a Patient • Create the request
  • 42. Another Example – Download a Patient • Create the request • Conform the request to Gettable • We are expecting a Patient • Use String interpolation to construct the path dynamically
  • 43. Another Example – Download a Patient • Create the request • Conform the request to Gettable • We are expecting a Patient • Use String interpolation to construct the path dynamically • Submit it!
  • 44. Last Example – Post a Patient • Create the request
  • 45. Last Example – Post a Patient • Create the request • Conform to Postable • Expect an OperationOutcome
  • 46. Last Example – Post a Patient • Create the request • Conform to Postable • Expect an OperationOutcome • Conform to Encodable • Populates the request body with JSON • Single Value Container for just the Patient JSON
  • 47. Last Example – Post a Patient • Create the request • Conform to Postable • Expect an OperationOutcome • Conform to Encodable • Populates the request body with JSON • Single Value Container for just the Patient JSON • Submit it!
  • 48. FireKit + Restivus = Easy Basic Client • FireKit Codables • Much more to Restivus than presented • Should be enough to get you started
  • 49. Summary • FireKit • Provides a Realm-ready FHIR DSTU2 spec • Easily update and delete complex FHIR models in Realm • Codable Conformant – Easily Serialize/Deserialze your data • NSCopying Conformant – Easily copy your data • Restivus • Easily create and submit Requests to a Server • Automatically inflates ready-to-use responses from JSON • Stays out of your way
  • 50. That’s all she wrote! FireKit: https://github.com/ryanbaldwin/FireKit Restivus: https://ryanbaldwin.github.io/Restivus Codable: http://apple.co/2AqcloL http://bit.ly/2znNuSn http://bit.ly/2yes7kU

Editor's Notes

  • #3: Good day! So lets get started. My name is Ryan Baldwin, and I’m a software developer with eHealth Innovation at the University Health Network in Toronto Canada. I’ve been developing software for about 16 years now, about 1/3 of which is in healthcare, but only recently have I started working with FHIR. I’m also the accidental creator of FireKit and Restivus, both of which are things we’ll cover today. I authored a book called Clojure Web Development Essentials, which, if you’re so inclined, you can purchase from Amazon and join the literal dozens of people to have read it.
  • #4: Anyways – enough about me. What about you? Who here knows FHIR? Beginner? Expert? And what about Realm? Anybody here know about or has worked with Realm? For those unfamiliar, Realm is an open source, cross-platform mobile database. In iOS it’s an alternative to CoreData. The good news is you don’t need to be an expert about either of these technologies to get something out of this talk. I’m actually new to both these technologies within the past year, but have done some interesting work with them. That being said you should be familiar with Swift.
  • #5: So I’m going to talk today about how FireKit became a thing, what it can do and what it can’t do. I’ll then spend more time in how we use FireKit to persist FHIR data, serialize and deserialize that data, and how we can work with a FHIR Server. ----- Meeting Notes (17-11-09 09:40) ----- order of bullet points
  • #6: So, how the heck did I get here? About a year ago we at eHealth Innovation started working on a new iOS app which made heavy use of Questionnaire, QuestionnaireResponse, Medication, and MedicationOrder resources. So I started handrolling the Questionnaire and QuestionnaireResponse classes and supporting datatypes. Then the JSON serialization, and the glue code for converting those classes into CoreData models, and I started to lose my marbles. I thought THERE MUST BE A BETTER WAY. I looked around online and found Pascal Pfiffner’s Swift-FHIR, which looked promissing, but it didn’t help with persistence. I discovered, however, that Pascal has an on open source python parser used to parse FHIR JSON definitions and generate Swift classes. So I forked that and over the course of a weekend I’d written a language pack which generated Realm-Ready Swift classes. I offered it as a pull request to Pascal but we decided it’d be better suited to just host it as my own thing. And thus, FireKit was born. So why Fire with f-i-r-e instead of FHIRKit, with capital FHIR? Mostly because I hate having a stream of capital letters in classes and module names.
  • #7: So what exactly is FireKit and what does it do? FireKit is a Realm-ready FHIR DSTU2 implementation in Swift. In 3 lines of code you can create a new Patient and persist it to the iOS device. All FireKit objects are fully serializable and deserializable to JSON. In fact, Every class in FireKit conforms to Swift 4’s Codable protocol, so you can, in theory, serialize using any Encoder or Decoder. So if you want to represent everything as a PropertyList that should be doable. Why you would do that… I do not know, but hey, it’s there for ya. Almost all of the classes in FireKit conform to NSCopyable, so you can quickly duplicate instances if need be. And finally FireKit comes with some Realm helper functions to help with some CRUD operations
  • #8: It comes with limitations, however. Unlike HAPI FHIR there is no API client in FireKit…. Yet. You currently must provide your own integration with a FHIR server. However this is where Restivus can help, which is another library I’ve developed and which we’ll talk about later. Also – because everything in FireKit is, ultimately, a Realm Object, you are beholden to Realm’s rules (which, frankly, are quite reasonable) - No implicit sharing of a Realm Object, say, a Patient, across thread boundaries - Anytime you modify an object you’ll need to do so in a write transaction - List of primitives, such as Strings, Ints, etc. were not supported in Realm until just recently in Realm 3. Instead FireKit provides simple wrappers, such as RealmString. ----- Meeting Notes (17-11-09 09:40) ----- no API FHIR client
  • #9: So what does this look like? I think the easiest way is to just jump right in by creating our first resource. There are typically 2 imports you need to make, depending on what you’re doing. FireKit is where the FHIR DSTU2 schema and helper functions are kept. We can create in-memory Resources, serialize them, etc. using FireKit RealmSwift with the official Swift API for Realm. We use RealmSwift to either directly or indirectly perform the create, retrieve, update and deleting of FireKit data. So lets say we want to make a patient, give that patient a name, and then persist that patient to realm. How would we do that?
  • #10: Well, we create a new patient the same way we create any new instance of anything in Swift, we simply initialize it.
  • #11: We can then initialize the HumanName and provide it a value for the family and given names. Patient, HumanName, and RealmString all come from FireKit Why RealmString and not just String? Remember that Realm 2.x does not support lists of primitives, and instead we need to wrap them.
  • #12: Finally, we use the RealmSwift API to actually persist the Patient and its name. On line 11 Create an instance of our Realm with all default values (including the file on disk) We use the Realm api to start a transaction and add the patient to realm, Everything in the realm.write block is in a transaction, in which we add the actual patient Add several patients inside the write block, if any fail, they all fail If we wanted we could create several patients and perform a realm.add for each one. The transaction is a real transaction, so if any of those realm.adds should fail, nothing would be committed to disk, as you would expect. That is literally all there is to getting your data into realm. There are more advanced techniques that are available from Realm, I won’t be covering those as they’re not specific to FireKit and, frankly, I rarely – if ever – use them.
  • #13: There are a few ways we can get data out of Realm. We can use Realm’s objects and object queries which, depending on what you’re doing, might be sufficient. - Objects returns a lazy Results list that can be filtered and sorted - Object returns a single object or nil Or, if you know the id of the resource you want to fetch, you can use FireKit’s resources or resource functions.
  • #14: I don’t want to spend too much time on Realm’s object or objects queries. I’ll cover the basics of them because what I say here will apply to FireKit’s resource and resources functions. We can use objects to get a Results list of all Patients. Results in Realm are lazy, and are only loaded from disk when we access a result’s property. They are just in time. So while we have the patients results on line 6, we haven’t actually fetched anything from disk yet.
  • #15: However, if we wanted to, we could iterate over every single one of those patients and print the name. Each iteration from lines 7 through 11 will load the next patient from disk. That being said we typically don’t want to load every single patient from disk. More likely we want to filter on those patients.
  • #16: The Results returned by the objects method provides a function, filter, which allows us to add a filter. Again, no patients have been loaded from disk yet. At this point we are basically still constructing our query. The filter syntax is the same as that of NSPredicate. In fact, you can actually pass an NSPredicate. The filter function returns a Results list as well. If we want we can chain multiple filters together, narrowing our results list even further
  • #17: In addition to filter we can also use sorted, which provides us a means of sorting the results when we start to use them.
  • #18: In addition to queries we can also use Realm’s object forPriamryKey function I’ve mentioned it a few times in passing, but I’ll talk a bit more about it here. Every FireKit object has a primary key property, called pk. By default it’s value is a UUID string, but you’re free to set it to whatever you wan if you’re feeling adventeroust when you create the new instance. It’s not something I often think about, but it’s there if we need it.
  • #19: What’s more common in the experience that I’ve had lately is using the resource’s id as that’s the common key between the client and the server. As such I created 2 functions that are similar to Realm’s objects and object functions, called resources and resource. The resources function is similar to objects in that it accepts a Type, but it also accepts a list of ids. This is basically a convenience function that wraps an objects/filter query.
  • #20: Resources, same as objects, returns a Results list, so we’re able to build further refine our results using filter chains and sorted, should we so please.
  • #21: Similar to object(forPrimaryKey) there’s a resource(withId). This behaves exactly like Realm’s object(forPrimaryKey) except, well, it uses the resource id instead of the primary key. It will return the inflated type, if it was found, otherwise it’ll return nil.
  • #22: So far we’ve covered Creating and Retrieving FHIR objects from Realm. Before we continue I want to get a bit of terminology out of the way, as you’ll find it in Realm’s documentation as well as FireKit’s, and that’s the notion of Managed vs. Unmanaged. Unmanaged Objects are basically those which have not yet been persisted. They’ve been created and might live in memory, but they do not live on disk. Going back to our first examples, when we were creating our first Patient, the patient was considered unmanaged onlines 5 through 9.
  • #23: An unmanaged object becomes managed only after it’s been successfuilly persisted to Realm. Such was the case in our first example when we performed the realm.add in the write transaction. It was at that point when our patient transitioned from the Unmanaged world into the Managed world. So why is this important?
  • #24: It’s important because You Cannot Modify Managed Objects Outside of a Write Transaction. Try it and your app will crash into the mountain.
  • #25: Any and all writes on a managed object _must_ be performed within a write transaction. You can define a write transaction using a block, or alternatively by calling beginWrite and commitWrite, and put your modifications in between.
  • #26: So with the above in mind, what are the different ways we can edit a resource? We can Edit individual properties We’ve already seen how this is done as we’ve been doing it the whole time, and is the native Realm way of doing things For some properties of FireKit objects, we can use it’s associated upsert function Alternatively, we can use a combination of FireKit Object’s copy and populate functions Finally, FireKit provides a realm extension for upserting an entire resource We will talk about all three, but no matter what, anything we do against a managed object must be performed inside a write transaction.
  • #27: So we’ve already seen plethora of individual property writes. We can grab an object back from Realm and modify it inside a write transaction and commit it
  • #28: Or we can get a list of objects back from the server and iterate through them, and, for whatever reason, make everybody’s birthday the same day. Remember that we can do this because the results we get from realm are not copies, but are the actual objects themselves. This works, but FHIR is not a simple data model. FHIR Resources are complex statues made of smaller element blocks. As such, when we are editing a Resource it can be tedius to check what exists and what doesn’t exist, having to create new instances when appropriate, etc. FireKit provides some help with this with several upsert instance functions
  • #29: Upsert An intelligent “update or insert”. FireKit will check if the item exists and, if not, will create it. Otherwise it will update the existing target Allows us to simply assign an instance to a complex property It essentially treats the input – whatever we pass to it – as a template Ensures compartmentalization – meaning it ensures the element is NOT referenced by multiple Resources. So in our example we can create a CodeableConcept for a patient’s MarriedStatus, and then blindly upsert the martialStatus on each Patient without having to worry about whether or not a status already exists, if we need to create one, etc. Nor do we have to create a CodeableConcept for each patient. We can create one that’s desired, and upsert multiple times.
  • #30: There are times, of course, when we want to have the ability to make changes and only commit them all at once if the user says. Think of it as a “Done/Cancel” scenario on a modal view, if we were editing the patient details or something. If our view is writing directly back to the original model on each mutation of, say, a patient’s name, that will update the persisted Patient in real time, which is difficult to rollback from. In these scenarios, however, we can perform a Copy/Populate. Copy: creates an in-memory, unmanaged copy of the source Does not duplicate the primary keys. If you wanted you could copy a resource and write it directly to realm Because the copy is unmanaged, we can edit it as much as we want outside a write transaction When we are done with the edits and want to save, we can then call Populate(from) on the original resource populate(from:) will update the target such that it reflects whatever we pass in (MINUS primary keys). It’s very similar to the upsert(maritalStatus) from the previous example In fact, the upsert(maritalStatus) function is using the copy/populate combo under the hood. Note that it will completely replace the values of the target. There is zero intelligent merging here. It if there are collections that are affected, for example HumanName in Patient, then that collection will be updated, appended to, and deleted from appropriately. Speaking of Deleting…
  • #31: There’s one last way to edit a patient…
  • #32: There’s one last way to edit a patient…
  • #33: How do we appropriately delete a FireKit object from Realm? The natural thing to do would be to use Realm’s baked in realm.delete(:). Don’t. Do not use that. Why, you ask? Because realm.delete() doesn’t actually cascade to relationships. As a result you’ll risk orphaning a whole lot of objects. For example, if you have a Patient with a HumanName, and you use realm’s API to delete the Patient, the HumanName will not be deleted. This would be fine in other domains, possibly, but in FHIR the element is confined to the boundaries of the Resource, meaning that HumanName should not be with any other Patient. Solution? Use FireKit’s cascadeDelete() This will delete everything that’s a member of the container. So if we called cascadeDelete on a Patient, everything directly tied to that Patient resource will be deleted (HumanName, extensions, etc). It will _NOT_, however, delete anything that has a FHIR Reference for that Patient. This affects the physical structure of the data only. Honestly, that’s all there is to say about Delete. It deletes your data. Data bye bye.
  • #34: So lets shift gears and get away from CRUD and start to focus a bit on integration. Serialization is a big thing here. Thankfully, serializing and deserializing FireKit objects is simple. That’s because all FireKit classes conform to Swift 4’s Codable protocol. This means you can pass FireKit objects to anything expecting a Swift 4 Encodable or Decodable
  • #35: Such as Swift 4’s JSONEncoder. We can use JSONEncoder() to serialize our patient object to JSON.
  • #36: Deserializing from JSON back into an inflated object is also straight forward, and only 1 line. Using Swift 4 Codables is important because it allows us to have a common ground for cross-framework integration. Since FireKit doesn’t actually provide its own FHRI Client out of the box, we have been using Restivus for all our relatively basic REST needs.
  • #37: What is Restivus? A swift 4, protocol-oriented library for creating and using rest requests It uses Swift 4’sCodables for serializing requests and, more importantly deserializing the responses This allows us to use FireKit classes to define responses from a server Restivus takes care of most of the plumbing, so you can focus on the structure of your requests and responses
  • #38: So lets start with a really simple example. A general one, where we can just fetch the contents of the google homepage. The first thing we do is we model the request. Because we’re just grabbing the google homepage there’s no parameters we need for a struct. Our struct, at this point, is basically a dumb container that we’ll bolt functionality on via Restivus protocols.
  • #39: There are 5 protocols that Restivus has, the name of each should give you an idea of the type of request it’ll produce: Gettable for GET requests Postable for POST requests And so on and so forth Restivus currently only supports 5 of the methods, as they’re the low hanging fruit. You conform the request to the appropriate protocol. In our case we’ll use Gettable, as we’re getting the google homepage. All Restivus protocols have sensible defaults, but we still need to do at least 1 thing, and that’s define the ResponseType of the response. In our case, we’re going to get whatever google gives us – we don’t really care what it is for the purpose of this example – so we’ll just use Restivus’s Raw type, which is just an alias to Swift’s Data type We also state the resultFormat will be raw, as opposed to its default of .json And finally we give it the URL we’re going to request again. And that’s it. Our request is done.
  • #40: There are 5 protocols that Restivus has, the name of each should give you an idea of the type of request it’ll produce: Gettable for GET requests Postable for POST requests And so on and so forth Restivus currently only supports 5 of the methods, as they’re the low hanging fruit. You conform the request to the appropriate protocol. In our case we’ll use Gettable, as we’re getting the google homepage. All Restivus protocols have sensible defaults, but we still need to do at least 1 thing, and that’s define the ResponseType of the response. In our case, we’re going to get whatever google gives us – we don’t really care what it is for the purpose of this example – so we’ll just use Restivus’s Raw type, which is just an alias to Swift’s Data type We also state the resultFormat will be raw, as opposed to its default of .json And finally we give it the URL we’re going to request again. And that’s it. Our request is done.
  • #41: One of the default implementations of Gettable is a submit function, which returns a URLSessionDataTask, and at a minimum accepts an optional completion block. The completion block passes in a Response enum of either success or failure. If successful, the enum value will contain an inflated instance of the data returned, in accordance to the ResponseType that we defined. The failure value will contain a Restivus.HTTPError. So, if that’s a little bit unclear, lets do another example that involves FHIR
  • #42: We’ll create a GetPatientRequest. If we want to get a specific patient from the server then we need to provide a PatientID, so our request only need model that one param.
  • #43: Next, because we want to get the patient, we’ll conform to the Gettable protocol. We are expecting a Patient, so our ResponseType will be Patient, instead of Raw Alternatively to the URL property (which defaults to nil), we can use a combination of baseURL and path, which will be munged together at runtime when we submit our request.
  • #44: Again, Restivus provides a sensible default implementation of submit. This time, the result passed into the completion block, if successful, will contain the fully inflated FireKit Patient object, ready to use, and not the raw data. The failure, again, will contain a Restivus.HTTPError. It’s honestly that easy. So what if we want to POST a patient to the server?
  • #45: Well, like all things, we start with a new request. This time we’ll call it AddPatientRequest, and it will take the patient we want to POST to the server.
  • #46: Since we want to POST the patient to the server, our request will conform to the Restivus.Postable protocol. Again, we are expecting something back from the server. In this case we’re expecting an OperationOutcome And again, we define the URL this request should submit to
  • #47: Finally, because we want to post a serialized Patient to the server, we simply have to conform our request to Encodable. Restivus will then automatically serialize our request object and submit it as the HTTP body of the HTTPURLRequest, but there’s a single gotcha: By default, our AddPatientRequest will encode a key/value pair, with the key “patient” and the value of our serialized patient. We don’t want this – we want to only submit the serialized patient. As such we have to implement Encodable’s encode function, which will encode only the Patient JSON. This is easily done by creating a single value container from the JSONEncoder() and using that to encode our patient.
  • #48: Again, to use it we simply create a new instance of the request, passing the patient we want to upload, and submitting it. If successful, our Result enum will contain the deserialized OperationOutcome ready for us to use; otherwise, as always, it’ll return an error.
  • #49: As we can see, FireKit Codables play nicely with Restivus, and as such we can quickly develop requests for fetching and submitting FHIR data to a FHIR server. There’s a lot more goodies in Restivus that I didn’t cover here in the interest of time, but I strongly suggest that if you’re interested, or as part of the exercise if you so choose to do that this afternoon, that you take a look at the documentation. Using restivus should be enough to get you started with communicating with a FHIR server It might also be good enough to
  • #51: ----- Meeting Notes (17-11-10 13:03) ----- - Show Patient structure - Note that FireKit does _not_ manage its own Realm