Skip to content

MHV-68149 Migration to new MHV API Gateway #21157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a6f17a8
MHV-68159 Migration to new MHV API Gateway
mmoyer-va Mar 7, 2025
d859e0c
MHV-68159 Added custom base bath
mmoyer-va Mar 18, 2025
4e7adcd
Merge branch 'master' into MHV-68159-switch-to-api-gateway
mmoyer-va Mar 18, 2025
863d026
MHV-68159 Fixes
mmoyer-va Mar 19, 2025
01d5806
MHV-68159 Corrections to paths and headers
mmoyer-va Mar 20, 2025
84d83dc
MHV-68159 More header fixes
mmoyer-va Mar 20, 2025
da89f79
Merge remote-tracking branch 'origin/master' into MHV-68159-switch-to…
mmoyer-va Mar 20, 2025
abeee7e
MHV-68159 Updated some specs/cassettes
mmoyer-va Mar 20, 2025
e14d343
MHV-68159 Spec updates
mmoyer-va Mar 20, 2025
3cd7906
MHV-68159 Updates to fix MR client_spec tests
mmoyer-va Mar 20, 2025
3d58bc3
MHV-68159 Attempting to get spec tests to pass in PR
mmoyer-va Mar 20, 2025
0b26663
MHV-68159 Spec fix
mmoyer-va Mar 20, 2025
cf5283a
MHV-68159 spec fixes
mmoyer-va Mar 20, 2025
e270e92
MHV-68159 Fixed a linter error
mmoyer-va Mar 20, 2025
7310138
MHV-68159 Converted bb client to use API Gateway
mmoyer-va Mar 21, 2025
38bd7c2
Reverting unrelated change -- will do in another PR
mmoyer-va Mar 21, 2025
0a27b43
MHV-68159 Updating tests
mmoyer-va Mar 24, 2025
7fd4eb4
MHV-68159 Fixed tests
mmoyer-va Mar 24, 2025
b963bc0
MHV-68159 Fixed tests
mmoyer-va Mar 24, 2025
680bbf5
Merge remote-tracking branch 'origin/master' into MHV-68159-switch-to…
mmoyer-va Mar 24, 2025
23a9c6d
MHV-68149 Diagnosing test errors
mmoyer-va Mar 24, 2025
1f2d990
MHV-68149 Reverting a change
mmoyer-va Mar 24, 2025
7b8a26a
MHV-68149 Updated user eligibility and spec
mmoyer-va Mar 24, 2025
d7ee7ce
Merge remote-tracking branch 'origin/master' into MHV-68159-switch-to…
mmoyer-va Mar 24, 2025
8d6722c
MHV-68149 Attempting to fix spec test
mmoyer-va Mar 24, 2025
0083bc3
MHV-68149 Fix test
mmoyer-va Mar 24, 2025
28d05d4
MHV-68149 Moving user_eligibility over fully to API Gateway
mmoyer-va Mar 25, 2025
bde8471
MHV-68159 Fixed error
mmoyer-va Mar 25, 2025
18f27a1
MHV-68149 Fixed BB code
mmoyer-va Mar 26, 2025
1c26bc7
Merge remote-tracking branch 'origin/master' into MHV-68159-switch-to…
mmoyer-va Mar 26, 2025
d7da911
MHV-68149 Roll back default config setting
mmoyer-va Mar 27, 2025
ae25857
MHV-68149 Removing unnecessary test fix
mmoyer-va Mar 27, 2025
0dd64b9
MHV-68149 Fixed images and DICOM download
mmoyer-va Mar 27, 2025
48dc9af
Merge branch 'master' into MHV-68159-switch-to-api-gateway
mmoyer-va Mar 27, 2025
5618921
Merge branch 'master' into MHV-68159-switch-to-api-gateway
mmoyer-va Mar 31, 2025
a88aed9
MHV-68149 Mock Flipper settings in specs
mmoyer-va Mar 31, 2025
2fd7110
MHV-68159 Move functionality to before(:each) to allow mocking
mmoyer-va Mar 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/features.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,10 @@ features:
actor_type: user
description: Show/hide content related to Vitals in Medical Records
enable_in_development: true
mhv_medical_records_migrate_to_api_gateway:
actor_type: user
description: Enables the switch to the new MHV API Gateway endpoints
enable_in_development: true
mhv_medical_records_phr_refresh_on_login:
actor_type: user
description: Enables/disables the PHR refresh for MHV users when logging into VA.gov
Expand Down
78 changes: 71 additions & 7 deletions lib/bb/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class Client < Common::Client::Base

CACHE_TTL = 3600 * 3 # cache for 3 hours

LEGACY_BASE_PATH = "#{Settings.mhv.rx.host}/mhv-api/patient/".freeze
APIGW_BASE_PATH = "#{Settings.mhv.api_gateway.hosts.bluebutton}/".freeze
APIGW_AUTH_BASE_PATH = "#{Settings.mhv.api_gateway.hosts.usermgmt}/".freeze

##
# PHR (Personal Health Record) refresh
#
Expand All @@ -29,7 +33,14 @@ class Client < Common::Client::Base
# @return [Common::Collection]
#
def get_extract_status
json = perform(:get, 'bluebutton/extractstatus', nil, token_headers).body
if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
BB::Configuration.custom_base_path = APIGW_BASE_PATH
json = perform(:get, 'v1/bluebutton/ess/extractstatus', nil, token_headers).body
else
BB::Configuration.custom_base_path = LEGACY_BASE_PATH
json = perform(:get, 'v1/bluebutton/extractstatus', nil, token_headers).body
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think that the v1 isn't necessary here because it's not used currently. Is it intentionally added here and throughout the rest of the file in the disabled flipper scenarios?

Suggested change
json = perform(:get, 'v1/bluebutton/extractstatus', nil, token_headers).body
json = perform(:get, 'bluebutton/extractstatus', nil, token_headers).body

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rmtolmach both the current MHV endpoints and the new API Gateway endpoints contain the v1 pattern, although there are other differences in the path. I have tested all the endpoints (against staging) with the flag on and off to ensure that we are successfully hitting the correct resources in both scenarios.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you've tested it and it works, that sounds good.

end

log_refresh_errors(json[:data]) if refresh_final?(json[:data])
Common::Collection.new(ExtractStatus, **json)
end
Expand All @@ -41,7 +52,13 @@ def get_extract_status
#
def get_eligible_data_classes
Common::Collection.fetch(::EligibleDataClass, cache_key: cache_key('geteligibledataclass'), ttl: CACHE_TTL) do
perform(:get, 'bluebutton/geteligibledataclass', nil, token_headers).body
if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
BB::Configuration.custom_base_path = APIGW_BASE_PATH
perform(:get, 'v1/bluebutton/ess/geteligibledataclass', nil, token_headers).body
else
BB::Configuration.custom_base_path = LEGACY_BASE_PATH
perform(:get, 'v1/bluebutton/geteligibledataclass', nil, token_headers).body
end
end
end

Expand All @@ -58,7 +75,13 @@ def post_generate(params)
form = BB::GenerateReportRequestForm.new(self, params)
raise Common::Exceptions::ValidationErrors, form unless form.valid?

perform(:post, 'bluebutton/generate', form.params, token_headers).body
if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
BB::Configuration.custom_base_path = APIGW_BASE_PATH
perform(:post, 'v1/bluebutton/ess/generate', form.params, token_headers).body
else
BB::Configuration.custom_base_path = LEGACY_BASE_PATH
perform(:post, 'v1/bluebutton/generate', form.params, token_headers).body
end
end

##
Expand All @@ -75,15 +98,23 @@ def get_download_report(doctype, header_callback, yielder)
# TODO: For testing purposes, use one of the following static URIs:
# uri = URI("#{Settings.mhv.rx.host}/vetsgov/1mb.file")
# uri = URI("#{Settings.mhv.rx.host}/vetsgov/90mb.file")
uri = URI.join(config.base_path, "bluebutton/bbreport/#{doctype}")
if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
BB::Configuration.custom_base_path = APIGW_BASE_PATH
uri = URI.join(config.base_path, "v1/bluebutton/ess/bbreport/#{doctype}")
else
BB::Configuration.custom_base_path = LEGACY_BASE_PATH
uri = URI.join(config.base_path, "v1/bluebutton/bbreport/#{doctype}")
end

streaming_get(uri, token_headers, header_callback, yielder)
end

