Artículo
Ricardo Paiva · Mar 24, 2021 Lectura de 9 min

InterSystems IRIS for Health, iOS y FHIR

SWIFT-FHIR-IRIS es una aplicación de iOS para exportar datos de HealthKit a InterSystems IRIS for Health (o a cualquier repositorio FHIR)

Swift-FHIR-Iris

Índice

Objetivo de esta demostración

El objetivo es crear una demostración de extremo a extremo del protocolo FHIR.

Lo que quiero decir con extremo a extremo, es desde una fuente de información como un iPhone. Recoge tus datos médicos en formato Apple (HealthKit), transfórmalos en FHIR y envíalos al repositorio de InterSystems IRIS for Health.

Esta información debe ser accesible a través de una interfaz web.

TL;DR: iPhone -> InterSystems FHIR -> Página web.

 

Cómo ejecutar esta demostración

 

Requisitos previos

  • Por la parte del cliente (iOS)
    • Xcode 12
  • Para el servidor y la aplicación web
    • Docker

 

Instalar Xcode

No hay mucho que decir aquí, abre la AppStore, busca Xcode e instálalo.

 

Abrir el proyecto SwiftUi

Swift es el lenguaje de programación de Apple para iOS, Mac, Apple TV y Apple Watch. Es el sustituto de objective-C.

Haz doble clic en Swift-FHIR-Iris.xcodeproj

Abre el simulador haciendo clic en la flecha superior izquierda.

xcode

 

Configurar el simulador

Ve a Health

Haz clic en Steps

Añade los datos

simulador

 

Lanzar InterSystems FHIR Server

En la carpeta raíz de este git, ejecuta el siguiente comando:

docker-compose up -d

Al finalizar el proceso de desarrollo, podrás conectarte al repositorio FHIR:

http://localhost:32783/fhir/portal/patientlist.html

portal

Este portal fue realizado por @diashenrique.

Con algunas modificaciones para manejar los pasos de Apple.

 

Jugar con la app de iOS

Primero, la aplicación te pedirá que aceptes compartir cierta información.

Haga clic en Authorize

autorizar

A continuación, puedes probar el servidor FHIR haciendo clic en "Save and test server".

La configuración predeterminada señala la configuración de Docker.

Si todo va bien, puedes introducir la información de tu paciente.

Nombre, apellido, cumpleaños, género.

El paciente se guarda en Fhir. Una ventana emergente te mostrará su ID de Fhir único.

savepatient

Puedes consultar este paciente en el portal:

Ve a: http://localhost:32783/fhir/portal/patientlist.html

Aquí podemos ver que hay un nuevo paciente "Toto" con 0 actividades.

portal de pacientes

Envía sus actividades:

Vuelve a la aplicación iOS y haz clic en Step count

Este panel resume el conteo de pasos de la semana. En nuestro caso hay 2 registros.

Ahora puedes enviarlos a InterSystems IRIS FHIR haciendo clic en Send.

enviar ios

Consulta las nuevas actividades en el portal:

Ahora podemos ver que Toto tiene dos nuevas observaciones y actividades.

portal de actividades

Puedes hacer clic en el botón de Gráfico para mostrar la información gráficamente.

portal de gráficas

 

Cómo funciona

 

iOS

La mayor parte de esta demostración está creada en SwiftUI.

https://developer.apple.com/xcode/swiftui/

Que es la framework más reciente para iOS.

 

Cómo verificar la autorización de los datos médicos

Está en la clase SwiftFhirIrisManager.

Esta clase es una instancia única o singleton y llevará todo lo que está alrededor de la aplicación con la anotación @EnvironmentObject.

Más información en: https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environm...

El método requestAuthorization:

    // Request authorization to access HealthKit.
    func requestAuthorization() {
        // Requesting authorization.
        /// - Tag: RequestAuthorization

        let writeDataTypes: Set<HKSampleType> = dataTypesToWrite()
        let readDataTypes: Set<HKObjectType> = dataTypesToRead()

        // requset authorization
        healthStore.requestAuthorization(toShare: writeDataTypes, read: readDataTypes) { (success, error) in
            if !success {
                // Handle the error here.
            } else {

                DispatchQueue.main.async {
                    self.authorizedHK = true
                }

            }
        }
    }

Donde healthStore es el objeto de HKHealthStore().

La HKHealthStore actua como la base de datos de healthdata en iOS.

dataTypesToWrite y dataTypesToRead son los objetos que nos gustaría consultar en la base de datos.

La autorización necesita un propósito y esto se hace en el archivo Info.plist xml al añadir:

    <key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
    <string>Read data for IrisExporter</string>
    <key>NSHealthShareUsageDescription</key>
    <string>Send data to IRIS</string>
    <key>NSHealthUpdateUsageDescription</key>
    <string>Write date for IrisExporter</string>

 

Cómo conectarse al repositorio de FHIR

