Skip to content

Commit 3db2d7b

Browse files
committed
Better error handling
1 parent 9b99823 commit 3db2d7b

25 files changed

+630
-453
lines changed

lib/seek/doi/parser.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class Parser
77
DOI_ENDPOINT = 'https://doi.org'.freeze
88

99
def self.parse(doi)
10+
1011
agency = get_doi_ra(doi)
1112

1213
case agency

lib/seek/doi/parsers/base_parser.rb

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,24 @@ def parse(doi)
1212
Rails.logger.info("Fetching metadata for DOI #{doi} from #{url}")
1313

1414
response = perform_request(url)
15-
return nil unless response.is_a?(Net::HTTPSuccess)
16-
17-
begin
18-
data = parse_response_body(response)
19-
raise "Missing metadata in response" unless data
20-
21-
data = decode_html_entities_in_hash(data)
22-
metadata = extract_metadata(data)
23-
metadata[:citation] ||= build_citation(metadata)
24-
25-
build_struct(metadata)
26-
rescue JSON::ParserError => e
27-
Rails.logger.error("JSON parse error for DOI #{doi}: #{e.message}")
28-
nil
29-
rescue StandardError => e
30-
Rails.logger.error("Unexpected error parsing DOI #{doi}: #{e.message}")
31-
nil
32-
end
15+
data = parse_response_body(response)
16+
17+
raise Seek::Doi::ParseException, "Empty metadata response for DOI #{doi}" if data.blank?
18+
19+
metadata = decode_html_entities_in_hash(extract_metadata(data))
20+
metadata[:citation] ||= build_citation(metadata)
21+
22+
build_struct(metadata)
23+
24+
rescue JSON::ParserError => e
25+
raise Seek::Doi::ParseException, "Error parsing JSON for DOI #{doi}: #{e.message}"
26+
rescue Seek::Doi::BaseException
27+
raise
28+
rescue StandardError => e
29+
raise Seek::Doi::ParseException, "Unexpected error while parsing DOI #{doi}: #{e.message}"
3330
end
3431

32+
3533
protected
3634

3735
def normalize_metadata(raw)
@@ -79,12 +77,22 @@ def perform_request(uri, accept_header: 'application/json')
7977
request = Net::HTTP::Get.new(uri)
8078
request['Accept'] = accept_header
8179
response = http.request(request)
82-
Rails.logger.debug("HTTP #{response.code} #{response.message} for #{uri}")
83-
response
80+
81+
case response.code.to_i
82+
when 200
83+
response
84+
when 204
85+
raise Seek::Doi::FetchException, "No metadata available for DOI #{uri}"
86+
when 404
87+
raise Seek::Doi::NotFoundException, "DOI not found: #{uri}"
88+
else
89+
raise Seek::Doi::FetchException, "Unexpected HTTP #{response.code} #{response.message} for #{uri}"
90+
end
8491
end
85-
rescue SocketError, Timeout::Error, StandardError => e
86-
Rails.logger.error("Network error fetching #{uri}: #{e.message}")
87-
nil
92+
rescue SocketError, Timeout::Error => e
93+
raise Seek::Doi::FetchException, "Network error fetching DOI metadata: #{e.message}"
94+
rescue URI::InvalidURIError => e
95+
raise Seek::Doi::MalformedDOIException, "Invalid DOI or malformed URI: #{e.message}"
8896
end
8997

9098

lib/seek/doi/parsers/crossref_parser.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ def extract_date(data)
5050
end
5151

5252
date_parts = get_date_parts.call('issued') ||
53-
get_date_parts.call('published') ||
54-
get_date_parts.call('published-print')
53+
get_date_parts.call('published') ||
54+
get_date_parts.call('published-print')
5555
date_parts ? (Date.new(*date_parts) rescue nil) : nil
5656
end
5757

lib/seek/doi/parsers/datacite_parser.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ def extract_date(data)
4343
if data['publicationYear']
4444
Date.new(data['publicationYear'].to_i)
4545
elsif (issued = Array(data['dates']).find { |d| d['dateType'] == 'Issued' })
46-
Date.parse(issued['date']) rescue nil
46+
begin
47+
Date.parse(issued['date'])
48+
rescue
49+
nil
50+
end
4751
end
4852
end
4953

test/unit/doi/crossref_parser_test.rb

Lines changed: 273 additions & 283 deletions
Large diffs are not rendered by default.

test/unit/doi/doi_parser_exception_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ class DoiParserExceptionTest < ActiveSupport::TestCase
4141
end
4242
end
4343

44+
45+
test 'raises ParseException when Crossref returns invalid JSON' do
46+
doi = '10.1016/j.patter.2025.101345'
47+
48+
VCR.use_cassette('doi/invalid_json_response') do
49+
error = assert_raises(Seek::Doi::ParseException) do
50+
Seek::Doi::Parser.parse(doi)
51+
end
52+
assert_match /Error parsing JSON for DOI/, error.message
53+
end
54+
end
55+
4456
end
4557

4658

test/vcr_cassettes/doi/crossref_ra.yml

Lines changed: 58 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/vcr_cassettes/doi/datacite_ra.yml

Lines changed: 58 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/vcr_cassettes/doi/doi_crossref_book_chapter_response_1.yml

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/vcr_cassettes/doi/doi_crossref_book_chapter_response_2.yml

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)