Skip to content

Commit

Permalink
Feature/op 651 add ruby examples (#6)
Browse files Browse the repository at this point in the history
* OP-651 add get examples for ruby

* OP-651 add create and search examples for ruby

* OP-651 add decryption example of questionnaire response
 * Due to a bug in fhir_models (fhir-crucible/fhir_models#93) we need too use xml response, which apparently doesn't parse the encrypted message very well, so a hack is needed there as well
  • Loading branch information
esbakker authored Aug 9, 2021
1 parent 04a97bd commit c3f9129
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 0 deletions.
6 changes: 6 additions & 0 deletions ruby/GemFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ruby '>= 2.5'
source 'https://rubygems.org'

gem 'fhir_models'
gem 'fhir_client'
gem 'gpgme'
31 changes: 31 additions & 0 deletions ruby/src/appointment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require './fhir_client'

class AppointmentClient
def get_appointment(id)
FhirClient.new

FHIR::Appointment.read(id)
end

def create_appointment
FhirClient.new

appointment = FHIR::Appointment.new
appointment.status = 'booked'
appointment.priority = 5
appointment.start = Date.new(2021, 7, 9)
appointment.end = Date.new(2021, 7, 12)
appointment.comment = 'Further expand on the results of the MRI and determine the next actions that may be appropriate.'
appointment.description = 'Discussion on the results of your recent MRI'

appointment_type = FHIR::CodeableConcept.new
appointment_type_coding = FHIR::Coding.new
appointment_type_coding.system = 'http://terminology.hl7.org/CodeSystem/v2-0276'
appointment_type_coding.code = 'FOLLOWUP'
appointment_type_coding.id = 'A follow up visit from a previous appointment'
appointment_type.coding = appointment_type_coding
appointment.appointmentType = appointment_type

FHIR::Appointment.create(appointment)
end
end
11 changes: 11 additions & 0 deletions ruby/src/fhir_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'fhir_models'
require 'fhir_client'

class FhirClient
def initialize
client = FHIR::Client.new('https://api-sandbox-staging.openhealthhub.com/fhir')
FHIR::Model.client = client
# Workaround for https://github.com/fhir-crucible/fhir_models/issues/93
client.default_xml
end
end
33 changes: 33 additions & 0 deletions ruby/src/main.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require './appointment'
require './questionnaire'
require './questionnaire-response'
require './vitalsigns'
require './subscription'

client = AppointmentClient.new
response = client.get_appointment(4)
puts response.to_json

response = client.create_appointment
puts response.to_json

client = QuestionnaireClient.new
response = client.get_questionnaire(4)
puts response.to_json

client = QuestionnaireResponseClient.new
response = client.get_questionnaire_response(4)
puts response.to_json

response = client.search_questionnaire_response
puts response.to_json

client = VitalSignsClient.new
response = client.get_vitalsigns(4)
puts response.to_json
response = client.search_vitalsigns
puts response.to_json

client = SubscriptionClient.new
response = client.create_subscription
puts response.to_json
88 changes: 88 additions & 0 deletions ruby/src/questionnaire-response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
require './fhir_client'
require 'gpgme'

class QuestionnaireResponseClient

def initialize
load_key
end

def get_questionnaire_response(id)
FhirClient.new

response = FHIR::QuestionnaireResponse.read(id)

decrypt(response) if is_encrypted_response(response)

response
end

def search_questionnaire_response
FhirClient.new

params = {
'part-of': '97f680b9-e397-4298-8c53-de62a284c806',
'identifier': '6226217e-7ae9-4fa2-8fbe-e83a8f8540f9'
}
FHIR::QuestionnaireResponse.search(params)
end

private

def load_key
GPGME::Key.import(File.open('../../sandbox.key'))
end

def is_encrypted_response(response)
response.meta.profile.any? { |profile| profile == 'http://openhealthhub.com/StructureDefinition/EncryptedQuestionnaireResponse' }
end

def decrypt(response)
extensions = response.extension.select { |extension| extension.url == 'http://openhealthhub.com/StructureDefinition/encryptedAnswers' }
crypto = GPGME::Crypto.new
encrypted_answers = fix_encrypted_message_for_xml_response(extensions)
decrypted_string = crypto.decrypt(encrypted_answers, password: 'api-sandbox').to_s
decrypted_answers = JSON.parse(decrypted_string)
add_to_response(response, decrypted_answers)
end

# Encrypted message is not correctly parsed in XML mode
def fix_encrypted_message_for_xml_response(extensions)
new_line_fix = extensions.first.valueString.gsub(/.*\s{2}/, '').gsub(' -----END PGP MESSAGE-----', '').gsub(' ', "\n")
"-----BEGIN PGP MESSAGE-----\n\n" + new_line_fix + "\n-----END PGP MESSAGE-----"
end

def add_to_response(response, decrypted_answers)
response.item.each { |item| handle_item(item, response, decrypted_answers) }
end

def handle_item(item, response, decrypted_answers)
set_decrypted_answer(item.answer, decrypted_answers[item.linkId]) if decrypted_answers.keys.include?(item.linkId)

item.item.each { |nested_item| handle_item(nested_item, response, decrypted_answers) }
end

def set_decrypted_answer(answers, decrypted_value)
answers.each_with_index do |answer, i|
# Workaround for https://github.com/fhir-crucible/fhir_models/issues/93
is_encrypted_string = !answer.valueString.nil? && answer.valueString['extension']['url'] == 'http://openhealthhub.com/fhir/StructureDefinition/encrypted-stringType'
answer.valueString = decrypted_value[i] if is_encrypted_string

is_encrypted_coding = !answer.valueCoding.nil? && answer.valueCoding.extension[0].url == 'http://openhealthhub.com/fhir/StructureDefinition/encrypted-coding'
answer.valueCoding.code = decrypted_value[i] if is_encrypted_coding

# Workaround for https://github.com/fhir-crucible/fhir_models/issues/93
is_encrypted_decimal = !answer.valueDecimal.nil? && answer.valueDecimal['extension']['url'] == 'http://openhealthhub.com/fhir/StructureDefinition/encrypted-decimalType'
answer.valueDecimal = decrypted_value[i] if is_encrypted_decimal

is_encrypted_attachment = !answer.valueAttachment.nil? && answer.valueAttachment.extension[0].url == 'http://openhealthhub.com/fhir/StructureDefinition/encrypted-attachment'
answer.valueAttachment.data = decrypted_value[i] if is_encrypted_attachment

# Workaround for https://github.com/fhir-crucible/fhir_models/issues/93
is_encrypted_date = !answer.valueDate.nil? && answer.valueDate['extension']['url'] == 'http://openhealthhub.com/fhir/StructureDefinition/encrypted-dateType'
answer.valueDate = decrypted_value[i] if is_encrypted_date
end
end

end

9 changes: 9 additions & 0 deletions ruby/src/questionnaire.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require './fhir_client'

class QuestionnaireClient
def get_questionnaire(id)
FhirClient.new

FHIR::Questionnaire.read(id)
end
end
16 changes: 16 additions & 0 deletions ruby/src/subscription.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require './fhir_client'

class SubscriptionClient
def create_subscription
FhirClient.new

subscription = FHIR::Subscription.new

subscription.criteria = 'Appointment?name=test'
subscription.channel = FHIR::Subscription::Channel.new
subscription.channel.type = 'rest-hook'
subscription.channel.endpoint = 'https://your-webhook/endpoint'

FHIR::Subscription.create(subscription)
end
end
19 changes: 19 additions & 0 deletions ruby/src/vitalsigns.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require './fhir_client'

class VitalSignsClient
def get_vitalsigns(id)
FhirClient.new

FHIR::Observation.read(id)
end

def search_vitalsigns
FhirClient.new

params = {
'identifier': '1234',
'device-name': 'testDevice'
}
FHIR::Observation.search(params)
end
end

0 comments on commit c3f9129

Please sign in to comment.