Class: Inferno::DSL::FHIRResourceValidation::Validator

Inherits:
Object
  • Object
show all
Defined in:
lib/inferno/dsl/fhir_resource_validation.rb

Constant Summary collapse

EXPANSION_PARAMETERS_ENV_VAR =

Environment variable containing the default expansion parameters. Used by #expansion_parameters when no value has been set explicitly. May contain either the raw JSON content of a FHIR Parameters resource (if it starts with {) or a path to a file containing one.

'FHIR_RESOURCE_VALIDATOR_EXPANSION_PARAMETERS'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = nil, test_suite_id = nil, requirements = nil) ⇒ Validator

Returns a new instance of Validator.



47
48
49
50
51
52
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 47

def initialize(name = nil, test_suite_id = nil, requirements = nil, &)
  @name = name
  @test_suite_id = test_suite_id
  instance_eval(&)
  @requirements = requirements
end

Instance Attribute Details

#nameObject

Returns the value of attribute name.



45
46
47
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 45

def name
  @name
end

#requirementsObject (readonly)

Returns the value of attribute requirements.



44
45
46
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 44

def requirements
  @requirements
end

#session_idObject

Returns the value of attribute session_id.



45
46
47
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 45

def session_id
  @session_id
end

#test_suite_idObject

Returns the value of attribute test_suite_id.



45
46
47
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 45

def test_suite_id
  @test_suite_id
end

Instance Method Details

#add_validation_messages_to_runnable(runnable, filtered_issues, message_prefix: '') ⇒ Object

Adds validation messages to the runnable



376
377
378
379
380
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 376

def add_validation_messages_to_runnable(runnable, filtered_issues, message_prefix: '')
  filtered_issues.each do |issue|
    runnable.add_message(issue.severity, "#{message_prefix}#{issue.message}")
  end
end

#additional_validation_messages(target, profile_url) ⇒ Array<ValidatorIssue>

Gets additional validation messages from custom validation blocks. Converts the message hashes to ValidatorIssue objects.

Parameters:

  • target (FHIR::Model, Hash)

    the object being validated

  • profile_url (String)

    the profile URL being validated against

Returns:



530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 530

def additional_validation_messages(target, profile_url)
  additional_validations
    .flat_map { |step| step.call(target, profile_url) }
    .select { |message| message.is_a? Hash }
    .map do |message_hash|
      # Create a synthetic raw_issue for additional validation messages
      synthetic_raw_issue = {
        'level' => message_hash[:type].upcase,
        'location' => 'additional_validation',
        'message' => message_hash[:message]
      }
      ValidatorIssue.new(
        raw_issue: synthetic_raw_issue,
        target: target,
        slice_info: [],
        filtered: false
      )
    end
end

#additional_validationsObject

Used internally by perform_additional_validation



217
218
219
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 217

def additional_validations
  @additional_validations ||= []
end

#apply_relationship_filters(issues) ⇒ Object

Performs filtering based on relationships between issues. Processes sub-issues of each issue before processing the top-level issues.

Parameters:



594
595
596
597
598
599
600
601
602
603
604
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 594

def apply_relationship_filters(issues)
  apply_relationship_filters_to_children(issues)

  issues.each_with_index do |issue, index|
    next if issue.filtered # Skip if already filtered

    # Apply conditional filters.
    # As more are needed, split with a "next if issue.filtered" pattern and add the new filter.
    filter_contained_resource(issues, issue, index)
  end
end

#apply_relationship_filters_to_children(issues) ⇒ Object

Performs filtering based on relationships between issues on the sub-issues of a list of issues.

Parameters:



611
612
613
614
615
616
617
618
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 611

def apply_relationship_filters_to_children(issues)
  issues.each do |issue|
    next if issue.filtered # Skip if already filtered

    # Recursively process nested slice_info first (depth-first)
    apply_relationship_filters(issue.slice_info) if issue.slice_info.any?
  end
end

#at_least_one_profile_without_errors?(details_issues) ⇒ Boolean

Checks if any profile is valid (all error-level slices are filtered)

Returns:

  • (Boolean)


655
656
657
658
659
660
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 655

def at_least_one_profile_without_errors?(details_issues)
  details_issues.any? do |details_issue|
    error_level_slices = details_issue.slice_info.select { |s| s.severity == 'error' }
    error_level_slices.all?(&:filtered)
  end
end

#build_expansion_parameters(value) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 193

def build_expansion_parameters(value)
  case value
  when Hash
    build_expansion_parameters_from_json_content(value.to_json)
  else
    {
      fileName: File.basename(value),
      fileContent: File.read(value),
      fileType: nil
    }
  end
end

#build_expansion_parameters_from_env(env_value) ⇒ Object

Determines whether the environment variable's content is raw JSON or a file path based on its first non-whitespace character.



184
185
186
187
188
189
190
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 184

def build_expansion_parameters_from_env(env_value)
  if env_value.lstrip.start_with?('{')
    build_expansion_parameters_from_json_content(env_value)
  else
    build_expansion_parameters(env_value)
  end
end

#build_expansion_parameters_from_json_content(json_content) ⇒ Object



207
208
209
210
211
212
213
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 207

def build_expansion_parameters_from_json_content(json_content)
  {
    fileName: 'expansion_parameters.json',
    fileContent: json_content,
    fileType: nil
  }
end

#call_validator(target, profile_url) ⇒ Object



448
449
450
451
452
453
454
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 448

def call_validator(target, profile_url)
  request_body = wrap_target_for_hl7_wrapper(target, profile_url)
  Faraday.new(
    url,
    request: { timeout: 600 }
  ).post('validate', request_body, content_type: 'application/json')
end

#conformant?(target, profile_url, runnable, add_messages_to_runnable: true, message_prefix: '', validator_response_details: nil) ⇒ Boolean

Returns:

  • (Boolean)


323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 323

def conformant?(target, profile_url, runnable, add_messages_to_runnable: true,
                message_prefix: '', validator_response_details: nil)

  # 1. Get raw content from validator
  response = get_raw_validator_content(target, profile_url, runnable)

  # 2. Convert to validation issues
  issues = get_issues_from_validator_response(response, target)

  # 3. Add additional validation messages
  issues = join_additional_validation_messages(issues, target, profile_url)

  # 4. Mark resources as filtered
  mark_issues_for_filtering(issues)

  # 5. Add error messages to runnable
  filtered_issues = issues.reject(&:filtered)
  add_validation_messages_to_runnable(runnable, filtered_issues, message_prefix:) if add_messages_to_runnable
  validator_response_details&.concat(issues)

  # 6. Return validity
  filtered_issues.none? { |issue| issue.severity == 'error' }
rescue Inferno::Exceptions::ErrorInValidatorException
  raise
rescue StandardError => e
  runnable.add_message('error', e.message)
  raise Inferno::Exceptions::ErrorInValidatorException,
        'Error occurred in the validator. Review Messages tab or validator service logs for more information.'
end

#conforms_to_logical_model?(object, model_url, runnable, add_messages_to_runnable: true, message_prefix: '', validator_response_details: nil) ⇒ Boolean

Validate a FHIR resource and determine if it's valid. Adds validation messages to the runnable if add_messages_to_runnable is true.

Returns:

  • (Boolean)


259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 259

def conforms_to_logical_model?(object, model_url, runnable, add_messages_to_runnable: true,
                               message_prefix: '', validator_response_details: nil)

  unless model_url.present?
    raise Inferno::Exceptions::TestSuiteImplementationException.new(
      'Logical Model Validation',
      'The profile of the logical model must be provided.'
    )
  end

  unless object.present?
    if add_messages_to_runnable
      runnable.add_message(:error,
                           "#{message_prefix}No object to check for conformance.")
    end
    return false
  end

  unless object.is_a?(Hash)
    raise Inferno::Exceptions::TestSuiteImplementationException.new(
      'Logical Model Validation',
      "Expected a Hash, got a #{object.class}."
    )
  end

  conformant?(object, model_url, runnable, add_messages_to_runnable:, message_prefix:,
                                           validator_response_details:)
end

#contained_resource_profile_issue?(base_issue) ⇒ Boolean

Checks if a base issue should be processed for contained resource filtering

Returns:

  • (Boolean)


643
644
645
646
647
648
649
650
651
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 643

def contained_resource_profile_issue?(base_issue)
  return false if base_issue.filtered # Skip if already filtered

  message_id = base_issue.raw_issue['messageId']
  return false unless message_id == 'Reference_REF_CantMatchChoice'
  return false unless base_issue.severity == 'error' || base_issue.severity == 'warning'

  true
end

#convert_raw_issue_to_validator_issue(raw_issue, target) ⇒ ValidatorIssue

Converts a single raw issue hash to a ValidatorIssue object. Recursively processes sliceInfo if present.

Parameters:

  • raw_issue (Hash)

    the raw issue from validator response

  • target (FHIR::Model, Hash)

    the object being validated

Returns:



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 430

def convert_raw_issue_to_validator_issue(raw_issue, target)
  # Recursively process sliceInfo
  slice_info = []
  if raw_issue['sliceInfo']&.any?
    slice_info = raw_issue['sliceInfo'].map do |slice_issue|
      convert_raw_issue_to_validator_issue(slice_issue, target)
    end
  end

  ValidatorIssue.new(
    raw_issue: raw_issue,
    target: target,
    slice_info: slice_info,
    filtered: false
  )
end

#exclude_message {|message| ... } ⇒ Object

Filter out unwanted validation messages. Any messages for which the block evalutates to a truthy value will be excluded.

Examples:

validator do
  exclude_message { |message| message.type == 'info' }
end

Yield Parameters:



252
253
254
255
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 252

def exclude_message(&block)
  @exclude_message = block if block_given?
  @exclude_message
end

#exclude_unresolved_url_messageProc

Filter for excluding unresolved URL validation messages

Returns:

  • (Proc)

    a proc that checks if a message is an unresolved URL message



582
583
584
585
586
587
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 582

def exclude_unresolved_url_message
  @exclude_unresolved_url_message ||= proc do |message|
    message.message.match?(/\A\S+: [^:]+: URL value '.*' does not resolve/) ||
      message.message.match?(/\A\S+: [^:]+: No definition could be found for URL value '.*'/)
  end
end

#expansion_parameters(value = nil) ⇒ Object

Set the expansion parameters to be sent with each validation request. This configures how the validator's terminology engine expands value sets during validation (e.g. designation preferences, forcing the use of the latest terminology versions, etc.). The content is sent inline with every validation request made by this validator, since the validator does not have access to Inferno's filesystem.

Accepts either a Hash containing the contents of a FHIR Parameters resource, or a String path to a file (JSON or XML) containing one. The file is read once, the first time it's needed.

If never set explicitly, this falls back to the FHIR_RESOURCE_VALIDATOR_EXPANSION_PARAMETERS environment variable, if present. This allows a shared set of expansion parameters to be configured once for every test kit that uses a given validator instance, while still letting individual test kits opt out or override it by calling this method themselves. The environment variable's content is treated as raw JSON if it starts with {, and otherwise as a file path.

Examples:

# Passing a Hash
fhir_resource_validator do
  url 'http://example.com/validator'
  expansion_parameters({
    resourceType: 'Parameters',
    parameter: [{ name: 'excludeNested', valueBoolean: true }]
  })
end
# Passing a file path
fhir_resource_validator do
  url 'http://example.com/validator'
  expansion_parameters 'path/to/expansion_parameters.json'
end

Parameters:

  • value (Hash, String, nil) (defaults to: nil)

    contents of a Parameters resource as a Hash, or a path to a file (JSON or XML) containing one



169
170
171
172
173
174
175
176
177
178
179
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 169

def expansion_parameters(value = nil)
  if value
    @expansion_parameters = build_expansion_parameters(value)
  elsif !@expansion_parameters_resolved
    env_value = ENV.fetch(EXPANSION_PARAMETERS_ENV_VAR, nil)
    @expansion_parameters = build_expansion_parameters_from_env(env_value) if env_value
  end
  @expansion_parameters_resolved = true

  @expansion_parameters
end

#filter_contained_resource(issues, base_issue, base_index) ⇒ Object

Filters Reference_REF_CantMatchChoice errors for contained resources. If a resource matches at least one profile (all slices filtered), marks the base error as filtered.

Parameters:

  • issues (Array<ValidatorIssue>)

    the complete list of issues

  • base_issue (ValidatorIssue)

    the issue to potentially filter

  • base_index (Integer)

    the index of the base issue in the issues array



627
628
629
630
631
632
633
634
635
636
637
638
639
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 627

