Reputation: 371
I'm trying to build a simple rest api in Lucerne, but the clack:call method fails if the json is malformed. So, I extended the bass-app class and added an around method:
(defclass tracker-app (base-app) ()
(:documentation "An extension of lucerne's base app to control behavior"))
(defmethod clack:call :around ((app tracker-app) env)
(handler-case (call-next-method)
(fast-http:cb-message-complete (e)
(vom:error "could not build message body: ~a" e)
(respond nil :status 400))
(:no-error (res) res)))
(defapp server :class 'tracker-app)
(start server :server woo)
But the parse error continues to crash the server.
I don't know much about clos, so I'm worried I've misunderstood how to catch errors in this context.
Edit: Added start information
Edit: Added stack trace
Upvotes: 3
Views: 243
Reputation: 38924
Assuming *features*
does not contain :catch-any-error
, here is a complete test case:
(ql:quickload :lucerne)
(defpackage :so.lucerne (:use :cl :lucerne))
(in-package :so.lucerne)
(defclass tracker-app (base-app) ()
(:documentation "An extension of lucerne's base app to control behavior"))
(defmethod clack:call :around ((app tracker-app) env)
(handler-case (call-next-method)
(fast-http:cb-message-complete (e)
(warn "could not build message body: ~a" e)
(respond nil :status 400))
#+catch-any-error
(error (e) (break "BREAK with ~a" e))
(:no-error (res) res)))
(defmethod clack:call ((app tracker-app) env)
(error "Oh No"))
(defapp server :class 'tracker-app)
(start server :server :woo)
When I try to load localhost:8000
, the following error is shown:
Callback Error: the message-complete callback failed
Oh No
[Condition of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE]
Pressing Enter on [Condition of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE]
gives:
#<FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE {10048315C3}>
--------------------
The object is a CONDITION of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE.
FORMAT-CONTROL: NIL
FORMAT-ARGUMENTS: NIL
DESCRIPTION: "the message-complete callback failed"
ERROR: #<SIMPLE-ERROR "Oh No" {1004831583}>
The error wraps another error.
Now if I (push :catch-any-error *features*)
and recompile the above method, the same test makes the code reach the (break ...)
statement, which is shown as BREAK with Oh No
.
No fast-http:cb-message-complete
is caught, and in fact no such condition is signaled at this point; instead at this location we only can catch the specific error that was signaled. It is only higher up in the call stack that errors are wrapped inside fast-http:cb-message-complete
errors.
In your case you can directly catch jonathan.error:<jonathan-error>
(unusual naming convention, but ok), the base class of all errors in the jonathan
library (you could catch the specific error type, but then you risk missing some other cases).
Upvotes: 2
Reputation:
[This answer is wrong: fast-http.error:cb-message-complete
& fast-http:cb-message-complete
seem to be the same symbol. I am leaving it here for posterity.]
You are not handling the right condition (and in fact I'm not sure you're handling a condition which exists at all, which I'd expect the system to have warned about perhaps, although perhaps it can't).
You need to handle fast-http.error:cb-message-complete
, but your handler specifies fast-http:cb-message-complete
. The first of these is a condition (defined here, while the second is I think implicitly define here and is not a condition but the name of a function I think.
A more general trick is to try to handle some much-too-general error: you will probably end up handling things you don't know how to handle, but if your handler gets invoked you know that the call stack looks like you think it does when the error is signalled. Then you can start handling the errors you actually care about. In this case that probably means fast-http.error:callback-error
I think.
Upvotes: 0