pedestal

2025-01-25T13:51:18.186749Z

First time using pedastal and having a rather fundamental issue which I can't get working properly. Based on this: http://pedestal.io/pedestal/0.6/guides/hello-world-content-types.html, I want to have a different content in the response based on the content negotation. The content negotation seems to fail (I'm trying to make the interceptors global, not route-specific). With this code:

(def routes
  (route/expand-routes
   #{["/api/hello" :get respond-hello :route-name :hello]}))

(def debug-content-negotiation
  {:name ::debug-content-negotiation
   :enter
   (fn [context]
     (println "Before negotiation: " (:request context))
     context)})


(def service
  (http/create-server
   {::http/routes routes
    ::http/type :jetty
    ::http/port 8080
    }))
I do get the expected output (`Hello, world!`).
curl -i -H "Accept: text/html" 

HTTP/1.1 200 OK
Date: Sat, 25 Jan 2025 14:00:11 GMT
Strict-Transport-Security: max-age=31536000; includeSubdomains
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Content-Security-Policy: object-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
Content-Type: text/plain
Transfer-Encoding: chunked

Hello, world!
With a debug-content-negotiation interceptor:
(def debug-content-negotiation
  {:name ::debug-content-negotiation
   :enter
   (fn [context]
     (println "Before negotiation: " (:request context))
     context)})


(def service
  (http/create-server
   {::http/routes routes
    ::http/type :jetty
    ::http/port 8080
    ::http/interceptors       [debug-content-negotiation]
    }))
I do get an empty result:
curl -i -H "Accept: text/html" 

HTTP/1.1 200 OK
Date: Sat, 25 Jan 2025 14:02:53 GMT
Content-Length: 0
When activating the content negotation:
(def service
  (http/create-server
   {::http/routes routes
    ::http/type :jetty
    ::http/port 8080
    ::http/interceptors       [(content-negotiation/negotiate-content supported-types)]
    }))
I get an internal server error:
curl -i -H "Accept: text/html" 

HTTP/1.1 500 Server Error
Date: Sat, 25 Jan 2025 13:49:19 GMT
Content-Type: text/plain
Transfer-Encoding: chunked

Internal server error: no response
What I expect to happen is that the enter-functions of the global interceptors are executed (as long as there's on response in the context), the function of the get of the hello route is executed (generating a body) and than the interceptor leave-functions are executed (in reverse order). I don't really understand where the 'no response' is coming from. It seems, when I add interceptors, the response-hello function isn't executed for some reason. What do I miss?

2025-01-25T17:45:16.303709Z

Did you read this: http://pedestal.io/pedestal/0.6/reference/default-interceptors.html There is a big difference between omitting the interceptors key and specifying one

2025-01-25T18:14:17.729889Z

I didn't read it, but now I did. However, I still fail to see how to make it work. I now add interceptors by using the 'update' (which makes sense, so now I still have the default ones as well). When I do that, I still have the same issue: I get an empty result whenever I add interceptors.

(def debug-content-negotiation
  {:name ::debug-content-negotiation
   :enter
   (fn [context]
     (println "Before negotiation: " (:request context))
     context)})

(def service-map
  (->
   {::http/routes routes
    ::http/type :jetty
    ::http/port 8008}
   (http/default-interceptors)
   (update ::http/interceptors conj debug-content-negotiation)))


(defn start []
  (-> service-map
      http/create-server
      http/start))
gives:
$ curl -i 

HTTP/1.1 200 OK
Date: Sat, 25 Jan 2025 18:06:34 GMT
Content-Length: 0
If I don't add the interceptors, all works fine:
(def service-map
  (->
   {::http/routes routes
    ::http/type :jetty
    ::http/port 8008}
    (http/default-interceptors)
   ))


(defn start []
  (-> service-map
      http/create-server
      http/start))
this works fine:
curl -i 

HTTP/1.1 200 OK
Date: Sat, 25 Jan 2025 18:10:08 GMT
Strict-Transport-Security: max-age=31536000; includeSubdomains
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Content-Security-Policy: object-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
Content-Type: text/plain
Transfer-Encoding: chunked

Hello, world!
Thx!

2025-01-25T18:39:47.984389Z

oh crap, nvm, got it, need to pass the interceptor map to the interceptor function so I create an interceptor record. problem solved 🙂.

1