class Mirah::Client
A client designed to communicate with the Mirah
system in a constrained set of well defined ways. This is a front to the more general Graphql
backend which is available.
Patient Methods¶ ↑
-
{find_patient}
-
{find_patient_by_external_id}
-
{query_patients}
-
{push_patient}
Organization Methods¶ ↑
-
{find_organization}
-
{find_organization_by_external_id}
-
{query_organizations}
-
{push_organization}
Practitioner Methods¶ ↑
-
{find_practitioner}
-
{find_practitioner_by_external_id}
-
{query_practitioners}
-
{push_practitioner}
Appointment Methods¶ ↑
-
{find_appointment}
-
{find_appointment_by_external_id}
-
{query_appointments}
-
{push_appointment}
@example
# Create a new client client = Mirah::Client.new(host: 'https://api.mirah.com', user_id: 'my_user_id', access_token: 'my_token') # find a patient client.find_patient_by_external_id('mrn0001')
Attributes
Access to the underlying graphql client. You may use this for advanced queries that are not provided as part of the standard library.
Public Class Methods
Construct a new Client
with the given host and credentials. @param host [String] The host, e.g. 'api.mirah.com' @param user_id [String] Your user id @param access_token [String] Your secret API token.
# File lib/mirah/client.rb, line 42 def initialize(host:, user_id:, access_token:) @client = Graphql.create_client(host: host) @client_context = { user_id: user_id, access_token: access_token } end
Public Instance Methods
Find an appointment by the given Mirah
internal UUID. This method should be used if you already know the Mirah
identifier. If you wish to query by your own system identifier, you should use {#find_appointment_by_external_id}
@since 0.1.0 @param id [String] Mirah
UUID for the appointment @return [Data::Appointment, nil] the appointment, or nil if the record does not exist.
# File lib/mirah/client.rb, line 248 def find_appointment(id) query_record(Graphql::Queries::AppointmentIdQuery, id, Data::Appointment, 'appointment') end
Find an appointment by your external id. This is a convenience method. If you wish to query a list of appointments by external id, please use {Client#query_appointments}.
@since 0.1.0 @param external_id [String] The identifier of the system of record @return [Data::Appointment, nil] the appointment, or nil if the record does not exist.
# File lib/mirah/client.rb, line 258 def find_appointment_by_external_id(external_id) query_record_by_external_id(Graphql::Queries::AppointmentExternalIdQuery, external_id, Data::Appointment, 'appointmentExternal') end
Find an organization by the given Mirah
internal UUID. This method should be used if you already know the Mirah
identifier. If you wish to query by your own system identifier, you should use {#find_organization_by_external_id}
@since 0.1.0 @param id [String] Mirah
UUID for the organization @return [Data::Organization, nil] the organization, or nil if the record does not exist.
# File lib/mirah/client.rb, line 125 def find_organization(id) query_record(Graphql::Queries::OrganizationIdQuery, id, Data::Organization, 'organization') end
Find an organization by your external id. This is a convenience method. If you wish to query a list of organizations by external id, please use {Client#query_organizations}.
@since 0.1.0 @param external_id [String] The identifier of the system of record @return [Data::Organization, nil] the organization, or nil if the record does not exist.
# File lib/mirah/client.rb, line 135 def find_organization_by_external_id(external_id) query_record_by_external_id(Graphql::Queries::OrganizationExternalIdQuery, external_id, Data::Organization, 'organizationExternal') end
Find a patient by the given Mirah
internal UUID. This method should be used if you already know the Mirah
identifier. If you wish to query by your own system identifier, you should use {#find_patient_by_external_id}
@since 0.1.0 @param id [String] Mirah
UUID for the patient @return [Data::Patient, nil] the patient, or nil if the record does not exist.
# File lib/mirah/client.rb, line 61 def find_patient(id) query_record(Graphql::Queries::PatientIdQuery, id, Data::Patient, 'patient') end
Find a patient by your external id. This is a convenience method. If you wish to query a list of patients by external id, please use {Client#query_patients}.
@since 0.1.0 @param external_id [String] The identifier of the system of record @return [Data::Patient, nil] the patient, or nil if the record does not exist.
# File lib/mirah/client.rb, line 71 def find_patient_by_external_id(external_id) query_record_by_external_id(Graphql::Queries::PatientExternalIdQuery, external_id, Data::Patient, 'patientExternal') end
Find an practitioner by the given Mirah
internal UUID. This method should be used if you already know the Mirah
identifier. If you wish to query by your own system identifier, you should use {#find_practitioner_by_external_id}
@since 0.1.0 @param id [String] Mirah
UUID for the practitioner @return [Data::Practitioner, nil] the practitioner, or nil if the record does not exist.
# File lib/mirah/client.rb, line 183 def find_practitioner(id) query_record(Graphql::Queries::PractitionerIdQuery, id, Data::Practitioner, 'practitioner') end
Find an practitioner by your external id. This is a convenience method. If you wish to query a list of practitioners by external id, please use {Client#query_practitioners}.
@since 0.1.0 @param external_id [String] The identifier of the system of record @return [Data::Practitioner, nil] the practitioner, or nil if the record does not exist.
# File lib/mirah/client.rb, line 193 def find_practitioner_by_external_id(external_id) query_record_by_external_id(Graphql::Queries::PractitionerExternalIdQuery, external_id, Data::Practitioner, 'practitionerExternal') end
Create or update an appointment. You must specify an external identifier, all other parameters are optional, but you may receive errors if you attempt to specify too few parameters for an appointment that does not exist.
@since 0.1.0 @param external_id [String] the external identifier for this appointment @param status [String] the status identifier of this appointment, see {Data::Appointment#status} @option input_values [String, nil] :start_date see {Data::Appointment#start_date} @option input_values [String, nil] :end_date see {Data::Appointment#end_date} @option input_values [String, nil] :minutes_duration see {Data::Appointment#minutes_duration} @option input_values [String, nil] :patient_id see {Data::Appointment#patient_id} @option input_values [String, nil] :external_patient_id see {Data::Appointment#external_patient_id} @option input_values [String, nil] :practitioner_id see {Data::Appointment#practitioner_id} @option input_values [String, nil] :external_practitioner_id see {Data::Appointment#external_practitioner_id} @option input_values [String, nil] :organization_id see {Data::Appointment#organization_id} @option input_values [String, nil] :external_organization_id see {Data::Appointment#external_organization_id} @return [PushResult<Data::Appointment>] the operation result with the appointment on success
# File lib/mirah/client.rb, line 298 def push_appointment(external_id:, status:, **input_values) mutate(Graphql::Mutations::CreateOrUpdateAppointmentMutation, Inputs::AppointmentInput.new(input_values.merge(external_id: external_id, status: status)), Data::Appointment, 'createOrUpdateAppointment') end
Create or update an organization. You must specify an external identifier, all other parameters are optional, but you may receive errors if you attempt to specify too few parameters for an organization that does not exist.
@since 0.1.0 @param external_id [String] the external identifier for this organization @option input_values [String, nil] :name see {Data::Organization#name} @option input_values [String, nil] :external_part_of_id The external identifier for the parent organization @return [PushResult<Data::Organization>] the operation result with the organization on success
# File lib/mirah/client.rb, line 167 def push_organization(external_id:, **input_values) mutate(Graphql::Mutations::CreateOrUpdateOrganizationMutation, Inputs::OrganizationInput.new(input_values.merge(external_id: external_id)), Data::Organization, 'createOrUpdateOrganization') end
Create or update a patient. You must specify an external identifier, all other parameters are optional, but you may receive errors if you attempt to specify too few parameters for a patient that does not exist.
@since 0.1.0 @param external_id [String] the external identifier for this patient @option input_values [String, nil] :given_name see {Data::Patient#given_name} @option input_values [String, nil] :family_name see {Data::Patient#family_name} @option input_values [Date, nil] :birth_date see {Data::Patient#birth_date} @option input_values [String, nil] :gender see {Data::Patient#gender} @option input_values [String, nil] :primary_language see {Data::Patient#primary_language} @option input_values [String, nil] :email see {Data::Patient#email} @option input_values [String, nil] :phone_number see {Data::Patient#phone_number} @option input_values [String, nil] :external_managing_organization_id see {Data::Patient#external_managing_organization_id} @return [PushResult<Data::Patient>] the operation result with a patient on success
# File lib/mirah/client.rb, line 109 def push_patient(external_id:, **input_values) mutate(Graphql::Mutations::CreateOrUpdatePatientMutation, Inputs::PatientInput.new(input_values.merge(external_id: external_id)), Data::Patient, 'createOrUpdatePatient') end
Create or update an practitioner. You must specify an external identifier, all other parameters are optional, but you may receive errors if you attempt to specify too few parameters for an practitioner that does not exist.
@since 0.1.0 @param external_id [String] the external identifier for this practitioner @option input_values [String, nil] :given_name see {Data::Practitioner#given_name} @option input_values [String, nil] :family_name see {Data::Practitioner#family_name} @option input_values [String, nil] :title see {Data::Practitioner#title} @option input_values [String, nil] :suffix see {Data::Practitioner#suffix} @option input_values [String, nil] :email see {Data::Practitioner#email} @option input_values [String, nil] :default_practitioner_role see {Data::Practitioner#default_practitioner_role} @option input_values [String, nil] :sso_username see {Data::Practitioner#sso_username} @option input_values [Array<String>, nil] :external_organization_ids see
{Data::Practitioner#external_organization_ids}
@return [PushResult<Data::Practitioner>] the operation result with the practitioner on success
# File lib/mirah/client.rb, line 232 def push_practitioner(external_id:, **input_values) mutate(Graphql::Mutations::CreateOrUpdatePractitionerMutation, Inputs::PractitionerInput.new(input_values.merge(external_id: external_id)), Data::Practitioner, 'createOrUpdatePractitioner') end
@since 0.1.0 @param external_id [Array<String>] See {Mirah::Filters::AppointmentFilters#external_id} @param status [String] See {Mirah::Filters::AppointmentFilters#external_id} @return [Collection<Data::Appointment>] a collection of pageable appointments.
# File lib/mirah/client.rb, line 272 def query_appointments(external_id: nil, status: nil) query_connection( Graphql::Queries::AppointmentQuery, Filters::AppointmentFilters.new(external_id: external_id, status: status), Filters::Paging.default, Data::Appointment, 'appointments' ) end
This is technically a public method so that collections can get the next page, but should not generally be invoked directly otherwise. @private
# File lib/mirah/client.rb, line 311 def query_connection(query, input, paging, data_klass, path) variables = input.to_graphql_hash.merge(paging.to_graphql_hash) response = client.query(query, variables: variables, context: client_context) check_response_for_errors(response) response_json = response.to_h results = parse_graphql_connection_response(response_json, data_klass, path, 'nodes') page_info = parse_page_info(response_json, path) # Used to generate subsequent pages query_details = { query: query, input: input, paging: paging, data_klass: data_klass, path: path } Collection.new(results: results, page_info: page_info, client: self, query: query_details) rescue StandardError => e handle_errors(e) end
@since 0.1.0 @param external_id [Array<String>] See {Mirah::Filters::OrganizationFilters#external_id} @param search [String] See {Mirah::Filters::OrganizationFilters#search} @return [Collection<Data::Organization>] a collection of pageable organizations.
# File lib/mirah/client.rb, line 149 def query_organizations(external_id: nil, search: nil) query_connection( Graphql::Queries::OrganizationQuery, Filters::OrganizationFilters.new(external_id: external_id, search: search), Filters::Paging.default, Data::Organization, 'organizations' ) end
Query for patients. You may specify a set of parameters as defined in {Mirah::Filters::PatientFilters}. Results are returned in a paginated format. See {Collection} for how to page results.
@since 0.1.0 @param external_id [Array<String>] See {Mirah::Filters::PatientFilters#external_id} @param search [String] See {Mirah::Filters::PatientFilters#search} @return [Collection<Data::Patient>] a collection of pageable patients.
# File lib/mirah/client.rb, line 85 def query_patients(external_id: nil, search: nil) query_connection( Graphql::Queries::PatientQuery, Filters::PatientFilters.new(external_id: external_id, search: search), Filters::Paging.default, Data::Patient, 'patients' ) end
Query for practitioners. You may specify a set of parameters as defined in {Mirah::Filters::PractitionerFilters}. Results are returned in a paginated format. See {Collection} for how to page results.
@since 0.1.0 @param external_id [String] See {Mirah::Filters::PractitionerFilters#external_id} @param search [String] See {Mirah::Filters::PractitionerFilters#search} @return [Collection<Data::Practitioner>] a collection of pageable practitioners.
# File lib/mirah/client.rb, line 207 def query_practitioners(external_id: nil, search: nil) query_connection( Graphql::Queries::PractitionerQuery, Filters::PractitionerFilters.new(external_id: external_id, search: search), Filters::Paging.default, Data::Practitioner, 'practitioners' ) end
Private Instance Methods
# File lib/mirah/client.rb, line 409 def check_response_for_errors(response) if response.errors.any? if response.errors[:data] == ['401 Unauthorized'] # rubocop:disable Style/GuardClause raise Errors::InvalidCredentials, 'The credentials you have supplied are invalid' else raise Errors::ServerError, 'Unknown error from Mirah server: ' + response.errors.values.flatten.join(',') end end raise Errors::ServerError, 'Data payload was empty' unless response.data end
Check that any errors raised have been wrapped in Mirah
errors appropriately.
# File lib/mirah/client.rb, line 400 def handle_errors(e) case e when Error raise else raise Errors::ClientError, e end end
# File lib/mirah/client.rb, line 351 def mutate(mutation, input, data_klass, path) input.validate! response = client.query(mutation, variables: { input: input.to_graphql_hash }, context: client_context) response_json = response.to_h.dig('data', path) if response_json result = data_klass.from_graphql_hash(response_json['result']) if response_json['result'] status = response_json['status'] errors = response_json['errors'] else status = 'ERROR' errors = response.to_h['errors'] end PushResult.new(result: result, status: status, errors: errors, input: input) rescue StandardError => e handle_errors(e) end
Parse the main part of the graphql response into the appropriate data class with additional paging and connection information.
@param response_json [GraphQL::Client::Response] the graphql error response @param data_klass [Class] the class to transform the response into @param path [String] the path in the response to look for the raw data @return [Collection<Class>] a wrapped collection with the results
# File lib/mirah/client.rb, line 393 def parse_graphql_connection_response(response_json, data_klass, path, item = 'nodes') response_json.dig('data', path, item)&.map do |datum| data_klass.from_graphql_hash(datum.to_h) end end
Parse the main part of the graphql response into the appropriate data class.
@param response_json [GraphQL::Client::Response] the graphql error response @param data_klass [Class] the class to transform the response into @param path [String] the path in the response to look for the raw data @return [Class] an item of the type of `data_klass`
# File lib/mirah/client.rb, line 378 def parse_graphql_response(response_json, data_klass, path) data_klass.from_graphql_hash(response_json.dig('data', path)) end
# File lib/mirah/client.rb, line 382 def parse_page_info(response_json, path) Data::PageInfo.from_graphql_hash(response_json.dig('data', path, 'pageInfo')) end
# File lib/mirah/client.rb, line 331 def query_record(query, id, data_klass, path) response = client.query(query, variables: { id: id }, context: client_context) check_response_for_errors(response) response_json = response.to_h parse_graphql_response(response_json, data_klass, path) rescue StandardError => e handle_errors(e) end
# File lib/mirah/client.rb, line 341 def query_record_by_external_id(query, external_id, data_klass, path) response = client.query(query, variables: { externalId: external_id }, context: client_context) check_response_for_errors(response) response_json = response.to_h parse_graphql_response(response_json, data_klass, path) rescue StandardError => e handle_errors(e) end