pricks
pricks

Reputation: 371

How to catch parse errors in Lucerne (common lisp)

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.

stack trace

Edit: Added start information

Edit: Added stack trace

Upvotes: 3

Views: 243

Answers (2)

coredump
coredump

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.

Explanation

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.

Solution

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

user5920214
user5920214

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

Related Questions