##
# Opt user in to VHIE sharing.
#
def post_opt_in
perform(:post, 'bluebutton/external/optinout/optin', nil, token_headers).body
BB::Configuration.custom_base_path = get_base_path
perform(:post, 'v1/bluebutton/external/optinout/optin', nil, token_headers).body
rescue ServiceException => e
# Ignore the error that the user is already opted in to VHIE sharing.
raise unless e.message.include? 'already.opted.in'
Expand All @@ -93,7 +124,8 @@ def post_opt_in
# Opt user out of VHIE sharing.
#
def post_opt_out
perform(:post, 'bluebutton/external/optinout/optout', nil, token_headers).body
BB::Configuration.custom_base_path = get_base_path
perform(:post, 'v1/bluebutton/external/optinout/optout', nil, token_headers).body
rescue ServiceException => e
# Ignore the error that the user is already opted out of VHIE sharing.
raise unless e.message.include? 'Opt-out consent policy is already set'
Expand All @@ -105,11 +137,43 @@ def post_opt_out
# @return [Hash] an object containing the body of the response
#
def get_status
perform(:get, 'bluebutton/external/optinout/status', nil, token_headers).body
BB::Configuration.custom_base_path = get_base_path
perform(:get, 'v1/bluebutton/external/optinout/status', nil, token_headers).body
end

private

def get_base_path
if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
APIGW_BASE_PATH
else
LEGACY_BASE_PATH
end
end

def token_headers
super.merge('x-api-key' => config.x_api_key)
end

def auth_headers
super.merge('x-api-key' => config.x_api_key)
end

def get_session_tagged
Sentry.set_tags(error: 'mhv_session')

if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
BB::Configuration.custom_base_path = APIGW_BASE_PATH
env = perform(:get, 'v1/usermgmt/auth/session', nil, auth_headers)
else
BB::Configuration.custom_base_path = LEGACY_BASE_PATH
env = perform(:get, '/mhv-api/patient/v1/session', nil, auth_headers)
end

Sentry.get_current_scope.tags.delete(:error)
env
end

def cache_key(action)
return nil unless config.caching_enabled?
return nil if session.user_id.blank?
Expand Down
22 changes: 21 additions & 1 deletion lib/bb/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,38 @@ module BB
# HTTP client configuration for {BB::Client}, sets the token, base path and a service name for breakers and metrics
#
class Configuration < Common::Client::Configuration::REST
##
# Setter for thread-local variable custom_base_path
#
def self.custom_base_path=(value)
Thread.current[:custom_base_path] = value
end

##
# Getter for thread-local variable custom_base_path
#
def self.custom_base_path
Thread.current[:custom_base_path]
end

##
# @return [String] Client token set in `settings.yml` via credstash
#
def app_token
Settings.mhv.rx.app_token
end

def x_api_key
Settings.mhv.medical_records.x_api_key
end

##
# @return [String] Base path for dependent URLs
#
def base_path
"#{Settings.mhv.rx.host}/mhv-api/patient/v1/"
# We can't use Flipper in this class due to a race condition with Breakers. So we will set
# the path in the client and use a thread-local variable here.
self.class.custom_base_path || "#{Settings.mhv.rx.host}/mhv-api/patient/v1/"
end

##
Expand Down
15 changes: 13 additions & 2 deletions lib/common/client/concerns/mhv_jwt_session_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ def get_session

def get_jwt_from_headers(res_headers)
# Get the JWT token from the headers
auth_header = res_headers['authorization']
auth_header = if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
res_headers['x-amzn-remapped-authorization']
else
res_headers['authorization']
end
if auth_header.nil? || !auth_header.start_with?('Bearer ')
raise Common::Exceptions::Unauthorized, detail: 'Invalid or missing authorization header'
end
Expand Down Expand Up @@ -78,7 +82,11 @@ def validate_session_params

def get_session_tagged
Sentry.set_tags(error: 'mhv_session')
env = perform(:post, '/mhvapi/security/v1/login', auth_body, auth_headers)
env = if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
perform(:post, '/v1/security/login', auth_body, auth_headers)
else
perform(:post, '/mhvapi/security/v1/login', auth_body, auth_headers)
end
Sentry.get_current_scope.tags.delete(:error)
env
end
Expand All @@ -93,6 +101,9 @@ def patient_fhir_id

def auth_headers
config.base_request_headers.merge('Content-Type' => 'application/json')
if Flipper.enabled?(:mhv_medical_records_migrate_to_api_gateway)
config.base_request_headers.merge('x-api-key' => Settings.mhv.medical_records.x_api_key)
end
end

def auth_body
Expand Down
Loading
Loading