vitvly
vitvly

Reputation: 3638

Request params not parsed in Ring/Compojure app

I am writing a web app using Ring and Compojure, and Friend library for authorization. Recently I've made some changes to the project, and now I am not able to fetch request parameters any more.

What I used to do is this:

; Routes definition
(defroutes app-routes
  (POST "/*.do" request 
    (insert-data (:params request))))

; Middlewares
(def secured-routes
  (handler/site
    (-> app-routes
        wrap-params
        (friend/authenticate friend-params-map))))

and form/URL parameters would be parsed into a Clojure map. Right now this does not seem to work, and (:params request) contains maps of the form

{:* <request-url>}

with a single :* key. If I try to (println request), a get a Clojure map with lots of key-value pairs, among which there are

:body #object[org.eclipse.jetty.server.HttpInputOverHTTP 0x6ef9a9e1 HttpInputOverHTTP@6ef9a9e1]

that seem to contain request data, correct? But how do I fetch those?

Previously I was just using wrap-params middleware as described above, and it worked.

One approach that works is invoking (body-string request) in each handler, that will return a stringified version of request body. But it would be great to get an automatically parsed Clojure map for each url handler. Obviously, I'm missing something.

Can someone please advise? I would also be happy to find out more how to debug those kinds of handler issues myself - meaning, debug middleware chains and find out why wrap-params does not get invoked or is invoked improperly.

Thanks!

UPDATE: per @nberger's comment, i've tried changing secured-routes definition to this:

(def secured-routes
  (-> app-routes
      (wrap-defaults site-defaults)
      (friend/authenticate friend-params-map)))

but now the login page does not work at all (authentication stopped working). After moving wrap-defaults after friend/authenticate as suggested in the comment, Friend complains in big font about Invalid anti-forgery token (???)

Upvotes: 4

Views: 949

Answers (1)

vitvly
vitvly

Reputation: 3638

I've found the issue. In the front-end code, POSTs to *.do have been modified to send application/json content-type. Below is the jQuery's ajax call that was used:

$.ajax({ 
  url: '/saveInput.do',
  type: 'POST',
  contentType: 'application/json; charset=UTF-8',
  data: JSON.stringify(formValues),
});

I've modified it to

$.ajax({ 
  url: '/saveInput.do',
  type: 'POST',
  data: formValues,
});

and it works now. Moreover, original Ajax call with JSON content-type can be preserved by including wrap-json-params middleware from ring-json, so that routes definition finally becomes:

(def secured-routes
  (-> app-routes
      (friend/authenticate friend-params-map)
      (wrap-defaults (assoc-in site-defaults [:security :anti-forgery] false))
      wrap-json-params))

I've opted for the latter. @nberger - thank you for help!

Upvotes: 2

Related Questions