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

Update HTTP status codes and associated symbols #2137

Merged
merged 4 commits into from Dec 7, 2023
Merged

Update HTTP status codes and associated symbols #2137

merged 4 commits into from Dec 7, 2023

Conversation

wtn
Copy link
Contributor

@wtn wtn commented Nov 24, 2023

These commits bring Rack in sync with the 2022-06-08 version of the IANA HTTP Status Code Registry.

This change is notably impactful in that the symbol for HTTP status code 422 changes from :unprocessable_entity to :unprocessable_content. To mitigate the impact, I added legacy symbol lookup to Rack::Utils.status_code.

It seems that some Rubyists are in the habit of retrieving status codes from Rack::Utils::SYMBOL_TO_STATUS_CODE directly (examples: here, here, here) rather than using the public method. Admittedly, I've done this myself. Well, it can't be helped, but perhaps this pattern can be discouraged in the future.

@ioquatix
Copy link
Member

This looks reasonable to me. @jeremyevans are you happy that backwards compatibility is sufficient?

Copy link
Contributor

@jeremyevans jeremyevans left a comment

Choose a reason for hiding this comment

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

I'm good with the general idea.

lib/rack/utils.rb Outdated Show resolved Hide resolved
lib/rack/utils.rb Outdated Show resolved Hide resolved
@wtn
Copy link
Contributor Author

wtn commented Nov 25, 2023

I removed the duplicated constant and added deprecation warnings.

The use of Hash#invert here is not ideal, but I didn't want to add yet more constants.

Copy link
Member

@ioquatix ioquatix left a comment

Choose a reason for hiding this comment

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

Looking good, just a few minor suggestions.

lib/rack/utils.rb Outdated Show resolved Hide resolved
lib/rack/utils.rb Outdated Show resolved Hide resolved
lib/rack/utils.rb Outdated Show resolved Hide resolved
lib/rack/utils.rb Outdated Show resolved Hide resolved
@wtn
Copy link
Contributor Author

wtn commented Nov 27, 2023

Thank you for feedback. I've made the following changes:

  1. use Hash#fetch in fallback symbol lookup
  2. rename OBSOLETE_HTTP_REASON_PHRASES to OBSOLETE_SYMBOLS_TO_STATUS_CODES and make it private
  3. add private constant OBSOLETE_SYMBOL_MAPPINGS to precompute preferred symbol for deprecation message
  4. use ternary statement for deprecation warning for succinctness and readability

@wtn wtn requested a review from ioquatix November 27, 2023 22:06
Copy link
Contributor

@jeremyevans jeremyevans 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 almost ready. I just have a couple of minor change requests.

test/spec_utils.rb Show resolved Hide resolved
lib/rack/utils.rb Outdated Show resolved Hide resolved
Copy link
Member

@ioquatix ioquatix left a comment

Choose a reason for hiding this comment

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

LGTM, let's see if @jeremyevans is okay to merge.

@ioquatix ioquatix merged commit 64ad26e into rack:main Dec 7, 2023
13 of 14 checks passed
@wtn wtn deleted the revise_codes branch December 8, 2023 05:06
@rafaelfranca
Copy link
Collaborator

Can we introduce the new names but keep the old names not deprecated?

For a libraries on top of rack the only way to support Rack 2 and Rails 3 at the same time after this change is by introducing a bunch of conditionals on the version of rack.

@ioquatix
Copy link
Member

ioquatix commented Jan 4, 2024

@rafaelfranca feel free to create a PR, not completely sure what issue you are having but sounds reasonable.

@rafaelfranca
Copy link
Collaborator

Will do.

The problem is that in Rails we have a few controllers with head :unprocessable_entity. To work without deprecation on Rack 3 we need to change it to head :unprocessable_content, but that doesn't work on Rack 2. So to work on both version we need to change the code to be:

head RACK_VERSION >= "3" ? :unprocessable_content : :unprocessable_entity

or some variation of that.

I'm also considering dropping support to Rack 2, in that case the problem will be solved for Rails 8, but not for 7.1, but I can probably work around the issue itself in Rails since that code will not live for much loger.

@ioquatix
Copy link
Member

ioquatix commented Jan 4, 2024

I believe you can use the status_code helper? Maybe it resolves the issue for you.

@rafaelfranca
Copy link
Collaborator

rafaelfranca commented Jan 5, 2024

That shows the deprecation. We don't want Rails to show people deprecation message for code the framework has.

@wtn
Copy link
Contributor Author

wtn commented Jan 5, 2024

In my view, it's best to keep the deprecation message in Rack.

Frameworks like Rails can manage the transition by adding status code symbols:

if Gem::Version.new(Rack.release) >= Gem::Version.new('3.y.z')
  Rack::Utils::SYMBOL_TO_STATUS_CODE[:payload_too_large] = 413
  Rack::Utils::SYMBOL_TO_STATUS_CODE[:unprocessable_entity] = 422
end

SYMBOL_TO_STATUS_CODE is not frozen, consider it part of the public API.

@rafaelfranca
Copy link
Collaborator

rafaelfranca commented Jan 5, 2024

This is exactly my point. I don't think rack should be pushing frameworks to do version checks. Rack is supposed to be a stable API. If a framework that depends on rack needs to check a version of the library we can't consider Rack stable anymore.

I'm all for adding features to Rack, but all their changes need to be backward compatible in a way that users don't have a hard time supporting 2 versions of Rack.

So my suggestion is: while Rack 2 is still supported, we don't show any deprecation, when only Rack 3 is supported we can add the deprecation in some Rack 3.x and in Rack 4 we remove it.

If this plan was hard to implement, I'd totally understand pushing version checks to users, but I'm sure we can keep an old status code name longer to make users' life easier.

@rafaelfranca
Copy link
Collaborator

Just to be clear, not criticizing the breaking changes/deprecations we had to do to evolve the spec, fix issues, etc, just saying there are a few like this one we can avoid if we decide to.

@tenderlove
Copy link
Member

SYMBOL_TO_STATUS_CODE is not frozen, consider it part of the public API.

I don't think we should consider mutating another library's constants to be "part of the public API". It's true that the constant is not frozen, but I also consider it bad manners to mutate someone else's constants. Also, in general, I think it's acceptable to freeze a constant but not do a major version release. IOW constant mutation is not public API, please do not consider it as such. If we want an API to mutate this constant, then we should add methods people call to register keys and values.

So my suggestion is: while Rack 2 is still supported, we don't show any deprecation, when only Rack 3 is supported we can add the deprecation in some Rack 3.x and in Rack 4 we remove it.

If this plan was hard to implement, I'd totally understand pushing version checks to users, but I'm sure we can keep an old status code name longer to make users' life easier.

I think this is reasonable.

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.

None yet

5 participants