def filter_contained_resource(issues, base_issue, base_index)
  return unless contained_resource_profile_issue?(base_issue)

  base_location = base_issue.location
  profile_detail_issues = find_following_profile_details_issues(issues, base_index, base_location)

  return if profile_detail_issues.empty?
  return unless at_least_one_profile_without_errors?(profile_detail_issues)

  base_issue.filtered = true
  # Also filter all the Details messages
  profile_detail_issues.each { |details_issue| details_issue.filtered = true }
end

#filter_individual_messages(issues) ⇒ Object

Recursively filters validation issues by setting the filtered flag. Applies filtering to both the issue itself and all nested slice_info.

Parameters:



555
556
557
558
559
560
561
562
563
564
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 555

def filter_individual_messages(issues)
  issues.each do |issue|
    # Create a mock message entity to check filtering rules
    mock_message = Entities::Message.new(type: issue.severity, message: issue.message)
    issue.filtered = should_filter_message?(mock_message)

    # Recursively filter slice_info
    filter_individual_messages(issue.slice_info) if issue.slice_info.any?
  end
end

#find_following_profile_details_issues(issues, start_index, base_location) ⇒ Array<ValidatorIssue>

Finds consecutive Details messages following a base issue at the same location.

Parameters:

  • issues (Array<ValidatorIssue>)

    the complete list of issues

  • start_index (Integer)

    the index to start searching from

  • base_location (String)

    the location to match

Returns:



669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 669

def find_following_profile_details_issues(issues, start_index, base_location)
  details_issues = []
  index = start_index + 1

  while index < issues.length
    issue = issues[index]

    # Check if this is a Details message for the same location
    break unless issue.message.include?('Details for #') && issue.location == base_location

    details_issues << issue
    index += 1
  end

  details_issues
end

#get_issues_from_validator_response(response, target) ⇒ Array<ValidatorIssue>

Converts raw validator response into a list of ValidatorIssue objects. Recursively processes slice information.

Parameters:

  • response (Faraday::Response)

    the HTTP response from the validator

  • target (FHIR::Model, Hash)

    the object being validated

Returns:



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 406

def get_issues_from_validator_response(response, target)
  response_body = remove_invalid_characters(response.body)
  response_hash = JSON.parse(response_body)

  if response_hash['sessionId'].present? && response_hash['sessionId'] != @session_id
    validator_session_repo.save(test_suite_id:, validator_session_id: response_hash['sessionId'],
                                validator_name: name.to_s, suite_options: requirements)
    @session_id = response_hash['sessionId']
  end

  raw_issues = response_hash.dig('outcomes', 0, 'issues') || []

  raw_issues.map do |raw_issue|
    convert_raw_issue_to_validator_issue(raw_issue, target)
  end
end

#get_raw_validator_content(target, profile_url, runnable) ⇒ Faraday::Response

Gets raw content from validator including error handling

Parameters:

  • target (FHIR::Model, Hash)

    the object to validate

  • profile_url (String)

    the profile URL to validate against

  • runnable (Object)

    the runnable context

Returns:

  • (Faraday::Response)

    the HTTP response from the validator



359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 359

def get_raw_validator_content(target, profile_url, runnable)
  response = call_validator(target, profile_url)

  unless response.status == 200
    raise Inferno::Exceptions::ErrorInValidatorException,
          'Error occurred in the validator. Review Messages tab or validator service logs for more information.'
  end

  response
rescue StandardError => e
  runnable.add_message('error', e.message)
  Application[:logger].error(e.message)
  raise Inferno::Exceptions::ErrorInValidatorException, validator_error_message(e)
end

#igs(*validator_igs) ⇒ Object

Set the IGs that the validator will need to load

Examples:

igs "hl7.fhir.us.core#4.0.0"
igs("hl7.fhir.us.core#3.1.1", "hl7.fhir.us.core#6.0.0")

Parameters:

  • validator_igs (Array<String>)


73
74
75
76
77
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 73

def igs(*validator_igs)
  validation_context(igs: validator_igs) if validator_igs.any?

  validation_context.igs
end

#join_additional_validation_messages(issues, target, profile_url) ⇒ Array<ValidatorIssue>

Joins additional validation messages to the issues list

Parameters:

  • issues (Array<ValidatorIssue>)

    the list of validator issues

  • target (FHIR::Model)

    the object being validated

  • profile_url (String)

    the profile URL being validated against

