I couldn't find any documentation on how to dispatch based on HTTP method (on the same uri). The closest I got was :default-request-type
on the define-easy-handler
-- but it seems to dispatch to the latter, even though I use GET method:
(define-easy-handler (index :uri "/" :default-request-type :get) ()
(log-message* :info "GET on index ------ ")
(format nil "Hello World"))
(define-easy-handler (echo :uri "/" :default-request-type :post) ()
(log-message* :info "POST on index ------ ")
(format nil "~S" (raw-post-data :force-text t)))
The (perhaps slightly deceptively named) :uri
parameter is allowed to be either a string or a predicate on the request object. So, you can pass a function there that checks if the method and path match. I wrote a macro to make it prettier:
(defmacro method-path (methods path)
"Expands to a predicate the returns true of the Hunchtoot request
has a SCRIPT-NAME matching the PATH and METHOD in the list of METHODS.
You may pass a single method as a designator for the list containing
only that method."
(declare
(type (or keyword list) methods)
(type string path))
`(lambda (request)
(and (member (hunchentoot:request-method* request)
,(if (keywordp methods)
`'(,methods)
`',methods))
(string= (hunchentoot:script-name* request)
,path))))
(hunchentoot:define-easy-handler (get-handler :uri (method-path :get "/hello")) ()
"hello!")
(hunchentoot:define-easy-handler (post-handler :uri (method-path (:post :put) "/hello")) ()
"a post or a put!")
In the case where the path is found but the method isn't, we should probably return an HTTP 405 error instead of the 404 error that Hunchentoot returns when no handlers match. In order to do this, you could manually write a catch-all handler for every path you define. The 405 response is supposed to include a list of acceptable methods, and I can't think of an easy way to generate one short of modifying define-easy-handler
to support specialization on method directly, which might be a good idea.
Many frameworks built on top of hunchentoot have that. Restas and Caveman are just two examples. For example in Restas you can say:
(restas:define-route foo ("/foo" :method :get)
; some code here
)
(restas:define-route foo/post ("/foo" :method :post)
; some other code here
)
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