-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Bypass formatting for statuses with no entity-body #1190
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
Conversation
I left my refactoring commits separate as to not add noise when reviewing the feature change. Please let me know if you'd prefer them squashed. |
This makes a lot of sense. It definitely needs an entry in UPGRADING. I would be down with just merging this "as is", fix the build though please ;) |
Got caught by the cop! Thanks for the reminder regarding UPGRADING. I added a section there. Please let me know if it is adequate. |
As for me, it makes more sense if we could skip the formatter explicity outside the formatter scope. I mean # endpoint
def status(code)
skip_formatter_middleware if no_body_status_code(code)
...
end
def skip_formatter_middleware
env['grape.formatter.skip'] = true
end
# formatter
def call(env)
return response if env['grape.formatter.skip']
end EDIT: removed |
@dm1try I think it makes sense to do this by default wrt Tell us how strongly you feel about this or something else before I merge? |
@dblock PR looks good, you can merge it "as is") |
My point was about having possibility to skip |
Bypass formatting for statuses with no entity-body
Merged |
Can we close #1162? |
#1159 (OPTIONS) is definitely addressed here, but I recant my suggestion regarding #1157 (Redirects). The RFC suggests for entity bodies for
Do you think it would make sense for |
Another approach could be to set the content type explicitly inside def redirect(url, options = {})
# ...
header 'Location', url
header Grape::Http::Headers::CONTENT_TYPE, options.fetch(:content_type) { env[Grape::Env::API_FORMAT] }
body ''
end The downside is that of course that the burden is on the user if they support multiple serialization formats. In that case though, it could be as simple as: redirect(some_url, content_type: env[Grape::Env::API_FORMAT] In that case it might make sense for them to be able to override the body as well to ensure it is serializable. @dblock - do either of those suggestions strike you as appropriate? |
I am not sure. Redirect with content type seems strange to me. I think this discussion should be re-raised in a new issue either way. |
tl;dr;
Allow the formatter middleware to bypass serialization of response bodies when the status indicates there is no content.
Background
#1162 describes a scenario where
OPTIONS
requests and redirects can raise exceptions when content types are limited to those that don't consider''
as valid or are not prepared to handle it. The specific example given involved content types being limited (or set by default) to XML.''
is not consider to be valid XML and as such results in an error when serialization is attempted.A resolution was proposed to handle this in the formatters by checking the request method. It seems - and was suggested - that this opens up the scope of concern for the formatters too much and I agree. Additionally, it places a burden on all custom formatters to account for responses intended to have no content - like the OPTIONS request in question.
Process
I initially referenced the RFC to determine the best course of action, and found this:
This indicates that while the specification for a response body is not defined in the RFC, it is most certainly allowed given that the status code is
200
and should ideally be accounted for. This led me to begin ensuring thatOPTIONS
requests could be serialized appropriately by the formatter middleware, which led to ideas involving a special representation of no content that could be checked conditioned there.When thinking through this and beginning to write some tests, I found that I was unable to get the content type to persist in the response. This led me to Rack where I found this:
After some additional digging I found that
Rack::Lint
takes it a step further and does not consider a response to be valid if it has content information and it's status code is included inRack::Utils::STATUS_WITH_NO_ENTITY_BODY
.Proposal
Using these observations, my proposal here is to condition the formatter middleware to look for response statuses that indicate a content body in not appropriate and make the decision to bypass serialization.
This allows for both
OPTIONS
routes that return a200
with a serialized body based on normal content negotiation, and for the defaultOPTIONS
route that is auto-generated by the framework which returns a204
and no content and does add additional concerns to each default and custom formatter.Additionally, I believe this addresses the second issue in #1162 involving a similar issue with redirects.