diff --git a/lib/fhir_client/client.rb b/lib/fhir_client/client.rb index e46a4744..ab6fa40c 100644 --- a/lib/fhir_client/client.rb +++ b/lib/fhir_client/client.rb @@ -289,21 +289,21 @@ def try_conformance_formats(default_format) rescue @cached_capability_statement = nil end - if @cached_capability_statement.nil? + if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4.0') use_r4b begin @cached_capability_statement = parse_reply(FHIR::R4B::CapabilityStatement, frmt, reply) rescue @cached_capability_statement = nil end - unless @cached_capability_statement + if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('4') use_r5 begin @cached_capability_statement = parse_reply(FHIR::R5::CapabilityStatement, frmt, reply) rescue @cached_capability_statement = nil end - unless @cached_capability_statement + if @cached_capability_statement.nil? || !@cached_capability_statement.fhirVersion.starts_with?('5') use_stu3 begin @cached_capability_statement = parse_reply(FHIR::STU3::CapabilityStatement, frmt, reply) @@ -353,11 +353,11 @@ def parse_reply(klass, format, response) else FHIR::DSTU2::Json.from_json(response.body) end - elsif(@fhir_version == :r4 || klass&.ancestors&.include?(FHIR::Model)) + elsif(@fhir_version == :stu3 || klass&.ancestors&.include?(FHIR::STU3::Model)) if(format.include?('xml')) - FHIR::Xml.from_xml(response.body) + FHIR::STU3::Xml.from_xml(response.body) else - FHIR::Json.from_json(response.body) + FHIR::STU3::Json.from_json(response.body) end elsif(@fhir_version == :r4b || klass&.ancestors&.include?(FHIR::R4B::Model)) if(format.include?('xml')) @@ -373,9 +373,9 @@ def parse_reply(klass, format, response) end else if(format.include?('xml')) - FHIR::STU3::Xml.from_xml(response.body) + FHIR::Xml.from_xml(response.body) else - FHIR::STU3::Json.from_json(response.body) + FHIR::Json.from_json(response.body) end end rescue => e diff --git a/test/fixtures/r4b_capabilitystatement.json b/test/fixtures/r4b_capabilitystatement.json new file mode 100644 index 00000000..408bf3d9 --- /dev/null +++ b/test/fixtures/r4b_capabilitystatement.json @@ -0,0 +1,148 @@ +{ + "resourceType" : "CapabilityStatement", + "id" : "example", + "text" : { + "status" : "generated", + "div" : "
\n\t\t\t

The EHR Server supports the following transactions for the resource Person: read, vread, \n update, history, search(name,gender), create and updates.

\n\t\t\t

The EHR System supports the following message: admin-notify::Person.

\n\t\t\t

The EHR Application has a \n general document profile.\n

