# Swift-FHIR-Iris
Application iOS pour exporter les données HealthKit vers InterSystems IRIS for Health (ou n'importe quel référentiel FHIR)
![main](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/FHIR.png)
# Table des matières
* [Objectif de cette démo](#goal)
* [Comment lancer cette démo](#rundemo)
* [Préalables](#prerequisites)
* [Installation de Xcode](#installxcode)
* [Ouvrir le projet SwiftUi](#openswiftui)
* [Configuration du simulateur](#simulator)
* [Lancement du serveur FHIR d'InterSystems](#lunchfhir)
* [Jeu avec l'application iOS](#iosplay)
* [Comment ça marche](#howtos)
* [iOS](#howtosios)
* [Comment vérifier l'autorisation pour les travaux sur les données de santé](#authorisation)
* [Comment se connecter à un référentiel FHIR ?](#howtoFhir)
* [Comment enregistrer un patient dans le référentiel FHIR ?](#howtoPatientFhir)
* [Comment extraire les données de HealthKit ?](#queryHK)
* [Comment transformer les données de HealthKit en FHIR ?](#HKtoFHIR)
* [Logiciel de gestion (FHIR)](#backend)
* [Interface utilisateur](#frontend)
* [ToDos](#todo)
# Objectif de cette démo
L'objectif est de créer une démonstration de bout en bout du protocole FHIR.
Ce que j'entends par de bout en bout, à partir d'une source d'information telle qu'un iPhone.
Collectez vos données de santé au format Apple (HealthKit), transformez-les en FHIR, puis envoyez-les au référentiel IRIS for Health d'InterSystems.
Ces informations doivent être accessibles via une interface web.
**TL;DR**: iPhone -> InterSystems FHIR -> Page Web.
# Comment lancer cette démo
## Préalables
* Pour la partie client (iOS)
* Xcode 12
* Pour le serveur et l'application Web
* Docker
## Installation de Xcode
Pas grand chose à dire ici, ouvrez l'AppStore, cherchez Xcode, installez.
## Ouvrir le projet SwiftUi
Swift est la language de programmation d'Apple pour iOS, Mac, Apple TV et Apple Watch. Elle est le remplaçant d'objective-C.
Double-cliquez sur Swift-FHIR-Iris.xcodeproj.
Ouvrez le simulateur par un clic sur la flèche en haut à gauche.
![xcode](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/xcode_and_simulator.gif)
## Configuration du simulateur
Accéder à Santé
Cliquez sur Étapes
Ajouter des données
![simulateur](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/configuration_simulator.gif)
## Lancement du serveur FHIR d'InterSystems
Dans le dossier racine de ce git, exécutez la commande suivante :
```sh
docker-compose up -d
```
À la fin du processus de construction, vous serez en mesure de vous connecter au référentiel FHIR :
http://localhost:32783/fhir/portal/patientlist.html
![portail](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_default.png)
Ce portail a été réalisé par @diashenrique.
Avec quelques modifications pour gérer les pas d'activité d'Apple.
## Jeu avec l'application iOS
L'application vous demandera d'abord d'accepter de partager certaines informations.
Cliquez sur autoriser
![authoriser](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/ios_authorize.gif)
Vous pouvez ensuite tester le serveur FHIR en cliquant sur "Sauvegarder et tester le serveur".
Les paramètres par défaut pointent vers la configuration docker.
En cas de succès, vous pouvez entrer les informations de votre patient.
Prénom, Nom de famille, Date de naissance, Genre.
Enregistrez le patient dans Fhir. Une fenêtre pop-up vous montrera votre ID Fhir unique.
![savepatient](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/save_patient.gif)
Consultez ce patient sur le portail :
Accédez à: http://localhost:32783/fhir/portal/patientlist.html
Nous pouvons voir ici, qu'il y a un nouveau patient "toto" avec 0 activités.
![patient portal](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/patient_toto.png)
Envoyez ses activités :
Retournez dans l'application iOS et cliquez sur Compteur de pas.
Ce panneau résume le nombre de pas de la semaine. Dans notre cas, il s'agit de 2 entrées.
Maintenant vous pouvez les envoyer à InterSystems IRIS FHIR par un clic sur envoi.
![envoie ios](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/ios_send.gif)
Consultez les nouvelles activités sur le portail :
Nous pouvons voir maintenant que Toto a deux nouvelles observations et activités.
![portail d'activités](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_activities.gif)
Vous pouvez éventuellement cliquer sur le bouton de graphique pour l'afficher comme un graphique.
![graphiques de portail](https://raw.githubusercontent.com/grongierisc/Swift-FHIR-Iris/main/img/gif/portal_chart.gif)
# Comment ça marche
## iOS
La plupart de cette démo est construite sur SwiftUI.
https://developer.apple.com/xcode/swiftui/
Qui est le dernier framework pour iOS et co.
### Comment vérifier l'autorisation pour les travaux sur les données de santé
Il se trouve dans la classe SwiftFhirIrisManager.
Cette classe est un élément singleton et elle sera transportée tout autour de l'application avec l'annotation @EnvironmentObject.
Plus d'informations ici : https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views
La méthode requestAuthorization :
```swift
// Demander l'autorisation pour accéder à HealthKit.
func requestAuthorization() {
// Demande d'accès.
/// - Tag: RequestAuthorization
let writeDataTypes: Set = dataTypesToWrite()
let readDataTypes: Set = dataTypesToRead()
// demande d'accès
healthStore.requestAuthorization(toShare: writeDataTypes, read: readDataTypes) { (succès, erreur) dans
if !success {
// Traitez l'erreur ici.
} else {
DispatchQueue.main.async {
self.authorizedHK = true
}
}
}
}
```
Où healthStore est l'objet de HKHealthStore().
Le HKHealthStore est comme la base de données de santé dans iOS.
dataTypesToWrite et dataTypesToRead sont les objets que nous souhaitons interroger dans la base de données.
L'autorisation doit avoir un but et cela est fait dans le fichier xml Info.plist en ajoutant :
```xml
NSHealthClinicalHealthRecordsShareUsageDescription
Lisez les données pour IrisExporter
NSHealthShareUsageDescription
Envoyez les données à IRIS
NSHealthUpdateUsageDescription
Date d'inscription pour IrisExporter
```
### Comment se connecter à un référentiel FHIR ?
Pour cette partie, j'ai utilisé le paquet FHIR de Smart-On-FHIR : https://github.com/smart-on-fhir/Swift-FHIR.
La classe utilisée est le FHIROpenServer.
```swift
private func test() {
progress = true
let url = URL(string: self.url)
swiftIrisManager.fhirServer = FHIROpenServer(baseURL : url! , auth: nil)
swiftIrisManager.fhirServer.getCapabilityStatement() { FHIRError in
progress = false
showingPopup = true
if FHIRError == nil {
showingSuccess = true
textSuccess = "Connecté au référentiel fhir"
} else {
textError = FHIRError?.description ?? "Erreur inconnue"
showingSuccess = false
}
return
}
}
```
Cela permet de créer un nouvel objet fhirServer dans le singleton swiftIrisManager.
Ensuite, nous utilisons la fonction getCapabilityStatement().
Si nous pouvons récupérer le capabilityStatement du serveur FHIR, cela signifie que nous nous sommes connectés avec succès au référentiel FHIR.
Ce référentiel n'est pas en HTTPS, par défaut apple interdit ce type de communication.
Pour permettre le support HTTP, le fichier xml Info.plist est édité comme suit :
```xml
NSAppTransportSecurity
NSExceptionDomains
localhost
NSIncludesSubdomains
NSExceptionAllowsInsecureHTTPLoads
```
### Comment enregistrer un patient dans le référentiel FHIR ?
Opération de base en vérifiant d'abord si le patient existe déjà dans le référentiel.
```swift
Patient.search(["family": "\(self.lastName)"]).perform(fhirServer)
```
Cela permet de rechercher les patients ayant le même nom de famille.
Ici, nous pouvons imaginer d'autres scénarios comme avec Oauth2 et un jeton JWT pour joindre le patient et son jeton. Mais pour cette démo, nous gardons les choses simples.
Ensuite, si le patient existe, nous le récupérons, sinon nous le créons :
```swift
func createPatient(callback: @escaping (Patient?, Error?) -> Void) {
// Créer une nouvelle ressource pour le patient
let patient = Patient.createPatient(prénom: firstName, nom: lastName, date de naissance: birthDay, sex: gender)
patient?.create(fhirServer, callback: { (erreur) dans
callback(patient, erreur)
})
}
```
### Comment extraire les données de HealthKit ?
Cela se fait en interrogeant le magasin Healthkit (HKHealthStore()).
Ici, nous faisons une requête pour les pas.
Préparez la requête avec le prédicat.
```swift
//La semaine dernière
let startDate = swiftFhirIrisManager.startDate
//Now
let endDate = swiftFhirIrisManager.endDate
print("Collecte des séances d'entraînement entre \(startDate) et \(endDate)")
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)
```
Puis la requête elle-même avec son type de données (HKQuantityType.quantityType(forIdentifier : .stepCount)) et le prédicat.
```swift
func queryStepCount(){
//La semaine dernière
let startDate = swiftFhirIrisManager.startDate
//Maintenant
let endDate = swiftFhirIrisManager.endDate
print("Collecte des séances d'entraînement entre \(startDate) et \(endDate)")
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)
let query = HKSampleQuery(sampleType: HKQuantityType.quantityType(forIdentifier: .stepCount)!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (requête, résultats, erreur) dans
guard let results = results as? [HKQuantitySample] else {
return
}
process(results, type: .stepCount)
}
healthStore.execute(query)
}
```
### Comment transformer les données de HealthKit en FHIR ?
Pour cette partie, nous utilisons le paquet Microsoft HealthKitToFHIR
https://github.com/microsoft/healthkit-to-fhir
Il s'agit d'un paquet utile qui offre des facteurs pour transformer HKQuantitySample en FHIR Observation
```swift
let observation = try! ObservationFactory().observation(from: item)
let patientReference = try! Reference(json: ["référence" : "Patient/\(patientId)"])
observation.category = try! [CodeableConcept(json: [
"coding": [
[
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "activité",
"display": "Activité"
]
]
])]
observation.subject = patientReference
observation.status = .final
print(observation)
observation.create(self.fhirServer,callback: { (erreur) dans
if error != nil {
completion(error)
}
})
```
Où élément est un HKQuantitySample, dans notre cas un type stepCount.
Le facteur fait le gros du travail en convertissant 'élément' et 'type' en FHIR codeableConcept et 'valeur' en FHIR valueQuantity.
La référence au patientId est faite manuellement en intégrant une référence json fhir.
```swift
let patientReference = try! Reference(json: ["référence" : "Patient/\(patientId)"])
```
On fait de même pour la catégorie :
```swift
observation.category = try! [CodeableConcept(json: [
"codage": [
[
"systèmem": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "activité",
"affichage": "Activité"
]
]
])]
```
Enfin, l'observation est créée dans le référentiel fhir :
```swift
observation.create(self.fhirServer,callback: { (erreur) in
if error != nil {
completion(error)
}
})
```
## Logiciel de gestion (FHIR)
Pas grand chose à dire, il est basé sur le modèle fhir de la communauté InterSystems :
https://openexchange.intersystems.com/package/iris-fhir-template
## Interface utilisateur
Il est basé sur les travaux de Henrique et est un joli interface utilisateur pour les dépôts FHIR fait en jquery.
https://openexchange.intersystems.com/package/iris-fhir-portal