I find that incremental development tends to break when coding for Hunchentoot.
For example, I might write a web page that is composed of a few functions. If one of these inner functions contains a call to - say - hunchentoot:post-parameters* then I can't easily test the function in the REPL. It'll error out because *request* doesn't exist unless the page is called by a web client.
It would be nice if some function-or-other-source existed such that I could test my-function thus:
>(let* ((*request* (get-previous-request-from-somewhere))
(*session* (slot-value *request* 'hunchentoot:session)))
(my-function <whatever params>))
Does it or something similar exist? Am I overlooking a better approach to debugging?
My interim solution looks something like this:
(defparameter *save-last-request* t)
(defvar *last-request* nil)
(defun store-request ()
(when *save-last-request*
(setf *last-request* *request*)))
(defmacro with-last-request (&body body)
`(let* ((*request* *last-request*)
(*session* (slot-value *request* 'hunchentoot:session)))
,@body))
It works fine with the caveat that each handler needs to make a call to store-request
.
I think the simplest thing to do might be to use a custom request class that introduces a way to persist requests somewhere into the initializer chain.
Here's a trivial example of one approach. A custom subclass of request which saves it's state, in a global stack.
You can set your acceptors to use custom request-classes using
(setf (acceptor-request-class acceptor ) new-value)
so something like this
(defparameter *requests* nil)
(defclass my-request (hunchentoot:request) ())
(defmethod initialize-instance :after ((req my-request) &key)
(push req *requests*))
and then set the acceptor request class to use this when you make your acceptor e.g.
(setf (hunchentoot:acceptor-request-class
(make-instance 'hunchentoot:easy-acceptor)) 'my-request)
Every time a request is created by this acceptor to pass to the handler, it will be added to the *requests*
list.
if you use a variable to specify the request class name you could toggle this class on and off for development/debugging.
You could then take requests from this stack in your test binding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With