From 68273b83fd2043c2687088a940124591bb5ba6c4 Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Tue, 10 Sep 2024 23:53:19 +0200 Subject: [PATCH 1/2] raise_error: Allow to configure status codes that don't raise --- docs/middleware/included/raising-errors.md | 25 +++++++++++++--------- lib/faraday/response/raise_error.rb | 4 +++- spec/faraday/response/raise_error_spec.rb | 20 +++++++++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/docs/middleware/included/raising-errors.md b/docs/middleware/included/raising-errors.md index 3b82130c..65fff3af 100644 --- a/docs/middleware/included/raising-errors.md +++ b/docs/middleware/included/raising-errors.md @@ -63,23 +63,28 @@ and raised as `Faraday::NilStatusError`, which inherits from `Faraday::ServerErr The behavior of this middleware can be customized with the following options: -| Option | Default | Description | -|---------------------|---------|-------------| -| **include_request** | true | When true, exceptions are initialized with request information including `method`, `url`, `url_path`, `params`, `headers`, and `body`. | +| Option | Default | Description | +|----------------------|---------|-------------| +| **include_request** | true | When true, exceptions are initialized with request information including `method`, `url`, `url_path`, `params`, `headers`, and `body`. | +| **allowed_statuses** | [] | An array of status codes that should not raise an error. | ### Example Usage ```ruby conn = Faraday.new(url: 'http://httpbingo.org') do |faraday| - faraday.response :raise_error, include_request: true + faraday.response :raise_error, include_request: true, allowed_statuses: [404] end begin - conn.get('/wrong-url') # => Assume this raises a 404 response -rescue Faraday::ResourceNotFound => e - e.response[:status] #=> 404 - e.response[:headers] #=> { ... } - e.response[:body] #=> "..." - e.response[:request][:url_path] #=> "/wrong-url" + conn.get('/wrong-url') # => Assume this raises a 404 response + conn.get('/protected-url') # => Assume this raises a 401 response +rescue Faraday::UnauthorizedError => e + e.response[:status] # => 401 + e.response[:headers] # => { ... } + e.response[:body] # => "..." + e.response[:request][:url_path] # => "/protected-url" end ``` + +In this example, a `Faraday::UnauthorizedError` exception is raised for the `/protected-url` request, while the +`/wrong-url` request does not raise an error because the status code `404` is in the `allowed_statuses` array. diff --git a/lib/faraday/response/raise_error.rb b/lib/faraday/response/raise_error.rb index 957b6e78..054e44bc 100644 --- a/lib/faraday/response/raise_error.rb +++ b/lib/faraday/response/raise_error.rb @@ -10,9 +10,11 @@ class RaiseError < Middleware ServerErrorStatuses = (500...600) # rubocop:enable Naming/ConstantName - DEFAULT_OPTIONS = { include_request: true }.freeze + DEFAULT_OPTIONS = { include_request: true, allowed_statuses: [] }.freeze def on_complete(env) + return if Array(options[:allowed_statuses]).include?(env[:status]) + case env[:status] when 400 raise Faraday::BadRequestError, response_values(env) diff --git a/spec/faraday/response/raise_error_spec.rb b/spec/faraday/response/raise_error_spec.rb index 65aba59d..6013080d 100644 --- a/spec/faraday/response/raise_error_spec.rb +++ b/spec/faraday/response/raise_error_spec.rb @@ -252,4 +252,24 @@ end end end + + describe 'allowing certain status codes' do + let(:conn) do + Faraday.new do |b| + b.response :raise_error, allowed_statuses: [404] + b.adapter :test do |stub| + stub.get('bad-request') { [400, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] } + end + end + end + + it 'raises an error for status codes that are not explicitly allowed' do + expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError) + end + + it 'does not raise an error for allowed status codes' do + expect { conn.get('not-found') }.not_to raise_error + end + end end From ea129520e25b8b437b4340289e2c910251dd1b99 Mon Sep 17 00:00:00 2001 From: Clemens Kofler Date: Tue, 10 Sep 2024 23:57:45 +0200 Subject: [PATCH 2/2] Refactor to cut repetition in raise_error's status code handling --- lib/faraday/response/raise_error.rb | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/faraday/response/raise_error.rb b/lib/faraday/response/raise_error.rb index 054e44bc..0b543219 100644 --- a/lib/faraday/response/raise_error.rb +++ b/lib/faraday/response/raise_error.rb @@ -8,6 +8,16 @@ class RaiseError < Middleware # rubocop:disable Naming/ConstantName ClientErrorStatuses = (400...500) ServerErrorStatuses = (500...600) + ClientErrorStatusesWithCustomExceptions = { + 400 => Faraday::BadRequestError, + 401 => Faraday::UnauthorizedError, + 403 => Faraday::ForbiddenError, + 404 => Faraday::ResourceNotFound, + 408 => Faraday::RequestTimeoutError, + 409 => Faraday::ConflictError, + 422 => Faraday::UnprocessableEntityError, + 429 => Faraday::TooManyRequestsError + }.freeze # rubocop:enable Naming/ConstantName DEFAULT_OPTIONS = { include_request: true, allowed_statuses: [] }.freeze @@ -16,26 +26,12 @@ def on_complete(env) return if Array(options[:allowed_statuses]).include?(env[:status]) case env[:status] - when 400 - raise Faraday::BadRequestError, response_values(env) - when 401 - raise Faraday::UnauthorizedError, response_values(env) - when 403 - raise Faraday::ForbiddenError, response_values(env) - when 404 - raise Faraday::ResourceNotFound, response_values(env) + when *ClientErrorStatusesWithCustomExceptions.keys + raise ClientErrorStatusesWithCustomExceptions[env[:status]], response_values(env) when 407 # mimic the behavior that we get with proxy requests with HTTPS msg = %(407 "Proxy Authentication Required") raise Faraday::ProxyAuthError.new(msg, response_values(env)) - when 408 - raise Faraday::RequestTimeoutError, response_values(env) - when 409 - raise Faraday::ConflictError, response_values(env) - when 422 - raise Faraday::UnprocessableEntityError, response_values(env) - when 429 - raise Faraday::TooManyRequestsError, response_values(env) when ClientErrorStatuses raise Faraday::ClientError, response_values(env) when ServerErrorStatuses