Fork me on GitHub
#pedestal
<
2017-05-01
>
bradford03:05:05

How do I disable secure-headers middleware? this does not seem to do it:

(def service {:env prod :io.pedestal.http/secure=-headers nil ::http/routes routes ::http/type :jetty ::http/port 8080} 

danielcompton03:05:23

:io.pedestal.http/secure=-headers -> :io.pedestal.http/secure-headers?

deg10:05:59

I either have a typo that I can't see, or I misunderstand how Pedestal interceptors work. I have an interceptor that modifies Vase query results to return them as a cvs string, rather than as a data structure. It gets back to my client as the raw string, rather than as the transit that the client expects. It looks like the problem is that modifying the context's :result in an interceptor somehow interrupts the interceptor chain, causing remaining interceptors not to run. In this code, including the update-in (rather than merely returning context) causes trace-context not to trigger, and returns the raw string generated by my csv function. What am I doing wrong? If it's a typo, I sure can't see it. If it is not legal to modify :response, then how do I generate results?

;;; From .edn file

                "/csv-history" {:get [<#C49BSM9B3|vase>/query {:name :receipts-server.v1/csv-history-get
                                                   :query [:find [(pull ?e [*]) ...]
                                                           :where [?e :purchase/uid]]
                                                   :to :receipts/raw-history}
                                      receipts-server.interceptors/generate-csv
                                      receipts-server.interceptors/trace-context]}

;;; From .clj file
(def generate-csv
  (i/interceptor
   {:name ::generate-csv
    :enter (fn [context]
             (log/info :msg (str "**** 2 enter = " (:receipts/raw-history context)))
             (log/info :msg (str "2 CONTEXT: " context))
             (update-in context [:response] assoc
                        :body    (csv (:receipts/raw-history context))
                        :headers {}
                        :status  200))
    :leave (fn [context]
             (log/info :msg (str "GEN-CSV LEAVE: " (:response context)))
              context)}))

(def trace-context
  (i/interceptor
   {:name ::trace-context
    :enter (fn [context]
             (log/info :msg (str "TRACE ENTER: " (:response context)))
             context)
    :leave (fn [context]
             (log/info :msg (str "TRACE LEAVE: " (:response context)))
             context)}))

malch12:05:28

@deg try assigning :response inside the :leave function

deg12:05:32

Thanks, I'll try that right now. But (despite having read that doc a few times) I don't see that requirement. (The only hint I see is the last line of the doc "Because a handler takes one kind of thing (request) and returns a different kind of thing (response), it can only be used in the last position of a stack.") What is the underlying logic that prevents assigning :response in the :enter?

malch12:05:35

I don’t know that logic exactly but I’m guessing that :response acts like a result in a web stack

malch12:05:22

Actually that makes sense - you should assoc :response inside the last interceptor of your stack (it’s :leave function) and only update it inside other interceptors

deg12:05:57

I'm not familiar with how a result acts in a web stack, but I guess that some mechanism looks for the existence of :response and aborts calling the :leave queue if a response already exists? In any event, you are obviously correct. That change solved half my problem. As expected, I now see calls to generate-csv/enter, trace-context/enter, trace-context/leave, and generate-csv/leave. All good so far. But, my client is still receiving the text/plain result, rather than the correct transit results. My guess is that I'm putting the wrong thing in response. Maybe I'm not supposed to supply the headers and status? Or maybe just give the body without any map wrapping it?

deg12:05:40

Ugh, I think I found what's going on... https://github.com/pedestal/pedestal/blob/master/service/src/io/pedestal/http.clj#L150 Looks like the body is only converted to Transit if it is a collection, not a string! Why?

deg12:05:14

Yup, that was it! I wrapped my body in {:cvs ...} and I'm good now.

deg12:05:40

So, questions for the gurus: - Why does Pedestal not allow a bare string to be passed back via transit? - Should Interceptors be better documented, explaining how and when to return a response? Where? In the Vase docs, or Pedestal, or both?

rauh12:05:20

@deg a string isn't valid JSON. Need to be either an (JS) array or a (JS) map.

deg12:05:08

Is that true of Transit too? I've seen that the transit library will happily take a bare string.

deg12:05:37

There is even an example of this in readme of the transit library https://github.com/cognitect/transit-clj

deg12:05:22

Ah, but this is transit+json, so I guess it uses json as bearer and needs to be valid json too?

rauh13:05:01

@deg the transit interceptor checks with (coll? body) so that's the problem. Though, it seems the updated JSON RFC also does allow single strings now.

rauh13:05:29

So you could do it by just setting the Content-Type header yourself.

deg13:05:43

Yup, the coll? check is the imediate problem. My question was why code was there.

rauh13:05:38

Oh you linked the coll? check yourself. Didn't click the link 🙂

deg13:05:09

It was easier just to wrap my result in a map, than to change the Content-Type. The latter would have meant playing with cljs-ajax to figure out what make it happy. Its handling of random content-types is somewhat, umm, random.

rauh13:05:20

FWIF I don't see the point of the cljs-ajax library. 😕

deg13:05:55

I use re-frame/http-fx, which depends on it.

deg13:05:40

And the re-frame stuff is nice enough, that I'm generally happy to put up with its opinionation. (if that's a word 🙂 )

deg13:05:53

Of course, that cost me too much time today, so...

rauh13:05:31

Yeah not sure I'd wanna lock myself into using a http-fx library. What about retries, offline queuing etc?

deg13:05:32

Dunno yet. I'm still writing toy code, mostly for the sake of exploring Vase + Pedestal + re-frame + ...

malch13:05:11

@rauh Is there a cljs library that provides retries and offline queuing?

rauh13:05:35

@malch there is goog.net.XhrManager but detecting if the browser if offline is difficult. I think there is a few JS libs

malch13:05:03

@rauh Thanks, will take a look myself simple_smile