I'm working on my shopping app and I'm trying to make a custom exception handler, but there's something else that's catching them before I get to them!
Here is my handler
(defn wrap-fallback-exception
[handler]
(fn [request]
(try+
(handler request)
(catch [:type :test] {:keys [msg]}
(println "## Test Exception:" msg))
(catch Exception e (println "## Exception"))
(catch Throwable e
(println "## Throwable:" (.getMessage e) e)))))
Here is my stack
(-> all-routes
(wrap-anti-forgery)
(friend/authenticate {
:unauthorized-handler unauth-handler
:credential-fn (partial cred get-user)
:workflows [(workflows/interactive-form)]})
(wrap-session {:store (->ShopStore )})
(wrap-keyword-params)
(wrap-params)
(wrap-cookies)
(wrap-fallback-exception)
(run-server {:port 3000}))
I trow a test in one of my ring functions
(throw+ (ex-info "TEST" {:type :test}))
And the resulting output looks like this
Sun Apr 01 15:57:29 CEST 2018 [worker-4] ERROR - GET /user/home
clojure.lang.ExceptionInfo: TEST {:type :test}
at clojure.core$ex_info.invokeStatic(core.clj:4739)
at clojure.core$ex_info.invoke(core.clj:4739)
at shop2.views.home$mk_proj_row.invokeStatic(home.clj:90)
at shop2.views.home$mk_proj_row.invoke(home.clj:88)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.AFn.applyTo(AFn.java:144)
at orchestra.spec.test$spec_checking_fn$fn__1372.doInvoke(test.clj:123)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$map$fn__5587.invoke(core.clj:2747)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:528)
at clojure.core$seq__5124.invokeStatic(core.clj:137)
at clojure.core$print_sequential.invokeStatic(core_print.clj:53)
at clojure.core$fn__7019.invokeStatic(core_print.clj:174)
at clojure.core$fn__7019.invoke(core_print.clj:174)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at clojure.core$pr_on.invokeStatic(core.clj:3666)
at clojure.core$pr_on.invoke(core.clj:3660)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$fn__7039.invokeStatic(core_print.clj:225)
at clojure.core$fn__7039.invoke(core_print.clj:225)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at clojure.core$pr_on.invokeStatic(core.clj:3666)
at clojure.core$pr_on.invoke(core.clj:3660)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$fn__7039.invokeStatic(core_print.clj:225)
at clojure.core$fn__7039.invoke(core_print.clj:225)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at clojure.core$pr_on.invokeStatic(core.clj:3666)
at clojure.core$pr_on.invoke(core.clj:3660)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$fn__7039.invokeStatic(core_print.clj:225)
at clojure.core$fn__7039.invoke(core_print.clj:225)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at clojure.core$pr_on.invokeStatic(core.clj:3666)
at clojure.core$pr_on.invoke(core.clj:3660)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$fn__7019.invokeStatic(core_print.clj:174)
at clojure.core$fn__7019.invoke(core_print.clj:174)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at clojure.core$pr_on.invokeStatic(core.clj:3666)
at clojure.core$pr_on.invoke(core.clj:3660)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$fn__7019.invokeStatic(core_print.clj:174)
at clojure.core$fn__7019.invoke(core_print.clj:174)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at clojure.core$pr_on.invokeStatic(core.clj:3666)
at clojure.core$pr_on.invoke(core.clj:3660)
at clojure.core$print_sequential.invokeStatic(core_print.clj:66)
at clojure.core$fn__7039.invokeStatic(core_print.clj:225)
at clojure.core$fn__7039.invoke(core_print.clj:225)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at clojure.core$pr_on.invokeStatic(core.clj:3666)
at clojure.core$pr_on.invoke(core.clj:3660)
at clojure.lang.Var.invoke(Var.java:385)
at clojure.lang.RT.print(RT.java:1877)
at clojure.lang.RT.printString(RT.java:1857)
at clojure.lang.APersistentVector.toString(APersistentVector.java:26)
at org.httpkit.HttpUtils.bodyBuffer(HttpUtils.java:112)
at org.httpkit.HttpUtils.HttpEncode(HttpUtils.java:442)
at org.httpkit.server.HttpHandler.run(RingHandler.java:101)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
The exception is never caught by my handler!
I've tried every version I can think of with no luck :-(
Who is catching it?
And how do I make it stop?
Regards
Soren
Your handler returns successfully, without throwing an exception. The value that it returns is, apparently, a many-levels-deep vector containing, buried deep within itself, a lazy sequence. When Ring tries to print that lazy sequence, forcing that sequence calls mk-proj-row, which throws an exception. Importantly, this happens after your handler has completely finished running, meaning the exception handler is no longer in effect.
I doubt you really want to be stringifying a giant vector as your output: my guess is you forgot to use Hiccup to convert that to HTML, or something else to convert it to JSON. You should probably have some middleware installed which does that conversion before returning to Ring; if you put that middleware before your wrap-fallback-exception middleware, then the laziness will no longer be a problem, because the lazy sequence will be realized inside of the Hiccup (or whatever) renderer, rather than by Ring after all your handlers have finished.
Related
I am trying to use uber/react-map-gl with Clojurescript. I have added it the project.clj-
:npm-deps {"#cljs-oss/module-deps" "^1.1.1"
:react-map-gl "^3.3.0-alpha.5"
:react "^16.4.1"}
and npm installed it separately. When I require it from my ns -
(:require [react-map-gl :as M
:refer [BaseControl TRANSITION_EVENTS
FlyToInterpolator]])
(js/console.log M)
(js/console.log BaseControl)
(js/console.log M/BaseControl) ;;-> also fails
M is correctly logged to the console, but drilling into the attributes (such as BaseControl) throws an Exception -
Exception: ReferenceError:
...$node_modules$react_map_gl$dist$esm$components$base_control is not defined at Object.get BaseControl [as BaseControl] (http://localhost:3449/js/compiled/out/node_modules/react-map-gl/dist/esm/index.js:5:19) at Object.remoteFunction (<anonymous>:2:14)]
A handful of the attributes are accessible (e.g. no exceptions), such as TRANSITION_EVENTS and FlyToInterpolator.
I see this bug (which may or may not be relevant), but I am not sure how to proceed or even troubleshoot. Here's a minimal failing example to repro. Any help would be appreciated.
This is not an answer (really just a comment).
I was able to ostensibly get farther by first manually requiring all of the components and overlays (which points to some deps mismanagement of some sort).
$ clj -m cljs.main -co compile-opts.edn -r
ClojureScript 1.10.339
cljs.user=> (require '"react-map-gl/dist/esm/components/popup"
'"react-map-gl/dist/esm/components/navigation-control"
'"react-map-gl/dist/esm/components/interactive-map"
'"react-map-gl/dist/esm/components/base-control"
'"react-map-gl/dist/esm/components/static-map"
'"react-map-gl/dist/esm/components/marker"
'"react-map-gl/dist/esm/overlays/svg-overlay"
'"react-map-gl/dist/esm/overlays/html-overlay"
'"react-map-gl/dist/esm/overlays/canvas-overlay"
'[react-map-gl :as M
:refer [BaseControl TRANSITION_EVENTS
FlyToInterpolator]])
cljs.user=> M
#js {:default nil, :InteractiveMap nil, :StaticMap nil, :BaseControl nil, :Marker nil, :Popup nil, :NavigationControl nil, :CanvasOverlay nil, :HTMLOverlay nil, :SVGOverlay nil, :TRANSITION_EVENTS #js {:BREAK 1, :SNAP_TO_END 2, :IGNORE 3}, :TransitionInterpolator #object[TransitionInterpolator], :LinearInterpolator #object[LinearInterpolator], :FlyToInterpolator #object[ViewportFlyToInterpolator], :experimental #js {:MapControls #object[MapControls]}}
You can see that, while this avoids the ...$node_modules$react_map_gl$dist$esm$components$base_control is not defined error, it is not really a solution as things like :BaseControl end up being nil.
You can get a sense of the dependencies at play by making a revision to the compiler to log the results of calls to cljs.closure/index-node-modules.
My deps.edn:
{:deps {org.clojure/clojurescript {:mvn/version "1.10.339"}}}
and compile-opts.edn:
{:npm-deps {:react-map-gl "^3.3.0-alpha.5"
:react "^16.4.1"}
:install-deps true
:output-dir "out"}
I'm playing around with Pharo, and would like to raise a customized error/exception/something, but I've got no idea how.
I've browsed the relevant (I think) chapters of "Pharo by Example" and "Deep into Pharo"; but couldn't make heads or tails about it - it seems way above the level that I need...
I've got a setter for a variable, and would like to raise an error/exception if the input isn't an Integer:
MyClass >> someVariable: anInteger
anInteger isInteger
ifFalse: [ self SomehowProtestLoadly - the part I don't know how to do ].
someVariable := anInteger
Just aborting or exiting would be sufficient... but if possible, I'd like to do it with a bit more "flare" - and in a more explainatory way...
The easiest way is to just signal a generic error:
someVariable: anInteger
anInteger isInteger
ifFalse: [self error: 'must be an Integer'].
someVariable := anInteger
Now, if you want to signal a specific error, do the following:
Create a subclass of Error, say, NonIntegerArgument
Write your code like this
someVariable: anInteger
anInteger isInteger
ifFalse: [NonIntegerArgument signal: 'must be an Integer'].
someVariable := anInteger
For handling this exception do the following
[myObject someVariable: self value]
on: NonIntegerArgument
do: [:ex | self handleException: ex]
Note that your exception could provide more information, say the actual argument that was sent. To do this add an instance variable to your NonIntegerArgument class, namely, argument. Add a getter and a setter for it. Then
NonIntegerArgument class >> #signal: aString argument: anObject
^self new
argument: anObject;
signal: aString
and use it this way
someVariable: anInteger
anInteger isInteger
ifFalse: [
NonIntegerArgument
signal: 'must be an Integer'
argument: anInteger].
someVariable := anInteger
Now, the ex variable will be able to respond with the argument of the offending message.
Does anybody understand the following behavior inside a ClojureScript browser repl? (provided by the boot tool chain)
my.core> (require 'cljs.pprint)
nil
my.core> (cljs.pprint/pprint "one")
#object[TypeError TypeError: cljs.pprint is undefined]
No stacktrace available.
my.core> (cljs.pprint/pprint "one" "two" "three")
WARNING: Wrong number of args (3) passed to cljs.pprint/pprint at line 1 <cljs repl>
#object[TypeError TypeError: cljs.pprint is undefined]
No stacktrace available.
It looks, that there is no reference to cljs.pprint/pprint, however the repl knows about the arity of this function.
this might help as well:
my.core> (cljs.repl/dir cljs.pprint)
t_cljs$pprint28171
t_cljs$pprint28177
with-pprint-dispatch
with-pretty-writer
write
write-out
nil
cider-repl-toggle-pretty-printing did the trick.
I'm trying to handle exceptions with Dire library. Like this:
(defn test-fn []
(client/head "https://google.com/404")
)
(with-handler! #'test-fn
java.lang.Exception
(fn [e] "error!"))
But always got an error:
ExceptionInfo clj-http: status 404 clj-http.client/wrap-exceptions/fn--3052 (client.clj:196)
I've tried to change java.lang.Exception to clojure.lang.ExceptionInfo with same effect. Did I miss something?
clj-http uses Slingshot apparently, cf. clj-http documentation on exceptions. The throw+ operation of Slingshot can throw any kind of object, not just exceptions (Throwables). The clj-http documentation has an example:
; Response map is thrown as exception obj.
; We filter out by status codes
(try+
(client/get "http://some-site.com/broken")
(catch [:status 403] {:keys [request-time headers body]}
(log/warn "403" request-time headers))
(catch [:status 404] {:keys [request-time headers body]}
(log/warn "NOT Found 404" request-time headers body))
(catch Object _
(log/error (:throwable &throw-context) "unexpected error")
(throw+)))
Furthermore, the Dire documentation has an example of how to integrate with Slingshot: basically you should be able to drop [:status 404] instead of the java.lang.Exception.
I have a rather simple problem I thought. I have a luminus web project with clojurescript and cljs-ajax. What I do is an ajax request to my server and in my error-handler I want to parse a json string to display a specific error message. I just cannot get it working.
This is my code:
Clojurescript:
(defn error-handler [response]
(js/alert (aget response "message")))
; (js/alert (:message response ))) neither works here
(defn test-connection []
(POST "/url"
{:params (get-form-data)
:response-format :json
:handler succ-handler
:error-handler error-handler}))
And my serverside code:
(defn connect-jira []
{:body {:message "No connection to JIRA. Please check your details."}}
)
(defroutes jira-routes
(POST "url" []
(connect-jira)))
What is the idiomatic way to return a custom error message and parse that with clojurescript?
Update
I tracked my problem down some more. There is a difference between the success and the error handler of the POST request. Lets say my server side looks like this:
(defn connect-jira []
{:status 200 :body {:message "No connection to JIRA. Please check your details."}})
And my success handler like this:
(defn succ-handler [{:keys [message]}]
(.log js/console message))
Then its all fine, the correct messages is logged to the console.
But if my server side looks like this (different statu):
(defn connect-jira []
{:status 500 :body {:message "No connection to JIRA. Please check your details."}})
I call the error handler on cljs side
(defn err-handler [{:keys [message]}]
(.log js/console message))
But the message is "null"
I also tried to overwrite the status-text on server side, but did not succeed. So, how do I pass a message to the error handler from server side?
Are you using this library for your AJAX calls?
https://github.com/yogthos/cljs-ajax
If so, your error handler would need to look something more like this:
(defn err-handler [{:keys [response]}]
(.log js/console (:message response)))