Module: Inferno::DSL::FHIRClient
- Includes:
- Messages
- Defined in:
- lib/inferno/dsl/fhir_client.rb
Overview
This module contains the FHIR DSL available to test writers.
Defined Under Namespace
Modules: ClassMethods
Class Method Summary collapse
Instance Method Summary collapse
-
#body_to_path(body) ⇒ Object
Converts a list of FHIR Parameters into a query string for GET requests.
-
#fetch_all_bundled_resources(resource_type:, bundle: resource, reply_handler: nil, client: :default, max_pages: 20, additional_resource_types: [], tags: []) ⇒ Array<FHIR::Resource>
Fetch all resources from a paginated FHIR bundle.
- #fetch_next_bundle(bundle, client, tags) ⇒ Object
- #fhir_class_from_resource_type(resource_type) ⇒ Object
-
#fhir_client(client = :default) ⇒ FHIR::Client
Return a previously defined FHIR client.
- #fhir_clients ⇒ Object
-
#fhir_create(resource, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR create interaction.
-
#fhir_delete(resource_type, id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR delete interaction.
-
#fhir_get_capability_statement(client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Fetch the capability statement.
-
#fhir_history(resource_type = nil, id = nil, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR history interaction.
-
#fhir_operation(path, body: nil, client: :default, name: nil, headers: {}, operation_method: :post, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR operation.
-
#fhir_patch(resource_type, id, patchset, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR patch interaction.
-
#fhir_read(resource_type, id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR read interaction.
-
#fhir_search(resource_type = nil, client: :default, params: {}, name: nil, search_method: :get, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR search interaction.
-
#fhir_transaction(bundle = nil, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR batch/transaction interaction.
-
#fhir_update(resource, id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR update interaction.
-
#fhir_vread(resource_type, id, version_id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR vread interaction.
- #find_fhir_client_definition(client) ⇒ Object
- #next_bundle_link(bundle) ⇒ Object
- #perform_refresh(client) ⇒ Object
-
#primitive_parameter?(param) ⇒ Boolean
Wrapper for checking if parameter contents are primitive.
-
#store_request_and_refresh_token(client, name, tags, &block) ⇒ Object
This method wraps a request to automatically refresh its access token if expired.
Methods included from Messages
#add_message, #error_messages?, #info, #messages, #warning
Methods included from Utils::MarkdownFormatter
Class Method Details
.included(klass) ⇒ Object
44 45 46 47 48 49 |
# File 'lib/inferno/dsl/fhir_client.rb', line 44 def self.included(klass) klass.extend ClassMethods klass.extend Forwardable klass.include RequestStorage klass.include TCPExceptionHandler end |
Instance Method Details
#body_to_path(body) ⇒ Object
Converts a list of FHIR Parameters into a query string for GET requests
83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/inferno/dsl/fhir_client.rb', line 83 def body_to_path(body) query_hashes = body.parameter.map do |param| if primitive_parameter?(param) { param.name => param.to_hash.except('name').values[0] } else Inferno::Application[:logger].error "Cannot use GET request with non-primitive datatype #{param.name}" raise ArgumentError, "Cannot use GET request with non-primitive datatype #{param.name}" end end query_hashes.map(&:to_query).join('&') end |
#fetch_all_bundled_resources(resource_type:, bundle: resource, reply_handler: nil, client: :default, max_pages: 20, additional_resource_types: [], tags: []) ⇒ Array<FHIR::Resource>
Fetch all resources from a paginated FHIR bundle
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/inferno/dsl/fhir_client.rb', line 348 def fetch_all_bundled_resources( # rubocop:disable Metrics/CyclomaticComplexity resource_type:, bundle: resource, reply_handler: nil, client: :default, max_pages: 20, additional_resource_types: [], tags: [] ) page_count = 1 resources = [] while bundle && page_count <= max_pages resources += bundle.entry&.map { |entry| entry&.resource } || [] reply_handler&.call(response) break if next_bundle_link(bundle).blank? bundle = fetch_next_bundle(bundle, client, ) page_count += 1 end if resources.any?(&:nil?) warning 'Inferno detected one or more bundle entries with no `resource` element, ' \ 'which is not allowed for a FHIR Bundle with `type` = "searchset".' end valid_resource_types = [resource_type, 'OperationOutcome'].concat(additional_resource_types) resources.compact! invalid_resource_types = resources.reject { |entry| valid_resource_types.include? entry.resourceType } .map(&:resourceType) .uniq if invalid_resource_types.any? info "Received resource type(s) #{invalid_resource_types.join(', ')} in search bundle, " \ "but only expected resource types #{valid_resource_types.join(', ')}. " \ 'This is unusual but allowed if the server believes additional resource types are relevant.' end resources rescue JSON::ParserError Inferno::Application[:logger].error "Could not resolve next bundle: #{next_bundle_link(bundle)}" resources end |
#fetch_next_bundle(bundle, client, tags) ⇒ Object
441 442 443 444 445 446 447 |
# File 'lib/inferno/dsl/fhir_client.rb', line 441 def fetch_next_bundle(bundle, client, ) reply = fhir_client(client).raw_read_url(next_bundle_link(bundle)) store_request('outgoing', tags:) { reply } return unless request.status == 200 fhir_client(client).parse_reply(FHIR::Bundle, fhir_client(client).default_format, reply) end |
#fhir_class_from_resource_type(resource_type) ⇒ Object
Make this a FHIR class method? Something like FHIR.class_for(resource_type)
399 400 401 |
# File 'lib/inferno/dsl/fhir_client.rb', line 399 def fhir_class_from_resource_type(resource_type) FHIR.const_get(resource_type.to_s.camelize) end |
#fhir_client(client = :default) ⇒ FHIR::Client
Return a previously defined FHIR client
56 57 58 59 |
# File 'lib/inferno/dsl/fhir_client.rb', line 56 def fhir_client(client = :default) fhir_clients[client] ||= FHIRClientBuilder.new.build(self, find_fhir_client_definition(client)) end |
#fhir_clients ⇒ Object
66 67 68 |
# File 'lib/inferno/dsl/fhir_client.rb', line 66 def fhir_clients @fhir_clients ||= {} end |
#fhir_create(resource, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR create interaction.
165 166 167 168 169 170 171 |
# File 'lib/inferno/dsl/fhir_client.rb', line 165 def fhir_create(resource, client: :default, name: nil, tags: []) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do fhir_client(client).create(resource) end end end |
#fhir_delete(resource_type, id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR delete interaction.
312 313 314 315 316 317 318 |
# File 'lib/inferno/dsl/fhir_client.rb', line 312 def fhir_delete(resource_type, id, client: :default, name: nil, tags: []) store_request('outgoing', name:, tags:) do tcp_exception_handler do fhir_client(client).destroy(fhir_class_from_resource_type(resource_type), id) end end end |
#fhir_get_capability_statement(client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Fetch the capability statement.
148 149 150 151 152 153 154 155 |
# File 'lib/inferno/dsl/fhir_client.rb', line 148 def fhir_get_capability_statement(client: :default, name: nil, tags: []) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do fhir_client(client).conformance_statement fhir_client(client).reply end end end |
#fhir_history(resource_type = nil, id = nil, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR history interaction.
252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/inferno/dsl/fhir_client.rb', line 252 def fhir_history(resource_type = nil, id = nil, client: :default, name: nil, tags: []) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do if id fhir_client(client).resource_instance_history(fhir_class_from_resource_type(resource_type), id) elsif resource_type fhir_client(client).resource_history(fhir_class_from_resource_type(resource_type)) else fhir_client(client).all_history end end end end |
#fhir_operation(path, body: nil, client: :default, name: nil, headers: {}, operation_method: :post, tags: []) ⇒ Inferno::Entities::Request
This is a placeholder method until the FHIR::Client supports general operations. Note that while both POST and GET methods are allowed, GET is only allowed when the operation does not affect the server’s state. See build.fhir.org/operationdefinition-definitions.html#OperationDefinition.affectsState
Currently does not allow for repeated parameters if using GET
Perform a FHIR operation
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/inferno/dsl/fhir_client.rb', line 113 def fhir_operation( path, body: nil, client: :default, name: nil, headers: {}, operation_method: :post, tags: [] ) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do operation_headers = fhir_client(client).fhir_headers operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present? operation_headers.merge!(headers) if headers.present? case operation_method when :post fhir_client(client).send(:post, path, body, operation_headers) when :get path = "#{path}?#{body_to_path(body)}" if body.present? fhir_client(client).send(:get, path, operation_headers) else Inferno::Application[:logger].error "Cannot perform #{operation_method} requests, use GET or POST" raise ArgumentError, "Cannot perform #{operation_method} requests, use GET or POST" end end end end |
#fhir_patch(resource_type, id, patchset, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR patch interaction.
235 236 237 238 239 240 241 |
# File 'lib/inferno/dsl/fhir_client.rb', line 235 def fhir_patch(resource_type, id, patchset, client: :default, name: nil, tags: []) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do fhir_client(client).partial_update(fhir_class_from_resource_type(resource_type), id, patchset) end end end |
#fhir_read(resource_type, id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR read interaction.
182 183 184 185 186 187 188 |
# File 'lib/inferno/dsl/fhir_client.rb', line 182 def fhir_read(resource_type, id, client: :default, name: nil, tags: []) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do fhir_client(client).read(fhir_class_from_resource_type(resource_type), id) end end end |
#fhir_search(resource_type = nil, client: :default, params: {}, name: nil, search_method: :get, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR search interaction.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/inferno/dsl/fhir_client.rb', line 276 def fhir_search( resource_type = nil, client: :default, params: {}, name: nil, search_method: :get, tags: [] ) search = if search_method == :post { body: params } else { parameters: params } end store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do if resource_type fhir_client(client) .search(fhir_class_from_resource_type(resource_type), { search: }) else fhir_client(client).search_all({ search: }) end end end end |
#fhir_transaction(bundle = nil, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR batch/transaction interaction.
328 329 330 331 332 333 334 335 |
# File 'lib/inferno/dsl/fhir_client.rb', line 328 def fhir_transaction(bundle = nil, client: :default, name: nil, tags: []) store_request('outgoing', name:, tags:) do tcp_exception_handler do fhir_client(client).transaction_bundle = bundle if bundle.present? fhir_client(client).end_transaction end end end |
#fhir_update(resource, id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR update interaction.
217 218 219 220 221 222 223 |
# File 'lib/inferno/dsl/fhir_client.rb', line 217 def fhir_update(resource, id, client: :default, name: nil, tags: []) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do fhir_client(client).update(resource, id) end end end |
#fhir_vread(resource_type, id, version_id, client: :default, name: nil, tags: []) ⇒ Inferno::Entities::Request
Perform a FHIR vread interaction.
200 201 202 203 204 205 206 |
# File 'lib/inferno/dsl/fhir_client.rb', line 200 def fhir_vread(resource_type, id, version_id, client: :default, name: nil, tags: []) store_request_and_refresh_token(fhir_client(client), name, ) do tcp_exception_handler do fhir_client(client).vread(fhir_class_from_resource_type(resource_type), id, version_id) end end end |
#find_fhir_client_definition(client) ⇒ Object
61 62 63 |
# File 'lib/inferno/dsl/fhir_client.rb', line 61 def find_fhir_client_definition(client) self.class.find_fhir_client_definition(client) end |
#next_bundle_link(bundle) ⇒ Object
450 451 452 |
# File 'lib/inferno/dsl/fhir_client.rb', line 450 def next_bundle_link(bundle) bundle&.link&.find { |link| link.relation == 'next' }&.url end |
#perform_refresh(client) ⇒ Object
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
# File 'lib/inferno/dsl/fhir_client.rb', line 415 def perform_refresh(client) credentials = client.auth_info || client.oauth_credentials post( credentials.token_url, body: credentials.oauth2_refresh_params, headers: credentials.oauth2_refresh_headers ) return if request.status != 200 credentials.update_from_response_body(request) if credentials.name.present? Inferno::Repositories::SessionData.new.save( name: credentials.name, value: credentials, type: credentials.is_a?(Inferno::DSL::AuthInfo) ? 'auth_info' : 'oauth_credentials', test_session_id: ) end rescue StandardError => e Inferno::Application[:logger].error "Unable to refresh token: #{e.}" end |
#primitive_parameter?(param) ⇒ Boolean
Wrapper for checking if parameter contents are primitive
74 75 76 77 |
# File 'lib/inferno/dsl/fhir_client.rb', line 74 def primitive_parameter?(param) param_val = param.to_hash.except('name') param_val.any? { |datatype, param_value| FHIR.primitive?(datatype: datatype[5..], value: param_value) } end |
#store_request_and_refresh_token(client, name, tags, &block) ⇒ Object
This method wraps a request to automatically refresh its access token if expired. It’s combined with ‘store_request` so that all of the fhir request methods don’t have to be wrapped twice.
407 408 409 410 411 412 |
# File 'lib/inferno/dsl/fhir_client.rb', line 407 def store_request_and_refresh_token(client, name, , &block) store_request('outgoing', name:, tags:) do perform_refresh(client) if client.need_to_refresh? && client.able_to_refresh? block.call end end |