Module: DaVinciCRDTestKit::MockEHR::FHIRRequestHandler

Included in:
FHIRCreateEndpoint, FHIRDeleteEndpoint, FHIRReadEndpoint, FHIRSearchEndpoint, FHIRUpdateEndpoint
Defined in:
lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.session_id_to_token(session_id, exp_min = 5) ⇒ Object



20
21
22
23
24
25
26
27
28
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 20

def self.session_id_to_token(session_id, exp_min = 5)
  token_structure = {
    session_id:,
    expiration: exp_min.minutes.from_now.to_i,
    nonce: SecureRandom.hex(8)
  }.to_json

  Base64.urlsafe_encode64(token_structure, padding: false)
end

Instance Method Details

#add_provided_resource_to_mock_ehr_bundleObject



185
186
187
188
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 185

def add_provided_resource_to_mock_ehr_bundle
  mock_ehr_bundle.entry << FHIR::Bundle::Entry.new({ resource: provided_resource })
  save_mock_ehr_bundle_to_input
end

#assign_id_to_provided_resource(target_id: SecureRandom.uuid) ⇒ Object


Create, Update




181
182
183
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 181

def assign_id_to_provided_resource(target_id: SecureRandom.uuid)
  provided_resource.id = target_id
end

#error_body(severity, code, text) ⇒ Object



39
40
41
42
43
44
45
46
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 39

def error_body(severity, code, text)
  FHIR::OperationOutcome.new(
    issue: FHIR::OperationOutcome::Issue.new(severity:, code:,
                                             details: FHIR::CodeableConcept.new(
                                               text:
                                             ))
  ).to_json
end

#interaction_typeObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 54

def interaction_type
  case request.env['REQUEST_METHOD']
  when 'GET'
    if resource_id.present?
      'Read'
    else
      'Search'
    end
  when 'POST'
    if request.env['PATH_INFO'].ends_with?('_search')
      'Search'
    else
      'Create'
    end
  when 'PUT'
    'Update'
  when 'DELETE'
    'Delete'
  end
end

#mock_ehr_bundleObject


Mock Bundle Management




216
217
218
219
220
221
222
223
224
225
226
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 216

def mock_ehr_bundle
  @mock_ehr_bundle ||= begin
    bundle_json = Inferno::Repositories::SessionData.new.load(
      test_session_id: test_run.test_session_id,
      name: mock_ehr_bundle_input_name
    )
    FHIR.from_contents(bundle_json)
  rescue StandardError
    nil
  end
end

#mock_ehr_bundle_input_nameObject



228
229
230
231
232
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 228

def mock_ehr_bundle_input_name
  return 'mock_ehr_bundle' unless test.config.options[:mock_ehr_bundle_input_name].present?

  test.config.options[:mock_ehr_bundle_input_name].to_s
end

#mock_ehr_bundle_present?Boolean

Returns:

  • (Boolean)


234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 234

def mock_ehr_bundle_present?
  if mock_ehr_bundle.blank?
    response.status = 400
    response.body = error_body('warning', 'required', "No Bundle provided in input #{mock_ehr_bundle_input_name}")
    return false
  end

  unless mock_ehr_bundle.is_a?(FHIR::Bundle)
    response.status = 400
    response.body = error_body('warning', 'required',
                               "Input #{mock_ehr_bundle_input_name} does not contain a FHIR Bundle.")
    return false
  end

  true
end

#prepare_responseObject


Response Generation




34
35
36
37
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 34

def prepare_response
  response.format = 'application/fhir+json'
  response.headers['Access-Control-Allow-Origin'] = '*'
end

#provided_resourceObject


Request Provided Resource (body)




111
112
113
114
115
116
117
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 111

def provided_resource
  @provided_resource ||= begin
    FHIR.from_contents(request.body.read)
  rescue StandardError
    nil
  end
end

#provided_resource_valid?Boolean

Returns:

  • (Boolean)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 119

def provided_resource_valid?
  if provided_resource.blank?
    response.status = 400
    response.body = error_body('error', 'structure', 'Invalid resource')
    return false
  end
  if provided_resource.resourceType != resource_type
    response.status = 400
    response.body =
      error_body('error', 'structure',
                 "Incorrect resource type: url indicates `#{resource_type}`, " \
                 "body contains `#{provided_resource.resourceType}`")
    return false
  end

  true
end

#remove_target_resource_from_bundleObject


Delete




205
206
207
208
209
210
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 205

def remove_target_resource_from_bundle
  return if target_resource_entry_index.nil?

  mock_ehr_bundle.entry.delete_at(target_resource_entry_index)
  save_mock_ehr_bundle_to_input
end

#resource_idObject


Request Resource Id




95
96
97
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 95

def resource_id
  request.params[:resource_id]
end

#resource_id_present?Boolean

Returns:

  • (Boolean)


99
100
101
102
103
104
105
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 99

def resource_id_present?
  return true if resource_id.present?

  response.status = 400
  response.body = error_body('error', 'required', 'No recognized resource id in URL')
  false
end

#resource_typeObject


Request Resource Type




79
80
81
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 79

def resource_type
  request.params[:resource_type]
end

#resource_type_present?Boolean

Returns:

  • (Boolean)


83
84
85
86
87
88
89
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 83

def resource_type_present?
  return true if resource_type.present?

  response.status = 400
  response.body = error_body('error', 'required', 'No recognized resource type in URL')
  false
end

#return_provided_resource(status: 201) ⇒ Object



137
138
139
140
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 137

def return_provided_resource(status: 201)
  response.status = status if status.present?
  response.body = provided_resource.to_json
end

#return_target_resource(status: 200) ⇒ Object



172
173
174
175
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 172

def return_target_resource(status: 200)
  response.status = status if status.present?
  response.body = target_resource.to_json
end

#return_unhandled_error(error) ⇒ Object



48
49
50
51
52
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 48

def return_unhandled_error(error)
  logger.error("FHIR #{interaction_type} error: #{error.full_message}")
  response.status = 500
  response.body = error_body('error', 'processing', error.message)
end

#save_mock_ehr_bundle_to_inputObject



251
252
253
254
255
256
257
258
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 251

def save_mock_ehr_bundle_to_input
  Inferno::Repositories::SessionData.new.save(
    test_session_id: test_run.test_session_id,
    name: mock_ehr_bundle_input_name,
    value: mock_ehr_bundle.to_json,
    type: test.available_inputs[mock_ehr_bundle_input_name.to_sym]&.type
  )
end

#target_resourceObject



157
158
159
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 157

def target_resource
  @target_resource ||= target_resource_entry&.resource
end

#target_resource_entryObject



152
153
154
155
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 152

def target_resource_entry
  @target_resource_entry ||=
    target_resource_entry_index.present? ? mock_ehr_bundle.entry[target_resource_entry_index] : nil
end

#target_resource_entry_indexObject


Reading




146
147
148
149
150
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 146

def target_resource_entry_index
  @target_resource_entry_index ||= mock_ehr_bundle.entry.find_index do |entry|
    entry.resource&.resourceType == resource_type && entry.resource&.id == resource_id
  end
end

#target_resource_present?Boolean

Returns:

  • (Boolean)


161
162
163
164
165
166
167
168
169
170
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 161

def target_resource_present?
  if target_resource.blank?
    response.status = 404
    response.body = error_body('error', 'not-found',
                               "No resource found with id #{resource_type}/#{resource_id}")
    return false
  end

  true
end

#test_run_identifierObject


Session Matching




10
11
12
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 10

def test_run_identifier
  token_to_session_id(request.headers['authorization']&.delete_prefix('Bearer '))
end

#token_to_session_id(token_to_decode) ⇒ Object



14
15
16
17
18
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 14

def token_to_session_id(token_to_decode)
  JSON.parse(Base64.urlsafe_decode64(token_to_decode))&.dig('session_id')
rescue JSON::ParserError, ArgumentError
  nil
end

#update_target_resource_in_mock_ehr_bundleObject



190
191
192
193
194
195
196
197
198
199
# File 'lib/davinci_crd_test_kit/server/endpoints/mock_ehr/fhir_request_handler.rb', line 190

def update_target_resource_in_mock_ehr_bundle
  if target_resource_entry.present?
    target_resource_entry.resource = provided_resource
    save_mock_ehr_bundle_to_input
    response.status = 200
  else
    add_provided_resource_to_mock_ehr_bundle
    response.status = 201
  end
end