Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make RaiseError middleware configurable to not raise error on certain status codes (e.g. 404) #1590

Merged
merged 3 commits into from
Sep 13, 2024

Conversation

clemens
Copy link
Contributor

@clemens clemens commented Sep 10, 2024

Description

This adds the possibility to use the RaiseError middleware while preventing certain status from raising errors.

A common example are cases where raising errors on 4xx/5xx status codes is generally desirable and consequently we want to use the RaiseError middleware and then having to work around a missing upsert (PUT) behavior by first trying to fetch a resource and depending on whether or not the resource is found, we subsequently POST to create or PATCH to update.

Before:

client = Faraday.new('https://example.com') do |b|
  b.response :raise_error
end

existing_object = begin
  client.get('/foo/1').body
rescue Faraday::ResourceNotFound
  # We expect this resource to potentially be missing, but still have to
  # rescue from it when using the RaiseError middleware
end

if existing_object
  client.patch('/foo', data)
else
  client.post('/foo', data)
end

After:

client = Faraday.new('https://example.com') do |b|
  b.response :raise_error, allowed_statuses: [404]
end

existing_object = client.get('/foo/1').body

if existing_object
  client.patch('/foo', data)
else
  client.post('/foo', data)
end

Closes #1587.

Todos

None.

Additional Notes

In addition to adding the feature, I've refactored the repetitive case/when statement. I'm happy to take it out if that change is undesirable.

Copy link
Member

@iMacTia iMacTia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thank you for working on this!

I just want to be sure though you understand the behaviour will be slightly different from what you highlighted in the "After" section of the PR description:

# In the case of a 404 status, this won't raise an error anymore,
# which is what we want 👍
existing_object = client.get('/foo/1').body

# However the "failed" response will still be processed as a successful one,
# meaning `existing_object` will always evaluate to `true` here 👇
# (e.g. the body of the response could still be an empty string)
# 
# You'd need to use a more explicitly check here, e.g. on the response status
# or the actual presence of the response body
if existing_object
  client.patch('/foo', data)
else
  client.post('/foo', data)
end

This is perfectly fine for me and it does make sense, but appreciate it might cause a bit of surprise.
If you're OK with it, I can get this merged and released

raise Faraday::ForbiddenError, response_values(env)
when 404
raise Faraday::ResourceNotFound, response_values(env)
when *ClientErrorStatusesWithCustomExceptions.keys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neat!

@clemens
Copy link
Contributor Author

clemens commented Sep 13, 2024

Thanks for the positive feedback!

What you're saying is true: The code in my "After" example doesn't exactly work yet. I do think it makes more sense to adapt the example rather than trying to build in some "special" behavior into the middleware – would you agree? Then I'd just change the PR description accordingly.

@iMacTia
Copy link
Member

iMacTia commented Sep 13, 2024

Yes, absolutely 👍
No need to amend the PR description, it looks like we're on the same page anyway and the changes to the documentation don't present the same example.

I just wanted to make sure there was no misunderstanding 😄
Merging 🚀 !

@iMacTia iMacTia merged commit 98d5adf into lostisland:main Sep 13, 2024
7 checks passed
@iMacTia
Copy link
Member

iMacTia commented Sep 13, 2024

This is now merged into main, do you think you might test the changes in your project from there @clemens?
Nothing against cutting a new release, just trying to play it safe with some testing if possible 🙂

@clemens
Copy link
Contributor Author

clemens commented Sep 17, 2024

This is now merged into main, do you think you might test the changes in your project from there @clemens? Nothing against cutting a new release, just trying to play it safe with some testing if possible 🙂

I've tested it today (with multiple 404 cases in a larger script) and everything worked as expected: I had other 4xx and 5xx errors being raised, but 404 just let the script proceed => great! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants