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
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
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
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!
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!
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
Hinweis der Redaktion
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.
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.
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
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.
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
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
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?
Well, we create a new patient the same way we create any new instance of anything in Swift, we simply initialize it.
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.
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.
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.
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.
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.
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
In addition to filter we can also use sorted, which provides us a means of sorting the results when we start to use them.
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.
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.
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.
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.
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.
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?
It’s important because You Cannot Modify Managed Objects Outside of a Write Transaction. Try it and your app will crash into the mountain.
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.
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.
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
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
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.
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…
There’s one last way to edit a patient…
There’s one last way to edit a patient…
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.
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
Such as Swift 4’s JSONEncoder. We can use JSONEncoder() to serialize our patient object to JSON.
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.
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
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.
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.
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.
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
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.
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.
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?
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.
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
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.
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.
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
----- Meeting Notes (17-11-10 13:03) -----
- Show Patient structure
- Note that FireKit does _not_ manage its own Realm