4

When I try and request a resource from a cljs app (running on http://localhost:3000) to my Pedestal server (running on http://localhost:8080) I get the below error. I would like to allow CORS from http://localhost:3000:

XMLHttpRequest cannot load http://localhost:8080/db/query. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

I am using cljs-http to send the request from the client. The request looks something like this:

(defn load-server-data
  []
  (go
    (let [q (<! (http/post "http://localhost:8080/db/query"
                           {:edn-params {:query '[:find ?rep ?last
                                                  :where
                                                  [?rep :sales-rep/first-name ?last]]}}))]
      (println "q" q))))

The route for /db/query looks like this:

(defroutes routes
           [[["/db"
              {:post handlers/db-post}
              ["/query" {:post handlers/db-query}
               ^:interceptors [interceptors/edn-interceptor]]]]])

This is the handler for /db/query:

(defn db-query
  [req]
  (let [edn-params (:edn-params req)
        q (:query edn-params)
        args (:args edn-params)
        q-result (apply d/q q (d/db conn) args)]
    {:status 200
     :body   (pr-str q-result)}))

To run the server I execute this function in the REPL.

(defn run-dev
  "The entry-point for 'lein run-dev'"
  [& args]
  (println "\nCreating your [DEV] server...")
  (-> service/service
      (merge {:env                     :dev
              ::server/join?           false
              ::server/routes          #(deref #'service/routes)
              ::server/allowed-origins {:creds true :allowed-origins (constantly true)}})
      server/default-interceptors
      server/dev-interceptors
      server/create-server
      server/start))

There does not seem to be much information around CORS for Pedestal. I have looked at the cors example but it seems to just work while mine does not. Is there another interceptor I need to add to my routes or some sort of configuration setting that I am missing here?

kennyjwilli
  • 193
  • 3
  • 13

2 Answers2

3

I have figured out the problem. It turns out that an error was being thrown, however, it was getting swallowed and hidden from my debugger. Simply adding a try catch around my handler function fixes the problem.

(defn db-query
  [req]
  (try
    (let [edn-params (:edn-params req)
          q (:query edn-params)
          args (:args edn-params)
          q-result (apply d/q q (d/db conn) args)]
      {:status 200
       :body   (pr-str q-result)})
    (catch Exception ex
      {:status 400
       :body   "Not authorized"})))
kennyjwilli
  • 193
  • 3
  • 13
2

My original response:

The purpose of CORS is to limit the origin of the requests. You have to purposely tell it where requests can come from. This will fix it.

(def service {;other config stuff
              io.pedestal.http/allowed-origins ["http://localhost:3000"]}

It appears this is a duplicate question. Apparently javascript ajax requests are by definition limited to single origin. That code would work in production only if the GET request is made by clj-http or http-kit on the ring server that spawn http://localhost:3000 and then a cljs-http ajax request is made to that same ring server on port 3000. I still don't know why your run-dev doesn't work, but if you're calling lein with run, this is definitely what's happening.

Community
  • 1
  • 1
Ricardo Acuna
  • 530
  • 2
  • 10
  • I already have `:allowed-origins (constantly true)` for dev. This is suitable to pass [this](https://github.com/pedestal/pedestal/blob/7d3895d0ed06f47555644ed560a49b1ab311d7ab/service/src/io/pedestal/http/cors.clj#L76) check. – kennyjwilli Oct 23 '15 at 18:39
  • I wouldn't be able to pinpoint the problem unless I look at the source, but now that I think about it you're correct. Are you using the same namespace qualified name for service and server ::bootstrap or ::server might not be merged correctly if you're using different names for io.pedestal.http. – Ricardo Acuna Oct 23 '15 at 20:47
  • I couldn't reproduce the issue, using cljs-http. I setup a pedestal server on localhost:8080 with run-dev, and a cljs client on localhost:3000 and it works just fine. If you could produce a [minimal working example](http://stackoverflow.com/help/mcve), your question would have a better shot at getting answered. – Ricardo Acuna Oct 24 '15 at 02:30