common-lispspecial-variables

How do I set a response status code with caveman2?


I'm trying to create an endpoint that will send a status code using caveman2.

(defroute "/books/" ()
  (render-json "Hello"))

I have found the function throw-code which enables me to send a status code, but it won't let me send a response body as well. It seems it was meant for handling errors.

(import 'caveman2:throw-code)
    (defroute "/books/" ()
      (throw-code 403)
      ;; This will not respond with "Hello"
      (render-json "Hello"))

The caveman2 github page talks about responding with specific status codes:

Set HTTP headers or HTTP status

There are several special variables available during a HTTP request. request and response represent a request and a response. If you are familiar with Clack, these are instances of subclasses of Clack.Request and Clack.Response.

(use-package :caveman2)

;; Get a value of Referer header.
(http-referer *request*)

;; Set Content-Type header.
(setf (getf (response-headers *response*) :content-type) "application/json")

;; Set HTTP status.
(setf (status *response*) 304)

However, I do not know how to instantiate these objects or how to import them. I couldn't find a working example and when I put this in as is in my code it won't compile.

How can I accomplish this?


Solution

  • The *response* variable is bound to an instance while the request is being processed (it is a special variable). You can experiment with the following short example:

    You need these systems:

    (ql:quickload '(:clack :caveman2))
    

    Then:

    (defpackage :test-caveman2 (:use :cl))
    (in-package :test-caveman2)
    
    
    (defparameter *web* (make-instance 'caveman2:<app>))
    
    (caveman2:defroute "/hello/" ()
      "Hello")
    
    (defparameter *server* (clack:clackup *web*))
    

    With the above code executed, you should be able to see a simple Hello page at address localhost:5000/hello/

    Now, let's make a page with a body but a different status:

    (caveman2:defroute "/bye/" ()
      ;; here *response* is bound to a response object
      ;; let's change its status
      (setf (caveman2:response-status caveman2:*response*) 403)
      "403 - Nope")
    

    If you inspect with your browser, e.g. F12 in Firefox, the Network tab, you can see that the response status is 403 for /bye/, but that the page displays also a body.