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

Passing status to the ErrorFormatter #2528

Conversation

drewnichols
Copy link

@drewnichols drewnichols commented Jan 28, 2025

The status paramter is not passed into the format_message method here in error!:

def error!(message, status = options[:default_status], headers = {}, backtrace = [], original_exception = nil)
rack_response(
status, headers.reverse_merge(Rack::CONTENT_TYPE => content_type),
format_message(message, backtrace, original_exception)
)
end

Passing it allow it to be included in the response body JSON. This is the way it's included in the JSON API error response bodies:

# HTTP/1.1 422 Unprocessable Entity
# Content-Type: application/vnd.api+json

{
  "errors": [
    {
      "status": "422",
      "source": { "pointer": "/data/attributes/firstName" },
      "title":  "Invalid Attribute",
      "detail": "First name must contain at least two characters."
    }
  ]
}

@drewnichols drewnichols force-pushed the make-http-status-accessible-to-error-formatters branch from e8f0495 to cb87e68 Compare January 28, 2025 06:37
@drewnichols drewnichols force-pushed the make-http-status-accessible-to-error-formatters branch from cb87e68 to d05f0ec Compare January 28, 2025 06:48
@drewnichols drewnichols changed the title added http status to the format_error parameter list making it access… Passing status to the ErrorFormatter Jan 28, 2025
@drewnichols drewnichols marked this pull request as ready for review January 28, 2025 06:51
Copy link
Member

@dblock dblock left a comment

Choose a reason for hiding this comment

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

Looks good, fix tests, likely needs documentation in https://github.com/ruby-grape/grape?tab=readme-ov-file#exception-handling and see if we can add lower level tests that a custom formatter for this.

Check failing tests for whether there's a non-backwards-compatible scenario, we don't want that.

@@ -4,7 +4,7 @@ module Grape
module ErrorFormatter
class Base
class << self
def call(message, backtrace, options = {}, env = nil, original_exception = nil)
def call(message, backtrace, options = {}, env = nil, original_exception = nil, _status = nil) # rubocop:disable Metrics/ParameterLists
Copy link
Member

Choose a reason for hiding this comment

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

Use rubocop -a ; rubocop --auto-gen-config instead of an inline #rubocop:disable, we have a lot of violations.

Copy link
Author

@drewnichols drewnichols Jan 28, 2025

Choose a reason for hiding this comment

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

done, though I would probably just update the Metrics/ParameterLists settings in .rubocop.yml as 5 is a really small number limit parameter count.

CHANGELOG.md Outdated Show resolved Hide resolved
Copy link
Member

@dblock dblock left a comment

Choose a reason for hiding this comment

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

Question below.

If the answer is yes, we need a backwards compatible implementation, maybe passing status within options?

@@ -2772,8 +2772,8 @@ Custom error formatters for existing and additional types can be defined with a

```ruby
class Twitter::API < Grape::API
error_formatter :txt, ->(message, backtrace, options, env, original_exception) {
"error: #{message} from #{backtrace}"
error_formatter :txt, ->(message, backtrace, options, env, original_exception, status) {
Copy link
Member

Choose a reason for hiding this comment

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

Is this a breaking change? Meaning if I had the old code and upgrade Grape, will this fail with an invalid number of parameters?

Copy link
Author

Choose a reason for hiding this comment

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

Best I could tell this calls Grape::Middleware::Error.format_message where I defaulted status to nil. If someone created a custom Middleware there could be a problem. Fairpoint though.. I can check this with my own app and also look into making some more specs to verify.

Copy link
Member

Choose a reason for hiding this comment

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

Since we document custom middleware this would be a breaking change :(

Copy link
Member

@dblock dblock left a comment

Choose a reason for hiding this comment

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

Let's discuss @ericproulx's comment on this interface in #2527 (comment). If we are going to introduce a breaking change, I think we want something future-proof.

The other option is to add status to the local scope, and not change this interface, which seems desirable.

@@ -2772,8 +2772,8 @@ Custom error formatters for existing and additional types can be defined with a

```ruby
class Twitter::API < Grape::API
error_formatter :txt, ->(message, backtrace, options, env, original_exception) {
"error: #{message} from #{backtrace}"
error_formatter :txt, ->(message, backtrace, options, env, original_exception, status) {
Copy link
Member

Choose a reason for hiding this comment

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

Since we document custom middleware this would be a breaking change :(

@drewnichols
Copy link
Author

Closing this PR. With the fix in #2533 we can now access the HTTP status from the env argument to CustomFormatter.call(..) per this #2527 (comment).

@dblock
Copy link
Member

dblock commented Feb 11, 2025

Thanks for hanging in here with us @drewnichols! I still wish we had a local scope for request and/or response here.

@drewnichols
Copy link
Author

drewnichols commented Feb 11, 2025

No worries, as this would be a breaking change it makes sense to do it in a major version update and put more thought into it to allow for future extensibility.

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

Successfully merging this pull request may close these issues.

2 participants