Returns:

  • (Array<ValidatorIssue>)

    the complete list of issues including additional messages



505
506
507
508
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 505

def join_additional_validation_messages(issues, target, profile_url)
  additional_issues = additional_validation_messages(target, profile_url)
  issues + additional_issues
end

#mark_issues_for_filtering(issues) ⇒ Object

Marks validation issues for filtering by setting the filtered flag on issues that should be excluded. Recursively marks issues in slice_info.

Parameters:



515
516
517
518
519
520
521
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 515

def mark_issues_for_filtering(issues)
  # Recursively mark all issues for filtering
  filter_individual_messages(issues)

  # Perform conditional filtering based on special cases
  apply_relationship_filters(issues)
end

#perform_additional_validation {|resource, profile_url| ... } ⇒ Object

Perform validation steps in addition to FHIR validation.

Examples:

perform_additional_validation do |resource, profile_url|
  if something_is_wrong
    { type: 'error', message: 'something is wrong' }
  else
    { type: 'info', message: 'everything is ok' }
  end
end

Yield Parameters:

  • resource (FHIR::Model)

    the resource being validated

  • profile_url (String)

    the profile the resource is being validated against

Yield Returns:

  • (Array<Hash<Symbol, String>>, Hash<Symbol, String>)

    The block should return a Hash or an Array of Hashes if any validation messages should be added. The Hash must contain two keys: :type and :message. :type can have a value of 'info', 'warning', or 'error'. A type of 'error' means the resource is invalid. :message contains the message string itself.



240
241
242
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 240

def perform_additional_validation(&block)
  additional_validations << block
end

#remove_invalid_characters(string) ⇒ String

Removes invalid characters from a string to prepare for JSON parsing

Parameters:

  • string (String)

    the string to clean

Returns:

  • (String)

    the cleaned string



494
495
496
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 494

def remove_invalid_characters(string)
  string.gsub(/[^[:print:]\r\n]+/, '')
end

#resource_is_valid?(resource, profile_url, runnable, add_messages_to_runnable: true, message_prefix: '', validator_response_details: nil) ⇒ Boolean

Validate a FHIR resource and determine if it's valid. Adds validation messages to the runnable if add_messages_to_runnable is true.

Parameters:

  • resource (FHIR::Model)

    the resource to validate

  • profile_url (String)

    the profile URL to validate against

  • runnable (Object)

    the runnable context (test/group/suite)

  • add_messages_to_runnable (Boolean) (defaults to: true)

    whether to add messages to the runnable

  • message_prefix (String) (defaults to: '')

    Prefix to add to the start of logged messages

  • validator_response_details (Array, nil) (defaults to: nil)

    if not nil, the service will populate this array with the detailed response message from the validator service. Can be used by test kits to perform custom handling of error messages.

Returns:

  • (Boolean)

    true if the resource is valid

See Also:

  • Inferno::DSL::FHIRResourceValidation#resource_is_valid?


301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 301

def resource_is_valid?(resource, profile_url, runnable, add_messages_to_runnable: true,
                       message_prefix: '', validator_response_details: nil)

  unless resource.present?
    runnable.add_message(:error, "#{message_prefix}No resource to validate.") if add_messages_to_runnable
    return false
  end

  unless resource.is_a?(FHIR::Model)
    raise Inferno::Exceptions::TestSuiteImplementationException.new(
      'FHIR Resource Validation',
      "Expected a FHIR::Model, got a #{resource.class}."
    )

  end
  profile_url ||= FHIR::Definitions.resource_definition(resource.resourceType).url

  conformant?(resource, profile_url, runnable, add_messages_to_runnable:, message_prefix:,
                                               validator_response_details:)
end

#should_filter_message?(message) ⇒ Boolean

Determines if a message should be filtered based on exclusion rules. Applies both the unresolved URL filter and any custom exclude_message filter.

Parameters:

Returns:

  • (Boolean)

    true if the message should be filtered out



572
573
574
575
576
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 572

def should_filter_message?(message)
  should_filter = exclude_unresolved_url_message.call(message) ||
                  exclude_message&.call(message)
  should_filter || false
end

#url(validator_url = nil) ⇒ Object

Set the url of the validator service

Parameters:

  • validator_url (String) (defaults to: nil)


61
62
63
64
65
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 61

def url(validator_url = nil)
  @url = validator_url if validator_url
  @url ||= ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL')
  @url
end

#validate(target, profile_url) ⇒ String

Post an object to the validation service for validating. Returns the raw validator response body.

Parameters:

Returns:

  • (String)

    the body of the validation response



463
464
465
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 463

def validate(target, profile_url)
  call_validator(target, profile_url).body
end

#validation_context(definition = nil) ⇒ Object Also known as: cli_context

Set the validationContext used as part of each validation request. Fields may be passed as either a Hash or block. Note that all fields included here will be sent directly in requests, there is no check that the fields are correct.

Examples:

# Passing fields in a block
fhir_resource_validator do
  url 'http://example.com/validator'
  validation_context do
    noExtensibleBindingMessages true
    allowExampleUrls true
    txServer nil
  end
end
# Passing fields in a Hash
fhir_resource_validator do
  url 'http://example.org/validator'
  validation_context({
    noExtensibleBindingMessages: true,
    allowExampleUrls: true,
    txServer: nil
  })
end

Parameters:

  • definition (Hash) (defaults to: nil)

    raw fields to set, optional



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 107

def validation_context(definition = nil, &)
  if @validation_context
    if definition
      @validation_context.definition.merge!(definition.deep_symbolize_keys)
    elsif block_given?
      @validation_context.instance_eval(&)
    end
  else
    @validation_context = ValidationContext.new(definition || {}, &)
  end
  @validation_context
end

#validator_error_message(error) ⇒ String

Add a specific error message for specific network problems to help the user

Parameters:

  • error (Exception)

    An error exception that happened during evaluator connection

Returns:

  • (String)

    A readable error message describing the specific network problem



472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 472

def validator_error_message(error)
  case error
  when Faraday::ConnectionFailed
    "Connection failed to validator at #{url}."
  when Faraday::TimeoutError
    "Timeout while connecting to validator at #{url}."
  when Faraday::SSLError
    "SSL error connecting to validator at #{url}."
  when Faraday::ClientError  # these are 400s
    "Client error (4xx) connecting to validator at #{url}."
  when Faraday::ServerError  # these are 500s
    "Server error (5xx) from validator at #{url}."
  else
    "Unable to connect to validator at #{url}."
  end
end

#validator_session_repoObject



54
55
56
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 54

def validator_session_repo
  @validator_session_repo ||= Inferno::Repositories::ValidatorSessions.new
end

#warm_up(target, profile_url) ⇒ Object

Warm up the validator session by sending a test validation request. This initializes the validator session and persists it for future use.

Parameters:

  • target (FHIR::Model, Hash)

    the object to validate

  • profile_url (String)

    the profile URL to validate against



387
388
389
390
391
392
393
394
395
396
397
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 387

def warm_up(target, profile_url)
  response_body = validate(target, profile_url)
  res = JSON.parse(response_body)
  session_id = res['sessionId']
  validator_session_repo.save(test_suite_id:, validator_session_id: session_id,
                              validator_name: name.to_s, suite_options: requirements)
  self.session_id = session_id
rescue JSON::ParserError
  Application[:logger]
    .error("Validator warm_up - error unexpected response format from validator: #{response_body}")
end

#wrap_target_for_hl7_wrapper(target, profile_url) ⇒ Object



687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'lib/inferno/dsl/fhir_resource_validation.rb', line 687

def wrap_target_for_hl7_wrapper(target, profile_url)
  validator_session_id =
    validator_session_repo.find_validator_session_id(test_suite_id,
                                                     name.to_s, requirements)

  @session_id = validator_session_id if validator_session_id

  # HL7 Validator Core 6.5.19+ renamed `cliContext` to `validationContext`.
  # This allows backward compatibility until the validator-wrapper is updated.
  context_key = Feature.use_validation_context_key? ? :validationContext : :cliContext

  file_contents =
    if target.is_a?(Hash)
      target.to_json
    else
      target.source_contents
    end

  wrapped_resource = {
    context_key => {
      **validation_context.definition,
      profiles: [profile_url]
    },
    filesToValidate: [
      {
        fileName: "#{profile_url.split('/').last}.json",
        fileContent: file_contents,
        fileType: 'json'
      }
    ],
    sessionId: @session_id
  }
  wrapped_resource[:expansionParameters] = expansion_parameters if expansion_parameters

  wrapped_resource.to_json
end