fhir_client 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,118 @@
1
+ module FHIR
2
+ module Sections
3
+ module Operations
4
+
5
+ # DSTU 2 Operations: http://hl7.org/implement/standards/FHIR-Develop/operations.html
6
+
7
+ # Concept Translation [base]/ConceptMap/$translate | [base]/ConceptMap/[id]/$translate
8
+
9
+ # Closure Table Maintenance [base]/$closure
10
+
11
+ # Fetch Patient Record [base]/Patient/$everything | [base]/Patient/[id]/$everything
12
+ # http://hl7.org/implement/standards/FHIR-Develop/patient-operations.html#everything
13
+ # Fetches resources for a given patient record, scoped by a start and end time, and returns a Bundle of results
14
+ def fetch_patient_record(id=nil, startTime=nil, endTime=nil, method='GET', format=@default_format)
15
+ fetch_record(id,startTime,endTime,method,FHIR::Patient,format)
16
+ end
17
+
18
+ def fetch_encounter_record(id=nil, method='GET', format=@default_format)
19
+ fetch_record(id,nil,nil,method,FHIR::Encounter,format)
20
+ end
21
+
22
+ def fetch_record(id=nil, startTime=nil, endTime=nil, method='GET', klass=FHIR::Patient, format=@default_format)
23
+ options = { resource: klass, format: format, operation: { name: :fetch_patient_record, method: method } }
24
+ options.deep_merge!({id: id}) if !id.nil?
25
+ options[:operation][:parameters] = {} if options[:operation][:parameters].nil?
26
+ options[:operation][:parameters].merge!({start: { type: 'Date', value: startTime}}) if !startTime.nil?
27
+ options[:operation][:parameters].merge!({end: { type: 'Date', value:endTime}}) if !endTime.nil?
28
+
29
+ if options[:operation][:method]=='GET'
30
+ reply = get resource_url(options), fhir_headers(options)
31
+ else
32
+ # create Parameters body
33
+ body = nil
34
+ if(options[:operation] && options[:operation][:parameters])
35
+ p = FHIR::Parameters.new
36
+ options[:operation][:parameters].each do |key,value|
37
+ parameter = FHIR::Parameters::Parameter.new.from_hash(name: key.to_s)
38
+ parameter.method("value#{value[:type]}=").call(value[:value])
39
+ p.parameter << parameter
40
+ end
41
+ body = p.to_xml
42
+ end
43
+ reply = post resource_url(options), p, fhir_headers(options)
44
+ end
45
+
46
+ reply.resource = parse_reply(FHIR::Bundle, format, reply)
47
+ reply.resource_class = options[:resource]
48
+ reply
49
+ end
50
+
51
+ # Build Questionnaire [base]/Profile/$questionnaire | [base]/Profile/[id]/$questionnaire
52
+
53
+ # Populate Questionnaire [base]/Questionnaire/$populate | [base]/Questionnaire/[id]/$populate
54
+
55
+ # Value Set Expansion [base]/ValueSet/$expand | [base]/ValueSet/[id]/$expand
56
+ # http://hl7.org/implement/standards/FHIR-Develop/valueset-operations.html#expand
57
+ # The definition of a value set is used to create a simple collection of codes suitable for use for data entry or validation.
58
+ def value_set_expansion(params={}, format=@default_format)
59
+ options = { resource: FHIR::ValueSet, operation: { name: :value_set_expansion } }
60
+ options.deep_merge!(params)
61
+ terminology_operation(options, format)
62
+ end
63
+
64
+ # Value Set based Validation [base]/ValueSet/$validate | [base]/ValueSet/[id]/$validate
65
+ # http://hl7.org/implement/standards/FHIR-Develop/valueset-operations.html#validate
66
+ # Validate that a coded value is in the set of codes allowed by a value set.
67
+ def value_set_code_validation(params={}, format=@default_format)
68
+ options = { resource: FHIR::ValueSet, operation: { name: :value_set_based_validation } }
69
+ options.deep_merge!(params)
70
+ terminology_operation(options, format)
71
+ end
72
+
73
+ # Concept Look Up [base]/CodeSystem/$lookup
74
+ def code_system_lookup(params={}, format=@default_format)
75
+ options = { resource: FHIR::CodeSystem, operation: { name: :code_system_lookup } }
76
+ options.deep_merge!(params)
77
+ terminology_operation(options, format)
78
+ end
79
+
80
+ #
81
+ def concept_map_translate(params={}, format=@default_format)
82
+ options = { resource: FHIR::ConceptMap, operation: { name: :concept_map_translate } }
83
+ options.deep_merge!(params)
84
+ terminology_operation(options, format)
85
+ end
86
+
87
+ def terminology_operation(params={}, format=@default_format)
88
+ options = { format: format }
89
+ # params = [id, code, system, version, display, coding, codeableConcept, date, abstract]
90
+ options.deep_merge!(params)
91
+
92
+ if options[:operation][:method]=='GET'
93
+ reply = get resource_url(options), fhir_headers(options)
94
+ else
95
+ # create Parameters body
96
+ body = nil
97
+ if(options[:operation] && options[:operation][:parameters])
98
+ p = FHIR::Parameters.new
99
+ options[:operation][:parameters].each do |key,value|
100
+ parameter = FHIR::Parameters::Parameter.new.from_hash(name: key.to_s)
101
+ parameter.method("value#{value[:type]}=").call(value[:value])
102
+ p.parameter << parameter
103
+ end
104
+ body = p.to_xml
105
+ end
106
+ reply = post resource_url(options), p, fhir_headers(options)
107
+ end
108
+
109
+ reply.resource = parse_reply(options[:resource], format, reply)
110
+ reply.resource_class = options[:resource]
111
+ reply
112
+ end
113
+
114
+ # Batch Mode Validation [base]/ValueSet/$batch
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,53 @@
1
+ module FHIR
2
+ module Sections
3
+ module Search
4
+
5
+ #
6
+ # Search a set of resources of a given type.
7
+ #
8
+ # @param klass The type of resource to be searched.
9
+ # @param options A hash of options used to construct the search query.
10
+ # @return FHIR::ClientReply
11
+ #
12
+ def search(klass, options={}, format=@default_format_bundle)
13
+ options.merge!({ resource: klass, format: format })
14
+
15
+ if options[:search] && options[:search][:flag]
16
+ reply = post resource_url(options), nil, fhir_headers(options)
17
+ else
18
+ reply = get resource_url(options), fhir_headers(options)
19
+ end
20
+ # reply = get resource_url(options), fhir_headers(options)
21
+ reply.resource = parse_reply(klass, format, reply)
22
+ reply.resource_class = klass
23
+ reply
24
+ end
25
+
26
+ def search_existing(klass, id, options={}, format=@default_format_bundle)
27
+ options.merge!({ resource: klass, id: id, format: format })
28
+ #if options[:search][:flag]
29
+ if options[:search] && options[:search][:flag]
30
+ reply = post resource_url(options), nil, fhir_headers(options)
31
+ else
32
+ reply = get resource_url(options), fhir_headers(options)
33
+ end
34
+ reply.resource = parse_reply(klass, format, reply)
35
+ reply.resource_class = klass
36
+ reply
37
+ end
38
+
39
+ def search_all(options={}, format=@default_format_bundle)
40
+ options.merge!({ format: format })
41
+ if options[:search] && options[:search][:flag]
42
+ reply = post resource_url(options), nil, fhir_headers(options)
43
+ else
44
+ reply = get resource_url(options), fhir_headers(options)
45
+ end
46
+ reply.resource = parse_reply(nil, format, reply)
47
+ reply.resource_class = nil
48
+ reply
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,64 @@
1
+ module FHIR
2
+ module Sections
3
+ module Tags
4
+ #
5
+ # Get a list of all tags on server
6
+ #
7
+ # GET [base]/_tags
8
+ #
9
+ # public List<AtomCategory> getAllTags();
10
+
11
+ #
12
+ # Get a list of all tags used for the nominated resource type
13
+ #
14
+ # GET [base]/[type]/_tags
15
+ #
16
+ # public <T extends Resource> List<AtomCategory> getAllTagsForResourceType(Class<T> resourceClass);
17
+
18
+ #
19
+ # Get a list of all tags affixed to the nominated resource. This duplicates the HTTP header entries
20
+ #
21
+ # GET [base]/[type]/[id]/_tags
22
+ #
23
+ # public <T extends Resource> List<AtomCategory> getTagsForResource(Class<T> resource, String id);
24
+
25
+ #
26
+ # Get a list of all tags affixed to the nominated version of the resource. This duplicates the HTTP header entries
27
+ #
28
+ # GET [base]/[type]/[id]/_history/[vid]/_tags
29
+ #
30
+ # public <T extends Resource> List<AtomCategory> getTagsForResourceVersion(Class<T> resource, String id, String versionId);
31
+
32
+ #
33
+ # Remove all tags in the provided list from the list of tags for the nominated resource
34
+ #
35
+ # DELETE [base]/[type]/[id]/_tags
36
+ #
37
+ # //public <T extends Resource> boolean deleteTagsForResource(Class<T> resourceClass, String id);
38
+
39
+ #
40
+ # Remove tags in the provided list from the list of tags for the nominated version of the resource
41
+ #
42
+ # DELETE [base]/[type]/[id]/_history/[vid]/_tags
43
+ #
44
+ # public <T extends Resource> List<AtomCategory> deleteTags(List<AtomCategory> tags, Class<T> resourceClass, String id, String version);
45
+
46
+ #
47
+ # Affix tags in the list to the nominated resource
48
+ #
49
+ # POST [base]/[type]/[id]/_tags
50
+ # @return
51
+ #
52
+ # public <T extends Resource> List<AtomCategory> createTags(List<AtomCategory> tags, Class<T> resourceClass, String id);
53
+
54
+ #
55
+ # Affix tags in the list to the nominated version of the resource
56
+ #
57
+ # POST [base]/[type]/[id]/_history/[vid]/_tags
58
+ #
59
+ # @return
60
+ #
61
+ # public <T extends Resource> List<AtomCategory> createTags(List<AtomCategory> tags, Class<T> resourceClass, String id, String version);
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,83 @@
1
+ module FHIR
2
+ module Sections
3
+ module Transactions
4
+
5
+ attr_accessor :transaction_bundle
6
+
7
+ def begin_transaction
8
+ @transaction_bundle = FHIR::Bundle.new
9
+ @transaction_bundle.type = 'transaction'
10
+ @transaction_bundle.entry ||= []
11
+ @transaction_bundle
12
+ end
13
+
14
+ def begin_batch
15
+ @transaction_bundle = FHIR::Bundle.new
16
+ @transaction_bundle.type = 'batch'
17
+ @transaction_bundle.entry ||= []
18
+ @transaction_bundle
19
+ end
20
+
21
+ # syntactic sugar for add_batch_request
22
+ # @param method one of ['GET','POST','PUT','DELETE']
23
+ # @param url relative path, such as 'Patient/123'. Do not include the [base]
24
+ # @param resource The resource if a POST or PUT
25
+ def add_transaction_request(method, url, resource=nil, if_none_exist=nil)
26
+ add_batch_request(method, url, resource, if_none_exist)
27
+ end
28
+
29
+ def add_batch_request(method, url, resource=nil, if_none_exist=nil)
30
+ request = FHIR::Bundle::Entry::Request.new
31
+ if FHIR::Bundle::Entry::Request::METADATA['method']['valid_codes'].values.first.include?(method.upcase)
32
+ request.local_method = method.upcase
33
+ else
34
+ request.local_method = 'POST'
35
+ end
36
+ request.ifNoneExist = if_none_exist if !if_none_exist.nil?
37
+ if url.nil? && !resource.nil?
38
+ options = Hash.new
39
+ options[:resource] = resource.class
40
+ options[:id] = resource.id if request.local_method != 'POST'
41
+ request.url = resource_url(options)
42
+ request.url = request.url[1..-1] if request.url.starts_with?('/')
43
+ else
44
+ request.url = url
45
+ end
46
+
47
+ entry = FHIR::Bundle::Entry.new
48
+ entry.resource = resource
49
+ entry.request = request
50
+
51
+ @transaction_bundle.entry << entry
52
+ entry
53
+ end
54
+
55
+ # syntactic sugar for end_batch
56
+ def end_transaction(format=@default_format)
57
+ end_batch(format)
58
+ end
59
+
60
+ # submit the batch/transaction to the server
61
+ # @param format
62
+ # @return FHIR::ClientReply
63
+ #
64
+ def end_batch(format=@default_format)
65
+ options = { format: format, 'Prefer' => 'return=representation' }
66
+ reply = post resource_url(options), @transaction_bundle, fhir_headers(options)
67
+ begin
68
+ if(format.downcase.include?('xml'))
69
+ reply.resource = FHIR::Xml.from_xml(reply.body)
70
+ else
71
+ reply.resource = FHIR::Json.from_json(reply.body)
72
+ end
73
+ rescue Exception => e
74
+ reply.resource = nil
75
+ end
76
+ reply.resource_class = reply.resource.class
77
+ reply
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,49 @@
1
+ module FHIR
2
+ module Sections
3
+ module Validate
4
+ #
5
+ # Validate resource payload.
6
+ #
7
+ # @param resourceClass
8
+ # @param resource
9
+ # @param id
10
+ # @return
11
+ #
12
+ # public <T extends Resource> AtomEntry<OperationOutcome> validate(Class<T> resourceClass, T resource, String id);
13
+ def validate(resource, options={}, format=@default_format)
14
+ options.merge!({ resource: resource.class, validate: true, format: format })
15
+ params = FHIR::Parameters.new
16
+ add_resource_parameter(params,'resource',resource)
17
+ add_parameter(params,'profile','Uri',options[:profile_uri]) if !options[:profile_uri].nil?
18
+ post resource_url(options), params, fhir_headers(options)
19
+ end
20
+
21
+ def validate_existing(resource, id, options={}, format=@default_format)
22
+ options.merge!({ resource: resource.class, id: id, validate: true, format: format })
23
+ params = FHIR::Parameters.new
24
+ add_resource_parameter(params,'resource',resource)
25
+ add_parameter(params,'profile','Uri',options[:profile_uri]) if !options[:profile_uri].nil?
26
+ post resource_url(options), params, fhir_headers(options)
27
+ end
28
+
29
+
30
+ private
31
+ def add_parameter(params,name,type,value)
32
+ params.parameter ||= []
33
+ parameter = FHIR::Parameters::Parameter.new.from_hash(name: name)
34
+ parameter.method("value#{type}=").call(value)
35
+ params.parameter << parameter
36
+ end
37
+
38
+ def add_resource_parameter(params, name,resource)
39
+ params.parameter ||= []
40
+ parameter = FHIR::Parameters::Parameter.new.from_hash(name: name)
41
+ parameter.resource = resource
42
+ params.parameter << parameter
43
+ end
44
+
45
+
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,73 @@
1
+ namespace :fhir do
2
+
3
+ desc 'console'
4
+ task :console, [] do |t, args|
5
+ binding.pry
6
+ end
7
+
8
+ #
9
+ # Prerequisites & Assumptions:
10
+ #
11
+ # 1. Running SMART-on-FHIR (DSTU2 branch) server [http://example/fhir]
12
+ # 2. Running OpenID Connect server [http://example:8080/openid-connect-server-webapp]
13
+ # 3. Configured client under OpenID Connect server:
14
+ # a. Create a system scope if necessary. SMART-on-FHIR requires 'fhir_complete' scope.
15
+ # b. Add the scope created in (a) to client.
16
+ # c. Add the FHIR server URL to the list of allowed redirect URIs (required?)
17
+ # d. Ensure client has 'client credentials' grant type
18
+ # d. Whitelist the client
19
+ # 4. 'client_id' and 'client_secret' variables are the name and secret of the client created in (3)
20
+ # 5. :authorize_url is the authorization endpoint of the OpenID connect server
21
+ # 6. :token_url is the token endpoint of the OpenID connect server
22
+ #
23
+ desc 'OAuth2 Example'
24
+ task :oauth2, [:url,:client_id,:client_secret] do |t, args|
25
+ client = FHIR::Client.new(args.url)
26
+ client_id = args.client_id
27
+ client_secret = args.client_secret
28
+ options = client.get_oauth2_metadata_from_conformance
29
+ if options.empty?
30
+ puts 'This server does not support the expected OAuth2 extensions.'
31
+ else
32
+ client.set_oauth2_auth(client_id,client_secret,options[:authorize_url],options[:token_url])
33
+ reply = client.read_feed(FHIR::Patient)
34
+ puts reply.body
35
+ end
36
+ end
37
+
38
+ desc 'count all resources for a given server'
39
+ task :count, [:url] do |t, args|
40
+ client = FHIR::Client.new(args.url)
41
+ counts = {}
42
+ fhir_resources.map do | klass |
43
+ reply = client.read_feed(klass)
44
+ counts["#{klass.name.demodulize}"] = reply.resource.total unless reply.resource.nil?
45
+ end
46
+ printf " %-30s %5s\n", 'Resource', 'Count'
47
+ printf " %-30s %5s\n", '--------', '-----'
48
+ counts.each do |key,value|
49
+ # puts "#{key} #{value}"
50
+ printf " %-30s %5s\n", key, value
51
+ end
52
+ end
53
+
54
+ desc 'delete all resources for a given server'
55
+ task :clean, [:url] do |t, args|
56
+ client = FHIR::Client.new(args.url)
57
+ fhir_resources.map do | klass |
58
+ reply = client.read_feed(klass)
59
+ while !reply.nil? && !reply.resource.nil? && reply.resource.total > 0
60
+ reply.resource.entry.each do |entry|
61
+ client.destroy(klass,entry.resource.id) unless entry.resource.nil?
62
+ end
63
+ reply = client.read_feed(klass)
64
+ end
65
+ end
66
+ Rake::Task['fhir:count'].invoke(args.url)
67
+ end
68
+
69
+ def fhir_resources
70
+ Mongoid.models.select {|c| c.name.include?('FHIR') && !c.included_modules.find_index(FHIR::Resource).nil?}
71
+ end
72
+
73
+ end