diff --git a/CHANGELOG.md b/CHANGELOG.md index 969242e..e463c6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ ## [Unreleased] + +## 0.3.0 / 2026-02-26 +### Added +* Added specific error classes (InvalidURIError, UnauthorizedError) for granular error handling +* Extracted common error handling into `with_error_handling` method + ### Fixed * Support Ruby 3.4. Drop support for Rails 7.0, Ruby 3.1 diff --git a/lib/ndr_lookup/fhir/base.rb b/lib/ndr_lookup/fhir/base.rb index 2c8f0a8..f51d2ba 100644 --- a/lib/ndr_lookup/fhir/base.rb +++ b/lib/ndr_lookup/fhir/base.rb @@ -6,9 +6,12 @@ module NdrLookup module Fhir # Client for interacting with the NHS Digital FHIR API class Base < ActiveResource::Base + # Specific error classes for different API failure modes class ApiError < StandardError; end class ResourceNotFound < ApiError; end class InvalidResponse < ApiError; end + class InvalidURIError < ApiError; end + class UnauthorizedError < ApiError; end class << self attr_writer :additional_headers @@ -24,17 +27,10 @@ def sync # Finds a specific FHIR resource by type and ID # @return [Hash] Parsed FHIR resource def find(resource_type, id) - response = connection.get( - "#{endpoint}/#{resource_type}/#{id}", - headers - ) - JSON.parse(response.body) - rescue ActiveResource::ResourceNotFound - raise ResourceNotFound, "#{resource_type} with ID '#{id}' not found" - rescue JSON::ParserError - raise InvalidResponse, 'Invalid JSON response from server' - rescue StandardError => e - raise ApiError, "Unexpected error: #{e.message}" + with_error_handling("#{resource_type} with ID '#{id}' not found") do + response = connection.get("#{endpoint}/#{resource_type}/#{id}", headers) + JSON.parse(response.body) + end end def endpoint @@ -51,24 +47,33 @@ def endpoint # @example Search for relationships # Client.search('OrganizationAffiliation', organization: 'RHAGX') def search(resource_type, params = {}) - url = construct_url(endpoint, resource_type, params) - - # Make the request - response = connection.get(url, headers) + with_error_handling do + url = construct_url(endpoint, resource_type, params) + response = connection.get(url, headers) + payload = JSON.parse(response.body) + raise_unless_response_success(response, payload) + payload + end + end - # Process response - payload = JSON.parse(response.body) - raise_unless_response_success(response, payload) + private - payload + # Wraps API calls with consistent error handling, converting external exceptions + # (ActiveResource, JSON, URI) into our own error classes. + def with_error_handling(not_found_message = nil) + yield + rescue ActiveResource::ResourceNotFound + raise ResourceNotFound, not_found_message || 'Resource not found' + rescue ActiveResource::UnauthorizedAccess + raise UnauthorizedError, 'Authentication failed' rescue JSON::ParserError raise InvalidResponse, 'Invalid JSON response from server' + rescue URI::InvalidURIError => e + raise InvalidURIError, "Invalid ID format: #{e.message}" rescue StandardError => e - raise ApiError, "Search failed: #{e.message}" + raise ApiError, "Unexpected error: #{e.message}" end - private - def construct_url(endpoint, resource_type, params = {}) url = "#{endpoint}/#{resource_type}" diff --git a/lib/ndr_lookup/version.rb b/lib/ndr_lookup/version.rb index 362749b..8493785 100644 --- a/lib/ndr_lookup/version.rb +++ b/lib/ndr_lookup/version.rb @@ -1,3 +1,3 @@ module NdrLookup - VERSION = '0.2.0'.freeze + VERSION = '0.3.0'.freeze end