Para esta parte utilicé el paquete FHIR de Smart-On-FHIR: https://github.com/smart-on-fhir/Swift-FHIR

Utilicé la clase FHIROpenServer.

    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 = "Connected to the fhir repository"
            } else {
                textError = FHIRError?.description ?? "Unknow error"
                showingSuccess = false
            }

            return
        }

    }

Esto crea un nuevo objeto fhirServer en la instancia única swiftIrisManager.

A continuación utilizamos la función getCapabilityStatement()

Si podemos recuperar la capabilityStatement del servidor FHIR, significará que nos conectamos correctamente al repositorio FHIR.

Este repositorio no está en HTTPS, de forma predeterminada apple bloquea este tipo de comunicación.

Para permitir el soporte HTTP, el archivo Info.plist xml se edita de la siguiente forma:

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>localhost</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>

 

Cómo guardar un paciente en el Repositorio de FHIR

La operación básica es verificar primero si el paciente ya existe en el repositorio

Patient.search(["family": "\(self.lastName)"]).perform(fhirServer)

Esto realiza una búsqueda de pacientes con el mismo apellido.

Aquí podemos imaginar otros escenarios como con Oauth2 y JWT token para unir al patientid con su token. Pero para esta demo, mantenemos las cosas sencillas.

A continuación, si el paciente existe, lo recuperamos; de lo contrario creamos el paciente:

    func createPatient(callback: @escaping (Patient?, Error?) -> Void) {
        // Create the new patient resource
        let patient = Patient.createPatient(given: firstName, family: lastName, dateOfBirth: birthDay, gender: gender)

        patient?.create(fhirServer, callback: { (error) in
            callback(patient, error)
        })
    }

 

Cómo extraer datos del HealthKit

Se realiza consultando el Healthkit Store (HKHealthStore())

Aquí consultamos los pasos.

Prepare la consulta con el predicado.

        //Last week
        let startDate = swiftFhirIrisManager.startDate
        //Now
        let endDate = swiftFhirIrisManager.endDate

        print("Collecting workouts between \(startDate) and \(endDate)")

        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)

A continuación, la misma consulta con su tipo de datos (HKQuantityType.quantityType(forIdentifier: .stepCount)) y el predicado.

func queryStepCount(){

        //Last week
        let startDate = swiftFhirIrisManager.startDate
        //Now
        let endDate = swiftFhirIrisManager.endDate

        print("Collecting workouts between \(startDate) and \(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) { (query, results, error) in

            guard let results = results as? [HKQuantitySample] else {
                   return
            }

            process(results, type: .stepCount)

        }

        healthStore.execute(query)

    }

 

Cómo convertir los datos de HealthKit a FHIR

En esta parte, utilizamos el paquete HealthKitToFHIR de Microsoft

https://github.com/microsoft/healthkit-to-fhir

Es un paquete útil que ofrece factories para convertir HKQuantitySample a FHIR Observation

     let observation = try! ObservationFactory().observation(from: item)
      let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"])
      observation.category = try! [CodeableConcept(json: [
          "coding": [
            [
              "system": "http://terminology.hl7.org/CodeSystem/observation-category",
              "code": "activity",
              "display": "Activity"
            ]
          ]
      ])]
      observation.subject = patientReference
      observation.status = .final
      print(observation)
      observation.create(self.fhirServer,callback: { (error) in
          if error != nil {
              completion(error)
          }
      })

Donde el elemento es un HKQuantitySample; en nuestro caso es un tipo stepCount.

El factory hace la mayor parte del trabajo de convertir 'unit' y 'type' a FHIR codeableConcept y 'value' a FHIR valueQuantity.

La referencia al patientId se realiza manualmente al emitir una referencia json fhir.

let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"])

Lo mismo se hace para la categoría :

      observation.category = try! [CodeableConcept(json: [
          "coding": [
            [
              "system": "http://terminology.hl7.org/CodeSystem/observation-category",
              "code": "activity",
              "display": "Activity"
            ]
          ]
      ])]

Al final, se crea la observación en el repositorio fhir:

      observation.create(self.fhirServer,callback: { (error) in
          if error != nil {
              completion(error)
          }
      })

 

Backend (FHIR)

No hay mucho que decir, se basa en la plantilla fhir de la Comunidad de InterSystems :

https://openexchange.intersystems.com/package/iris-fhir-template

 

Frontend

Se basa en los trabajos de Henrique, que es un buen front-end para los repositorios FHIR hechos en jquery.

https://openexchange.intersystems.com/package/iris-fhir-portal

 

 
00
2 0 1 19
Log in or sign up to continue

Respuestas

Este artículo está etiquetado como "Mejores prácticas" ("Best practices") yes

(Los artículos con la etiqueta "Mejores prácticas" incluyen recomendaciones sobre cómo desarrollar, probar, implementar y administrar mejor las soluciones de InterSystems).