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

Html exceptions only when accepted #592

Closed
wants to merge 4 commits into from

Conversation

bestie
Copy link
Contributor

@bestie bestie commented Aug 10, 2013

Rather than be concerned with whether a request is an asynchronous browser
request or not it is better to simply consider the Accept header and only serve
HTML to clients that specifically ask for it.

This way you will not find your pure JSON API application splitting out HTML
error messages to your console when using curl :)

Rather than be concerned with whether a request is an asynchronous browser
request or not it is better to simply consider the Accept header and only serve
HTML to clients that specifically ask for it.

This way you will not find your pure JSON API application splitting out HTML
error messages to your console when using curl :)
* Load HTML exception template only if needed
* Only #call is public
* Enumerable body concern in one place
end

def prefers_plain_text?(env)
env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" && (!env["HTTP_ACCEPT"] || !env["HTTP_ACCEPT"].include?("text/html"))
private
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't marking all the following methods as private a too invasive change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it would be very odd if anyone was making use of these methods so I thought better to close up the public API to make later changes easier.

I would think it very odd if someone was making use of these methods, though I do appreciate your concern.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see you point and agree with you, but I think that this kind of changes are not OK unless there is a major version bump to notify of possible breakage.

@bestie
Copy link
Contributor Author

bestie commented Aug 13, 2013

I've restored the public API to it's previous state, also I've made sure the new method I've added is private.

Hope this is now acceptable. I'm happy to squash commits if that's your preference.

@bestie
Copy link
Contributor Author

bestie commented Nov 27, 2013

@spastorino @raggi Any thoughts on this?

I'm having to monkey patch this change in on all my JSON API apps otherwise every time you get an error it's a huge PITA :)

@@ -17,7 +17,6 @@ class ShowExceptions

def initialize(app)
@app = app
@template = ERB.new(TEMPLATE)
Copy link
Member

Choose a reason for hiding this comment

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

ERB parsing is not cheap. Why was this moved, it seems orthogonal to the desired changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just a refactoring I thought might be beneficial.

Now no ERB object is created unless HTML is about to rendered. This should improve performance if anything.

Happy to revert if this is a deal breaker.

Copy link
Member

Choose a reason for hiding this comment

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

You want to improve boot time performance at the sacrifice of runtime performance? I'd be more worried about the extra garbage, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes that's right, as the template only needs to rendered in the case of an exception isn't it better to take the performance hit only when one is raised rather than on every request?

Copy link
Member

Choose a reason for hiding this comment

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

Initialize is not called every request.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Of course you're right. However this change still prevents all template related objects from being created until absolutely necessary.

@raggi
Copy link
Member

raggi commented Dec 4, 2013

Looks good in principle. Would you mind addressing the comment?

As this is orthoganol to HTML rendering change.
@bestie
Copy link
Contributor Author

bestie commented Jan 10, 2014

While I stand by my refactorings I agree that the discussed changes to the template rendering are orthogonal to the purpose of this PR.

I have therefore removed it.

@@ -85,7 +94,7 @@ def pretty(env, exception)
end
}.compact

[@template.result(binding)]
@template.result(binding)
Copy link
Member

Choose a reason for hiding this comment

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

Why did you remove the array here? Doesn't ERB return strings from result?

Rack SPEC says "Body must respond to #each and yield strings". String does not do this in all supported ruby versions in all locales.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've moved the concern of wrapping the response body string in an array to one place. See line 45 https://github.com/bestie/rack/blob/5b2ee1163aa6f68df5ec712b4d9802d90a7875f4/lib/rack/showexceptions.rb#L45

def prefers_plain_text?(env)
env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" && (!env["HTTP_ACCEPT"] || !env["HTTP_ACCEPT"].include?("text/html"))
def accepts_html?(env)
env["HTTP_ACCEPT"] && env["HTTP_ACCEPT"].include?("text/html")
Copy link
Member

Choose a reason for hiding this comment

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

We have Rack::Utils.best_q_match and friends now, that are probably better used here.

@raggi raggi added this to the Rack 1.5.3 milestone Jul 12, 2014
@raggi raggi closed this in 6f1a4a4 Jul 13, 2014
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

3 participants