Skip to content

Commit

Permalink
Facilities API v2 config, model, and services (#16463)
Browse files Browse the repository at this point in the history
* Add v2 routes for Facilities API

* Add Facilities API v2 model

* Add Facilities API v2 config and services

* Fix codeowners and linting issues

* Linting fixes

* Fix linting

* More linting fixes
  • Loading branch information
khenson-oddball committed Apr 26, 2024
1 parent 9a50e72 commit d4c5192
Show file tree
Hide file tree
Showing 12 changed files with 1,027 additions and 3 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Expand Up @@ -1884,6 +1884,7 @@ spec/support/vcr_cassettes/lighthouse/benefits_intake/200_lighthouse_intake_bulk
spec/support/vcr_cassettes/lighthouse/benefits_intake/200_lighthouse_intake_bulk_status_report_success.yml @department-of-veterans-affairs/platform-va-product-forms @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
spec/support/vcr_cassettes/lighthouse/claims/200_response.yml @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/dbex-trex
spec/support/vcr_cassettes/lighthouse/direct_deposit @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/dbex-trex @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
spec/support/vcr_cassettes/lighthouse/facilities_401.yml @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/vfs-facilities-frontend
spec/support/vcr_cassettes/lighthouse/veteran_verification @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/dbex-trex @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
spec/support/vcr_cassettes/mail_automation @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
spec/support/vcr_cassettes/map @department-of-veterans-affairs/octo-identity
Expand Down
11 changes: 11 additions & 0 deletions config/initializers/statsd.rb
Expand Up @@ -96,6 +96,17 @@
StatsD.measure('facilities.lighthouse', duration, tags: ['facilities.lighthouse'])
end

ActiveSupport::Notifications.subscribe(
'lighthouse.facilities.v2.request.faraday'
) do |_, start_time, end_time, _, payload|
payload_statuses = ["http_status:#{payload.status}"]
StatsD.increment('facilities.lighthouse.v2.response.failures', tags: payload_statuses) unless payload.success?
StatsD.increment('facilities.lighthouse.v2.response.total', tags: payload_statuses)

duration = end_time - start_time
StatsD.measure('facilities.lighthouse.v2', duration, tags: ['facilities.lighthouse'])
end

# IAM SSOe session metrics
StatsD.set('iam_ssoe_oauth.users', 0)

Expand Down
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require 'common/models/base'

module FacilitiesApi
class V2::Lighthouse::Facility < Common::Base
include ActiveModel::Serializers::JSON

attribute :access, Object
attribute :active_status, String
attribute :address, Object
attribute :classification, String
attribute :detailed_services, Object
attribute :distance, Float
attribute :facility_type, String
attribute :facility_type_prefix, String
attribute :feedback, Object
attribute :hours, Object
attribute :id, String
attribute :lat, Float
attribute :long, Float
attribute :mobile, Boolean
attribute :name, String
attribute :operating_status, Object
attribute :operational_hours_special_instructions, String
attribute :parent, Object
attribute :phone, Object
attribute :services, Object
attribute :time_zone, String
attribute :type, String
attribute :unique_id, String
attribute :visn, String
attribute :website, String
attribute :tmp_covid_online_scheduling, Boolean

def initialize(fac)
super(fac)
set_attributes(fac)

self.id = fac['id']
self.access = fac['attributes']['wait_times']
self.facility_type_prefix, self.unique_id = fac['id'].split('_')
self.feedback = fac['attributes']['satisfaction']
self.type = fac['type']
end

private

def set_attributes(fac)
fac['attributes'].each_key do |key|
self[key.underscore] = fac['attributes'][key] if attributes.include?(key.underscore.to_sym)
end
end
end
end
@@ -0,0 +1,56 @@
# frozen_string_literal: true

require 'common/client/base'
require_relative 'response'
require_relative 'configuration'

module FacilitiesApi
module V2
module Lighthouse
# Documentation located at:
# https://developer.va.gov/explore/api/va-facilities/docs
class Client < Common::Client::Base
configuration V2::Lighthouse::Configuration

##
# Request a single facility
# @param id [String] the id of the facility created by combining the type of facility and station number
# @example client.get_by_id(vha_358)
# @return [V2::Lighthouse::Facility]
#
def get_by_id(id)
response = perform(:get, "/services/va_facilities/v1/facilities/#{id}", nil)
V2::Lighthouse::Response.new(response.body, response.status).facility
end

##
# Request a list of all facilities or only facilities matching the params provided
# @param params [Hash] a hash of parameter objects
# see https://developer.va.gov/explore/api/va-facilities/docs for more options
# @example client.get_facilities(bbox: [60.99, 10.54, 180.00, 20.55])
# @example client.get_facilities(facilityIds: 'vha_358,vba_358')
# @example client.get_facilities(lat: 10.54, long: 180.00, per_page: 50, page: 2)
# @return [Array<V2::Lighthouse::Facility>]
#
def get_facilities(params)
filtered_params = params.slice(:facilityIds, :mobile, :page, :per_page, :services, :type, :visn)

if params.key?(:bbox)
filtered_params.merge!(params.slice(:bbox))
elsif params.key?(:lat) && params.key?(:long)
filtered_params.merge!(params.slice(:lat, :long, :radius))
elsif params.key?(:state)
filtered_params.merge!(params.slice(:state))
elsif params.key?(:zip)
filtered_params.merge!(params.slice(:zip))
elsif params.key?(:facilityIds)
filtered_params.merge!(params.slice(:facilityIds))
end

response = perform(:get, '/services/va_facilities/v1/facilities', filtered_params)
V2::Lighthouse::Response.new(response.body, response.status).facilities
end
end
end
end
end
@@ -0,0 +1,41 @@
# frozen_string_literal: true

require 'common/client/configuration/rest'
require 'common/client/middleware/response/raise_error'
require_relative 'middleware/errors'

module FacilitiesApi
module V2
module Lighthouse
class Configuration < Common::Client::Configuration::REST
def base_path
Settings.lighthouse.facilities.url
end

def service_name
'Lighthouse_Facilities'
end

def self.base_request_headers
super.merge('apiKey' => Settings.lighthouse.facilities.api_key)
end

def connection
Faraday.new(base_path, headers: base_request_headers, request: request_options) do |conn|
conn.use :breakers
conn.request :instrumentation, name: 'lighthouse.facilities.v2.request.faraday'

# Uncomment this if you want curl command equivalent or response output to log
# conn.request(:curl, ::Logger.new(STDOUT), :warn) unless Rails.env.production?
# conn.response(:logger, ::Logger.new(STDOUT), bodies: true) unless Rails.env.production?

conn.response :raise_error, error_prefix: service_name
conn.response :lighthouse_facilities_errors

conn.adapter Faraday.default_adapter
end
end
end
end
end
end
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module FacilitiesApi
module V2
module Lighthouse
module Middleware
class Errors < Faraday::Middleware
def on_complete(env)
return if env.success?

env.body = parse_body(env)
end

private

def parse_body(env)
body = JSON.parse(env.body)
message = body['message']

body['detail'] = message
body['code'] = env.status
body['source'] = 'Lighthouse Facilities'

body
end
end
end
end
end
end
Faraday::Response.register_middleware lighthouse_facilities_errors: FacilitiesApi::V2::Lighthouse::Middleware::Errors
@@ -0,0 +1,60 @@
# frozen_string_literal: true

require 'common/models/base'

module FacilitiesApi
module V2
module Lighthouse
class Response < Common::Base
attribute :body, String
attribute :current_page, Integer
attribute :data, Object
attribute :links, Object
attribute :meta, Object
attribute :per_page, Integer
attribute :status, Integer
attribute :total_entries, Integer

def initialize(body, status)
super()
self.body = body
self.status = status
parsed_body = JSON.parse(body)
self.data = parsed_body['data']
self.meta = parsed_body['meta']
self.links = parsed_body['links']
set_metadata(meta) if meta
end

def facilities
facilities = data.each_with_index.map do |facility, index|
fac = V2::Lighthouse::Facility.new(facility)
fac.distance = meta['distances'][index]['distance'] if meta['distances']
fac
end

paginate_response(facilities)
end

def facility
V2::Lighthouse::Facility.new(data)
end

private

def set_metadata(meta)
self.current_page = meta['pagination']['currentPage']
self.per_page = meta['pagination']['perPage']
self.total_entries = meta['pagination']['totalEntries']
end

def paginate_response(facilities)
WillPaginate::Collection.create(current_page, per_page) do |pager|
pager.replace(facilities)
pager.total_entries = total_entries
end
end
end
end
end
end
5 changes: 5 additions & 0 deletions modules/facilities_api/config/routes.rb
Expand Up @@ -14,5 +14,10 @@
resources :va, only: %i[index show]
end

namespace :v2, defaults: { format: 'json' } do
resources :va, only: :show
post 'va', to: 'va#search'
end

resources :apidocs, only: [:index]
end
@@ -0,0 +1,63 @@
# frozen_string_literal: true

require 'rails_helper'

describe FacilitiesApi::V2::Lighthouse::Facility, team: :facilities, type: :model do
context 'Creating' do
let(:attributes) do
{
'attributes' => {
'satisfaction' => {
health: {
primary_care_urgent: 0.8700000047683716,
primary_care_routine: 0.8700000047683716
},
effective_date: '2024-02-08'
}
},
'id' => 'abc_123',
'type' => 'va_facilities'
}
end

it 'has object defaults' do
facility = FacilitiesApi::V2::Lighthouse::Facility.new(attributes)
expect(facility.attributes).to match(
{
access: nil,
active_status: nil,
address: nil,
classification: nil,
detailed_services: nil,
distance: nil,
facility_type: nil,
facility_type_prefix: 'abc',
feedback: {
health: {
primary_care_urgent: 0.8700000047683716,
primary_care_routine: 0.8700000047683716
},
effective_date: '2024-02-08'
},
hours: nil,
id: 'abc_123',
lat: nil,
long: nil,
mobile: nil,
name: nil,
operating_status: nil,
operational_hours_special_instructions: nil,
parent: nil,
phone: nil,
services: nil,
time_zone: nil,
type: 'va_facilities',
unique_id: '123',
visn: nil,
website: nil,
tmp_covid_online_scheduling: nil
}
)
end
end
end

0 comments on commit d4c5192

Please sign in to comment.