\n\t\t
" + }, + "url" : "urn:uuid:68d043b5-9ecf-4559-a57a-396e0d452311", + "version" : "20130510", + "name" : "ACME-EHR", + "title" : "ACME EHR capability statement", + "status" : "draft", + "experimental" : true, + "date" : "2012-01-04", + "publisher" : "ACME Corporation", + "contact" : [{ + "name" : "System Administrator", + "telecom" : [{ + "system" : "email", + "value" : "wile@acme.org" + }] + }], + "description" : "This is the FHIR capability statement for the main EHR at ACME for the private interface - it does not describe the public interface", + "useContext" : [{ + "code" : { + "system" : "http://terminology.hl7.org/CodeSystem/usage-context-type", + "code" : "focus" + }, + "valueCodeableConcept" : { + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/variant-state", + "code" : "positive" + }] + } + }], + "jurisdiction" : [{ + "coding" : [{ + "system" : "urn:iso:std:iso:3166", + "code" : "US", + "display" : "United States of America (the)" + }] + }], + "purpose" : "Main EHR capability statement, published for contracting and operational support", + "copyright" : "Copyright © Acme Healthcare and GoodCorp EHR Systems", + "kind" : "instance", + "instantiates" : ["http://ihe.org/fhir/CapabilityStatement/pixm-client"], + "software" : { + "name" : "EHR", + "version" : "0.00.020.2134", + "releaseDate" : "2012-01-04" + }, + "implementation" : { + "description" : "main EHR at ACME", + "url" : "http://10.2.3.4/fhir" + }, + "fhirVersion" : "4.3.0", + "format" : ["xml", + "json"], + "patchFormat" : ["application/xml-patch+xml", + "application/json-patch+json"], + "implementationGuide" : ["http://hl7.org/fhir/us/lab"], + "rest" : [{ + "mode" : "server", + "documentation" : "Main FHIR endpoint for acem health", + "security" : { + "cors" : true, + "service" : [{ + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/restful-security-service", + "code" : "SMART-on-FHIR" + }] + }], + "description" : "See Smart on FHIR documentation" + }, + "resource" : [{ + "type" : "Patient", + "profile" : "http://registry.fhir.org/r4/StructureDefinition/7896271d-57f6-4231-89dc-dcc91eab2416", + "supportedProfile" : ["http://registry.fhir.org/r4/StructureDefinition/00ab9e7a-06c7-4f77-9234-4154ca1e3347"], + "documentation" : "This server does not let the clients create identities.", + "interaction" : [{ + "code" : "read" + }, + { + "code" : "vread", + "documentation" : "Only supported for patient records since 12-Dec 2012" + }, + { + "code" : "update" + }, + { + "code" : "history-instance" + }, + { + "code" : "create" + }, + { + "code" : "history-type" + }], + "versioning" : "versioned-update", + "readHistory" : true, + "updateCreate" : false, + "conditionalCreate" : true, + "conditionalRead" : "full-support", + "conditionalUpdate" : false, + "conditionalDelete" : "not-supported", + "searchInclude" : ["Organization"], + "searchRevInclude" : ["Person"], + "searchParam" : [{ + "name" : "identifier", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-identifier", + "type" : "token", + "documentation" : "Only supports search by institution MRN" + }, + { + "name" : "general-practitioner", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-general-practitioner", + "type" : "reference" + }] + }], + "interaction" : [{ + "code" : "transaction" + }, + { + "code" : "history-system" + }], + "compartment" : ["http://hl7.org/fhir/CompartmentDefinition/patient"] + }], + "messaging" : [{ + "endpoint" : [{ + "protocol" : { + "system" : "http://terminology.hl7.org/CodeSystem/message-transport", + "code" : "mllp" + }, + "address" : "mllp:10.1.1.10:9234" + }], + "reliableCache" : 30, + "documentation" : "ADT A08 equivalent for external system notifications", + "supportedMessage" : [{ + "mode" : "receiver", + "definition" : "http://hl7.org/fhir/MessageDefinition/example" + }] + }], + "document" : [{ + "mode" : "consumer", + "documentation" : "Basic rules for all documents in the EHR system", + "profile" : "http://fhir.hl7.org/base/Profilebc054d23-75e1-4dc6-aca5-838b6b1ac81d/_history/b5fdd9fc-b021-4ea1-911a-721a60663796" + }] +} \ No newline at end of file diff --git a/test/fixtures/r5_capabilitystatement.json b/test/fixtures/r5_capabilitystatement.json new file mode 100644 index 00000000..79a207cb --- /dev/null +++ b/test/fixtures/r5_capabilitystatement.json @@ -0,0 +1,151 @@ +{ + "resourceType" : "CapabilityStatement", + "id" : "example", + "text" : { + "status" : "generated", + "div" : "
\n\t\t\t\n

The EHR Server supports the following transactions for the resource Person: read, vread, \n update, history, search(name,gender), create and updates.

\n\t\t\t\n

The EHR System supports the following message: admin-notify::Person.

\n\t\t\t\n

The EHR Application has a \n \n general document profile.\n \n

