-
-
Notifications
You must be signed in to change notification settings - Fork 94
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
Error handling when server sends invalid json #110
Comments
@bsteuber I think this is still the best default behaviour. I think we should do the same here as clj-http. Note, that you can always, build your own custom HTTP client by choosing the needed middleware. Take a look here: |
In my case I get an exception thrown, which I mind a little, but my Problem is that I don't know how to catch it. (defn testex []
(go
(let [response (<! (try (http/get "http://localhost:3000/sim/error" {:with-credentials? false})
(catch :default e
(println "error" e))))]
(println response)))) The URL returns HTTP 500 with content-type "application/json" and not a json body. What would be the correct approach here? Here's the stacktrace:
|
I just hit this too. @r0man I have to say I'm confused why you think this is the best default behavior. If cljs-http gets bad json from the server, what it does right now is print a stack trace to the console, which, of course, is shorn of any context so it's impossible to tell what line of calling code even caused the problem. This is baffling since cljs-http already has an error reporting mechanism. Why not just catch exceptions and report them through the error mechanism? I also don't even begin to understand how that piece of code could help calling code. Are you suggesting that we just fork cljs-http? |
try-catch could be added on Changing this would cause response to be returned (with empty body) when body can't be decoded. |
I'm probably missing something, but right now, if you hit this bug, the entire state machine vaporizes and it never returns. So whatever you do, it surely has to be better than that. You can't break any calling code in this code path because (I think) it never returns to the calling code. |
Yes, that's the thing. Because currently response is never returned, current user code probably isn't prepared to check if the returned body was decoded successfully. Returning response without decoded body might break code which isn't prepared for these responses. |
Maybe it would make sense to return response with status 0, like:
Status code 0 would probably enable most existing code to handle these responses as error. I think e.g. Chrome uses status code 0 already in some cases (request timeout, CORS). |
Another option would be to use something like this: http://swannodette.github.io/2013/08/31/asynchronous-error-handling @jmlsf I don't have time to work on this myself at the moment, so a patch is very welcome. No need to fork this, just talk to me. I'm open to suggestions. ;) |
I believe the problem is here: (defn wrap-json-response
"Decode application/json responses."
[client]
(fn [request]
(-> #(decode-body % util/json-decode "application/json" (:request-method request))
(async/map [(client request)])))) The issue is that I think the way to fix this is to change (defn decode-body
"Decocde the :body of `response` with `decode-fn` if the content type matches."
[response decode-fn content-type request-method]
(try
(if (and (not= :head request-method)
(not= 204 (:status response))
(re-find (re-pattern (str "(?i)" (escape-special content-type)))
(str (clojure.core/get (:headers response) "content-type" ""))))
(update-in response [:body] decode-fn)
response)
(catch e
(merge response
{:status 0
:success false
:error-code :bad-response-body
:error e
:original-status (:status response)})))) The alternative is to push the exception on the channel instead of the call to I should point out I'm happy to try my hand at a PR, but I wanted to see if I was barking up the wrong tree first. |
@jmlsf @Deraen Yes, I suggested going with However, I'm open to anything. What kind of API would you prefer as the user of this lib? I'm asking because I actually don't use this lib much at the moment myself, and wonder if all those keys you have to check are not a bit overwhelming.
|
I think my two goals are (1) provide a programatic way to deal with errors and (2) make it debuggable. Dealing with 2 is fairly easy: as long as you communicate the error in some way, either by returning a status object or throwing an exception. But dealing with (1) requires that we catch exceptions where they occur in the middleware and assign and document error codes (i.e., If we were allowed to break the interface, I think the conventions around One thing that's nice about using an error object to indicate failure is that you don't have to have I do like the idea of trying to isolate anything that is known to throw an error (like JSON.parse) and assigning (and documenting) an error code for it. |
@jmlsf I think |
Sorry you are right of course. At a minimum people will need the status code. |
I hit what I believe is the same problem when decoding EDN with an unsupported type: "No reader function for tag ordered/set." |
@kanaka Custom EDN readers are not supported yet I think. We need something similiar to: |
@r0man custom readers would be great but my more immediate concern was that there doesn't appear to be a way to cleanly catch invalid/unsupported data so that it can be reported properly to the user. |
@kanaka Yes, that is still an issue. I think we need something what I described here: |
I am calling
(http/get "http://api.icndb.com/jokes/22")
which interestingly delivers a php error message, but with a header including content-type application/json and status 200. Of course it is a server issue, but it would be nice if cljs-http could return an error here so I can handle it somehow instead of just failing.
The text was updated successfully, but these errors were encountered: