mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-01-31 03:59:51 +08:00
Implement protocols.io error handling for api client and normalizer
This commit is contained in:
parent
c691ad80b5
commit
ebcaa4b014
13 changed files with 235 additions and 8 deletions
|
@ -27,7 +27,15 @@ class ExternalProtocolsController < ApplicationController
|
|||
endpoint_name = Constants::PROTOCOLS_ENDPOINTS.dig(*show_params[:protocol_source]
|
||||
.split('/').map(&:to_sym))
|
||||
api_client = "ProtocolImporters::#{endpoint_name}::ApiClient".constantize.new
|
||||
html_preview = api_client.protocol_html_preview(show_params[:protocol_id])
|
||||
|
||||
begin
|
||||
html_preview = api_client.protocol_html_preview(show_params[:protocol_id])
|
||||
rescue SocketError, HTTParty::Error => e
|
||||
render json: {
|
||||
errors: [network: e.message]
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
render json: {
|
||||
protocol_source: show_params[:protocol_source],
|
||||
|
|
|
@ -17,9 +17,24 @@ module ProtocolImporters
|
|||
def call
|
||||
return self unless valid?
|
||||
|
||||
# TODO: check for errors
|
||||
api_response = api_client.single_protocol(@id)
|
||||
normalized_hash = normalizer.normalize_protocol(api_response)
|
||||
# Call api client
|
||||
begin
|
||||
api_response = api_client.single_protocol(@id)
|
||||
rescue api_errors => e
|
||||
@errors[e.class.to_s.downcase.to_sym] = e.error_message
|
||||
return self
|
||||
rescue SocketError, HTTParty::Error => e
|
||||
@errors[e.class.to_s.downcase.to_sym] = e.message
|
||||
return self
|
||||
end
|
||||
|
||||
# Normalize protocol
|
||||
begin
|
||||
normalized_hash = normalizer.normalize_protocol(api_response)
|
||||
rescue normalizer_errors => e
|
||||
@errors[e.class.to_s.downcase.to_sym] = e.error_message
|
||||
return self
|
||||
end
|
||||
|
||||
pio = ProtocolImporters::ProtocolIntermediateObject.new(normalized_json: normalized_hash,
|
||||
user: @user,
|
||||
|
@ -63,5 +78,13 @@ module ProtocolImporters
|
|||
def normalizer
|
||||
"ProtocolImporters::#{endpoint_name}::ProtocolNormalizer".constantize.new
|
||||
end
|
||||
|
||||
def api_errors
|
||||
"ProtocolImporters::#{endpoint_name}::ApiErrors::Error".constantize
|
||||
end
|
||||
|
||||
def normalizer_errors
|
||||
"ProtocolImporters::#{endpoint_name}::NormalizerError".constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,9 +17,24 @@ module ProtocolImporters
|
|||
def call
|
||||
return self unless valid?
|
||||
|
||||
api_response = api_client.protocol_list(@query_params)
|
||||
# Call api client
|
||||
begin
|
||||
api_response = api_client.protocol_list(@query_params)
|
||||
rescue api_errors => e
|
||||
@errors[e.class.to_s.downcase.to_sym] = e.error_message
|
||||
return self
|
||||
rescue SocketError, HTTParty::Error => e
|
||||
@errors[e.class.to_s.downcase.to_sym] = e.message
|
||||
return self
|
||||
end
|
||||
|
||||
@protocols_list = normalizer.normalize_list(api_response)
|
||||
# Normalize protocols list
|
||||
begin
|
||||
@protocols_list = normalizer.normalize_list(api_response)
|
||||
rescue normalizer_errors => e
|
||||
@errors[e.class.to_s.downcase.to_sym] = e.error_message
|
||||
return self
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
@ -66,5 +81,13 @@ module ProtocolImporters
|
|||
def normalizer
|
||||
"ProtocolImporters::#{endpoint_name}::ProtocolNormalizer".constantize.new
|
||||
end
|
||||
|
||||
def api_errors
|
||||
"ProtocolImporters::#{endpoint_name}::ApiErrors::Error".constantize
|
||||
end
|
||||
|
||||
def normalizer_errors
|
||||
"ProtocolImporters::#{endpoint_name}::NormalizerError".constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,9 +12,12 @@ module ProtocolImporters
|
|||
default_timeout CONSTANTS[:default_timeout]
|
||||
logger Rails.logger, CONSTANTS[:debug_level]
|
||||
|
||||
attr_reader :errors
|
||||
|
||||
def initialize(token = nil)
|
||||
# Currently we support public tokens only (no token needed for public data)
|
||||
@auth = { token: token }
|
||||
@errors = {}
|
||||
|
||||
# Set default headers
|
||||
self.class.headers('Authorization': "Bearer #{@auth[:token]}") if @auth[:token].present?
|
||||
|
@ -45,12 +48,12 @@ module ProtocolImporters
|
|||
query = CONSTANTS.dig(:endpoints, :protocols, :default_query_params)
|
||||
.merge(query_params)
|
||||
|
||||
self.class.get('/protocols', query: query)
|
||||
check_for_api_errors(self.class.get('/protocols', query: query))
|
||||
end
|
||||
|
||||
# Returns full representation of given protocol ID
|
||||
def single_protocol(id)
|
||||
self.class.get("/protocols/#{id}")
|
||||
check_for_api_errors(self.class.get("/protocols/#{id}"))
|
||||
end
|
||||
|
||||
# Returns html preview for given protocol
|
||||
|
@ -59,6 +62,22 @@ module ProtocolImporters
|
|||
def protocol_html_preview(uri)
|
||||
self.class.get("https://www.protocols.io/view/#{uri}.html", headers: {})
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_for_api_errors(response)
|
||||
if response['status_code'] == 0
|
||||
return response
|
||||
elsif response['status_code'] == 1
|
||||
raise ApiErrors::MissingOrEmptyParametersError.new(response['status_code'], response['error_message'])
|
||||
elsif response['status_code'] == 1218
|
||||
raise ApiErrors::InvalidTokenError.new(response['status_code'], response['error_message'])
|
||||
elsif response['status_code'] == 1219
|
||||
raise ApiErrors::TokenExpiredError.new(response['status_code'], response['error_message'])
|
||||
else
|
||||
raise ApiErrors::Error.new(response['status_code'], response['error_message'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtocolImporters
|
||||
module ProtocolsIO
|
||||
module V3
|
||||
module ApiErrors
|
||||
class Error < StandardError
|
||||
attr_reader :status_code, :error_message
|
||||
|
||||
def initialize(status_code, error_message)
|
||||
@status_code = status_code
|
||||
@error_message = error_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtocolImporters
|
||||
module ProtocolsIO
|
||||
module V3
|
||||
module ApiErrors
|
||||
class InvalidTokenError < Error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtocolImporters
|
||||
module ProtocolsIO
|
||||
module V3
|
||||
module ApiErrors
|
||||
class MissingOrEmptyParametersError < Error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtocolImporters
|
||||
module ProtocolsIO
|
||||
module V3
|
||||
module ApiErrors
|
||||
class TokenExpiredError < Error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtocolImporters
|
||||
module ProtocolsIO
|
||||
module V3
|
||||
class NormalizerError < StandardError
|
||||
attr_reader :error_type, :error_message
|
||||
|
||||
def initialize(error_type, error_message)
|
||||
@error_type = error_type
|
||||
@error_message = error_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,6 +7,9 @@ module ProtocolImporters
|
|||
def normalize_protocol(client_data)
|
||||
# client_data is HttpParty ApiReponse object
|
||||
protocol_hash = client_data.parsed_response.with_indifferent_access[:protocol]
|
||||
unless protocol_hash.present?
|
||||
raise NormalizerError.new(:nil_protocol, 'Protocol not present in hash.')
|
||||
end
|
||||
|
||||
normalized_data = {
|
||||
uri: client_data.request.last_uri.to_s,
|
||||
|
@ -54,6 +57,9 @@ module ProtocolImporters
|
|||
def normalize_list(client_data)
|
||||
# client_data is HttpParty ApiReponse object
|
||||
protocols_hash = client_data.parsed_response.with_indifferent_access[:items]
|
||||
unless protocols_hash.present?
|
||||
raise NormalizerError.new(:nil_protocol_items, 'Protocol items not present in hash.')
|
||||
end
|
||||
normalized_data = {}
|
||||
normalized_data[:protocols] = protocols_hash.map do |e|
|
||||
{
|
||||
|
|
|
@ -78,6 +78,16 @@ describe ExternalProtocolsController, type: :controller do
|
|||
expect(JSON.parse(response.body)['html']).to eq(html_preview)
|
||||
end
|
||||
|
||||
it 'return network errors when calling api client' do
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:protocol_html_preview)
|
||||
.and_raise(SocketError))
|
||||
|
||||
# Call action
|
||||
action
|
||||
expect(JSON.parse(response.body)).to have_key('errors')
|
||||
end
|
||||
|
||||
it 'returns error JSON and 400 response when something went wrong' do
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:protocol_html_preview)).and_raise(StandardError)
|
||||
|
|
|
@ -22,6 +22,40 @@ describe ProtocolImporters::BuildProtocolFromClientService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when raise api client error' do
|
||||
it 'return network errors' do
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:single_protocol)
|
||||
.and_raise(SocketError))
|
||||
|
||||
expect(service_call.errors).to have_key(:socketerror)
|
||||
end
|
||||
|
||||
it 'return api errors' do
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:single_protocol)
|
||||
.and_raise(ProtocolImporters::ProtocolsIO::V3::ApiErrors::MissingOrEmptyParametersError.new('1', 'Missing Or Empty Parameters Error')))
|
||||
|
||||
expect(service_call.errors).to have_key(:"protocolimporters::protocolsio::v3::apierrors::missingoremptyparameterserror")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when normalize protocol fails' do
|
||||
it 'return normalizer errors' do
|
||||
client_data = double('api_response')
|
||||
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:single_protocol)
|
||||
.and_return(client_data))
|
||||
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer)
|
||||
.to(receive(:normalize_protocol).with(client_data)
|
||||
.and_raise(ProtocolImporters::ProtocolsIO::V3::NormalizerError.new('nil_protocol', 'Nil Protocol')))
|
||||
|
||||
expect(service_call.errors).to have_key(:"protocolimporters::protocolsio::v3::normalizererror")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when have valid arguments' do
|
||||
before do
|
||||
client_data = double('api_response')
|
||||
|
|
|
@ -32,6 +32,40 @@ describe ProtocolImporters::SearchProtocolsService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when raise api client error' do
|
||||
it 'return network errors' do
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:protocol_list)
|
||||
.and_raise(SocketError))
|
||||
|
||||
expect(service_call.errors).to have_key(:socketerror)
|
||||
end
|
||||
|
||||
it 'return api errors' do
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:protocol_list)
|
||||
.and_raise(ProtocolImporters::ProtocolsIO::V3::ApiErrors::MissingOrEmptyParametersError.new('1', 'Missing Or Empty Parameters Error')))
|
||||
|
||||
expect(service_call.errors).to have_key(:"protocolimporters::protocolsio::v3::apierrors::missingoremptyparameterserror")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when normalize protocol fails' do
|
||||
it 'return normalizer errors' do
|
||||
client_data = double('api_response')
|
||||
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:protocol_list)
|
||||
.and_return(client_data))
|
||||
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer)
|
||||
.to(receive(:normalize_list).with(client_data)
|
||||
.and_raise(ProtocolImporters::ProtocolsIO::V3::NormalizerError.new('nil_items', 'Nil Items')))
|
||||
|
||||
expect(service_call.errors).to have_key(:"protocolimporters::protocolsio::v3::normalizererror")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when have valid attributes' do
|
||||
before do
|
||||
client_data = double('api_response')
|
||||
|
|
Loading…
Reference in a new issue