\n\t\t\n
" + }, + "url" : "urn:uuid:68d043b5-9ecf-4559-a57a-396e0d452311", + "version" : "20130510", + "name" : "ACMEEHR", + "title" : "ACME EHR capability statement", + "status" : "draft", + "experimental" : true, + "date" : "2012-01-04", + "publisher" : "ACME Corporation", + "contact" : [{ + "name" : "System Administrator", + "telecom" : [{ + "system" : "email", + "value" : "wile@acme.org" + }] + }], + "description" : "This is the FHIR capability statement for the main EHR at ACME for the private interface - it does not describe the public interface", + "useContext" : [{ + "code" : { + "system" : "http://terminology.hl7.org/CodeSystem/usage-context-type", + "code" : "focus" + }, + "valueCodeableConcept" : { + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/variant-state", + "code" : "positive" + }] + } + }], + "jurisdiction" : [{ + "coding" : [{ + "system" : "urn:iso:std:iso:3166", + "code" : "US", + "display" : "United States of America (the)" + }] + }], + "purpose" : "Main EHR capability statement, published for contracting and operational support", + "copyright" : "Copyright © Acme Healthcare and GoodCorp EHR Systems", + "kind" : "instance", + "instantiates" : ["http://ihe.org/fhir/CapabilityStatement/pixm-client"], + "software" : { + "name" : "EHR", + "version" : "0.00.020.2134", + "releaseDate" : "2012-01-04" + }, + "implementation" : { + "description" : "main EHR at ACME", + "url" : "http://10.2.3.4/fhir" + }, + "fhirVersion" : "5.0.0", + "format" : ["xml", + "json"], + "patchFormat" : ["application/xml-patch+xml", + "application/json-patch+json"], + "acceptLanguage" : ["en", + "es"], + "implementationGuide" : ["http://example.org/fhir/us/lab"], + "rest" : [{ + "mode" : "server", + "documentation" : "Main FHIR endpoint for acem health", + "security" : { + "cors" : true, + "service" : [{ + "coding" : [{ + "system" : "http://hl7.org/fhir/restful-security-service", + "code" : "SMART-on-FHIR" + }] + }], + "description" : "See Smart on FHIR documentation" + }, + "resource" : [{ + "type" : "Patient", + "profile" : "http://registry.fhir.org/r5/StructureDefinition/7896271d-57f6-4231-89dc-dcc91eab2416", + "supportedProfile" : ["http://registry.fhir.org/r5/StructureDefinition/00ab9e7a-06c7-4f77-9234-4154ca1e3347"], + "documentation" : "This server does not let the clients create identities.", + "interaction" : [{ + "code" : "read" + }, + { + "code" : "vread", + "documentation" : "Only supported for patient records since 12-Dec 2012" + }, + { + "code" : "update" + }, + { + "code" : "history-instance" + }, + { + "code" : "create" + }, + { + "code" : "history-type" + }], + "versioning" : "versioned-update", + "readHistory" : true, + "updateCreate" : false, + "conditionalCreate" : true, + "conditionalRead" : "full-support", + "conditionalUpdate" : false, + "conditionalPatch" : false, + "conditionalDelete" : "not-supported", + "searchInclude" : ["Patient:organization"], + "searchRevInclude" : ["Person:patient"], + "searchParam" : [{ + "name" : "identifier", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-identifier", + "type" : "token", + "documentation" : "Only supports search by institution MRN" + }, + { + "name" : "general-practitioner", + "definition" : "http://hl7.org/fhir/SearchParameter/Patient-general-practitioner", + "type" : "reference" + }] + }], + "interaction" : [{ + "code" : "transaction" + }, + { + "code" : "history-system" + }], + "compartment" : ["http://hl7.org/fhir/CompartmentDefinition/patient"] + }], + "messaging" : [{ + "endpoint" : [{ + "protocol" : { + "system" : "http://hl7.org/fhir/message-transport", + "code" : "mllp" + }, + "address" : "mllp:10.1.1.10:9234" + }], + "reliableCache" : 30, + "documentation" : "ADT A08 equivalent for external system notifications", + "supportedMessage" : [{ + "mode" : "receiver", + "definition" : "http://hl7.org/fhir/MessageDefinition/example" + }] + }], + "document" : [{ + "mode" : "consumer", + "documentation" : "Basic rules for all documents in the EHR system", + "profile" : "http://fhir.hl7.org/base/Profilebc054d23-75e1-4dc6-aca5-838b6b1ac81d/_history/b5fdd9fc-b021-4ea1-911a-721a60663796" + }] +} \ No newline at end of file diff --git a/test/unit/client_interface_sections/read_test.rb b/test/unit/client_interface_sections/read_test.rb index 14219503..87d8ea1f 100644 --- a/test/unit/client_interface_sections/read_test.rb +++ b/test/unit/client_interface_sections/read_test.rb @@ -15,7 +15,7 @@ def test_read patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test/).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.read(FHIR::Patient,'foo') assert reply.resource.is_a?(FHIR::Patient) @@ -29,7 +29,7 @@ def test_vread patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test\/.*_history\/2/).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.vread(FHIR::Patient,'foo', 2) assert reply.resource.is_a?(FHIR::Patient) @@ -46,7 +46,7 @@ def test_conditional_read_since patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test/).with(headers: {'If-Modified-Since' => 'Wed, 21 Oct 2015 07:28:00 GMT'}).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.conditional_read_since(FHIR::Patient,'foo', 'Wed, 21 Oct 2015 07:28:00 GMT') assert reply.resource.is_a?(FHIR::Patient) @@ -59,7 +59,7 @@ def test_conditional_read_version patient = FHIR::Patient.new({'gender'=>'female', 'active'=>true, 'deceasedBoolean'=>false}) stub_request(:get, /read-test/).with(headers: {'If-None-Match' => 'W/ABC'}).to_return(status: 200, body: patient.to_json, headers: {'Content-Type'=>'application/fhir+json', 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json reply = temp.conditional_read_version(FHIR::Patient,'foo','ABC') assert reply.resource.is_a?(FHIR::Patient) @@ -77,7 +77,7 @@ def test_raw_read 'ETag'=>'W/"foo"', 'Last-Modified'=>Time.now.strftime("%a, %e %b %Y %T %Z")}) temp = client - temp.use_stu3 + temp.use_r4 temp.default_json options = {resource: FHIR::Patient, id: 'foo'} reply = temp.raw_read(options) diff --git a/test/unit/multiversion_test.rb b/test/unit/multiversion_test.rb index eb4134d0..a5ecd7f2 100644 --- a/test/unit/multiversion_test.rb +++ b/test/unit/multiversion_test.rb @@ -1,5 +1,5 @@ require_relative '../test_helper' - +require 'pry' class MultiversionTest < Test::Unit::TestCase def test_autodetect_stu3 @@ -47,6 +47,36 @@ def test_autodetect_r4 assert client.default_format.include? 'json' end + def test_autodetect_r4b + root = File.expand_path '..', File.dirname(File.absolute_path(__FILE__)) + capabilitystatement = File.read(File.join(root, 'fixtures', 'r4b_capabilitystatement.json')) + stub_request(:get, /autodetect/).to_return(body: capabilitystatement) + client = FHIR::Client.new('autodetect') + # Intentionally set the client incorrectly + client.default_xml + client.use_r4 + assert client.cached_capability_statement.nil? + assert client.detect_version == :r4b, "Expected Version to be r4b, but found #{client.detect_version.to_s}" + assert !client.cached_capability_statement.nil?, 'Expected Capability Statement to be cached' + assert client.cached_capability_statement.is_a?(FHIR::R4B::CapabilityStatement) + assert client.default_format.include? 'json' + end + + def test_autodetect_r5 + root = File.expand_path '..', File.dirname(File.absolute_path(__FILE__)) + capabilitystatement = File.read(File.join(root, 'fixtures', 'r5_capabilitystatement.json')) + stub_request(:get, /autodetect/).to_return(body: capabilitystatement) + client = FHIR::Client.new('autodetect') + # Intentionally set the client incorrectly + client.default_xml + client.use_r4 + assert client.cached_capability_statement.nil? + assert client.detect_version == :r5, "Expected Version to be r5, but found #{client.detect_version.to_s}" + assert !client.cached_capability_statement.nil?, 'Expected Capability Statement to be cached' + assert client.cached_capability_statement.is_a?(FHIR::R5::CapabilityStatement) + assert client.default_format.include? 'json' + end + def test_stu3_patient_manual stub_request(:get, /stu3/).to_return(body: FHIR::STU3::Patient.new.to_json) client = FHIR::Client.new('stu3') @@ -156,7 +186,7 @@ def test_r4b_reply_fhir_version client.use_r4b FHIR::R4B::Model.client = client patient = FHIR::R4B::Patient.read('foo') - assert_equal :r4, client.reply.fhir_version + assert_equal :r4b, client.reply.fhir_version end def test_r5_reply_fhir_version