-
Notifications
You must be signed in to change notification settings - Fork 130
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
handle-malformed raises exception when returning a map #94
Comments
This is a nasty gap in liberator. The context will not have a negotiated media type available until the decision point media-type-available? is executed. But there is a simple workaround: assoc the desired media-type in the context: (defresource someting |
Thanks for that. However, is there a way to do this assoc while still returning a boolean from EDIT: I figured it out, If I return a vector, the first entry being the boolean result of the decision and the second entry being the :representation map, then it all appears to work. My code as it stands now:
That's a pretty neat way of handling things, but not obvious until I tried it by chance. Thanks for the help :) |
I just hit this, and it applies to |
I'm having to include the :representation key in all my :malformed? decisions too, it'd be nice to have a cleaner way of expressing this. |
Any news on this? |
Is this supposed to be the expected behavior? Or should we expect this to be fixed in the near future? |
@ricardojmendez: It's always legal to provide a return value of this form, so you don't have to worry about this workaround being broken by a fix, if that's what you're asking. (The fix would be to negotiate an appropriate content-type for you in this case, making it optional to specify one, but still allowed.) |
Thanks @graue, I was indeed wondering if a future release would end up breaking this workaround. I can live with returning the content-type. |
@ShaneKilkelly thanks for the workaround! |
I found a slightly more "elegant" fix. Since I know my API will always return JSON, I can add the media type to (def base-resource
{:service-available? {:representation {:media-type "application/json"}
:handle-malformed {:error "malformed"}
:available-media-types ["application/json"]}
(defresource myresource
baseresource
:handle-ok {:status "OK"}) I'm not shooting myself in the face by doing this, right? |
@mveytsman Work-arounds are, by definition, sub-optimal. :) Some thoughts:
So, yes, I think you are shooting yourself in the foot, as well as anyone who reads the code. But I can't blame you for exploring work-arounds. |
@xpe you have good points here. Besides the need for a good solution for the overal problem, I was tinkering with the idea of having an What do you think? |
I think that's a great idea! @ordnungswidrig I take it you would accept a PR to that effect, or are these kinds of changes something you don't want to leave to contributors? Max
|
Would liberator.conneg/best-allowed-content-type be considered fairly stable to use as a workaround to set a representation in service-available (or (liberator.conneg/best-allowed-content-type ACCEPT-HEADER ["application/json" "application/transit+json;verbose"] ) "application/json" ) ? Cheers |
@zamaterian yes that's a possible workaround. I'm not sure, however, if the Vary header is set correctly if done naively. I was looking into something like that while working adding conneg support for "error" status codes but's it's not trivial if you want to support all the negotiable parameters. |
@zamaterian you can take the code in (defn negotiate-media-type [context]
(try-header "Accept"
(when-let [type (conneg/best-allowed-content-type
(get-in context [:request :headers "accept"])
((get-in context [:resource :available-media-types] (constantly "text/html")) context))]
{:representation {:media-type (conneg/stringify type)}}))) Liberator adds the Vary header according to the values at the key |
This is a pretty nasty bug, in an otherwise fantastic library. It seems to me that 'malformed?' simply comes too early in the decision graph. The malformed decision handler encourages the user to start poking around in the request body before the client and server have finished negotiating headers. Would it not make more sense for the server to tell the client either, "I do not know how to handle that incoming content type", or "I cannot produce any of these output types" before it starts inspecting the incoming body to see if it is a wellformed request?! I am currently using 'wrap-json-body' in my middleware which, sensibly, only touches the body if the content-type is application/json. However, because of this strange ordering in the decision graph, this means that my malformed handler has to be prepared to receive either a clojure map (when content-type is application/json) or a plain input stream (when it's not). I don't understand why this needs to be the case. Liberator should reject the latter requests upstream of my malformed decision function right? |
@wesleyhall http status 400 Bad Request indicates a request that is malformed on the HTTP syntax level. You won't encounter them in ring too often because the server adapter and ring were able to process the request and thus the request cannot be "too malformed". If you want to indicate that the request body ("entity" in http speak) is malformed you better use 422 unprocessable entity. The drawback is that that status code is not in the http spec (RFC 7231) but from WebDAV (RFC 4918). This explains why the (defresource foo ;; untested
:processable? (fn [_] {::msg "invalid json body"})
:handle-unprocessable-entity (fn [{msg ::msg}] (ring-response {:status 400} msg))) |
I agree with @xpe about not hijacking the :allowed? [true/false {:representation {:media-type "application/edn"}}]
:handle-forbidden {:message "Not allowed."}` |
When I try to return a map (json) from handle-malformed, the server crashes with the following exception:
The following code is an example:
If the handle-malformed function is replaced with a string, the code works and a plain text string is returned to the client, however this is not a workable solution as the api needs to consistently deal with json rather than sometimes returning plain text. :)
Seeing as other handle-xyz branches can return map data, I presume that handle-malformed should be able to do the same?
Tested on Ubuntu 13.10 , liberator 0.10.0 .
The text was updated successfully, but these errors were encountered: