1

I'm unable to access form parameters from a POST request. I've tried every combination of middleware and config options I've seen in the docs, on SO, etc. (including the deprecated compojure/handler options) and I'm still unable to see the parameters. I'm sure I'm missing something very obvious, so any suggestions (no matter how slight) would be greatly appreciated.

Here's my latest attempt, wherein I try to use the site-defaults middleware and disable the anti-forgery/CSRF protection provided by default. (I know this is a bad idea.) However, when I try to view the page in question in a web browser, the browser tries to download the page, as if it were a file it wasn't capable of rendering. (Interestingly, the page is rendered as expected when using Curl.)

Here's the latest attempt:

(defroutes config-routes*
  (POST "/config" request post-config-handler))

(def config-routes
  (-> #'config-routes*
    (basic-authentication/wrap-basic-authentication authenticated?)
    (middleware-defaults/wrap-defaults (assoc middleware-defaults/site-defaults :security {:anti-forgery false}))))

Previous attempt:

(def config-routes
  (-> #'config-routes*
    (basic-authentication/wrap-basic-authentication authenticated?)
    middleware-params/wrap-params))

UPDATE: The parameters appear to be swallowed by the outer defroutes:

(defroutes app-routes
  (ANY "*" [] api-routes)
  (ANY "*" [] config-routes)
  (route/not-found "Not Found"))

So, my question now becomes: How can I thread the parameters through to the nested defroutes?

My temporary solve is based on this solution, but Steffen Frank's is much simpler. I will try that and follow-up.

UPDATE 2:

In trying to implement the suggestions provided by both of the current answers, I'm running into a new issue: route matches are overeager. e.g. given the following, POSTs to /something fail with a 401 response because of the wrap-basic-authentication middleware in config-routes.

(defroutes api-routes*
   (POST "/something" request post-somethings-handler))

(def api-routes
  (-> #'api-routes*
    (middleware-defaults/wrap-defaults middleware-defaults/api-defaults)
    middleware-json/wrap-json-params
    middleware-json/wrap-json-response))

(defroutes config-routes*
  (GET "/config" request get-config-handler)
  (POST "/config" request post-config-handler))

(def config-routes
  (-> #'config-routes*
    (basic-authentication/wrap-basic-authentication authenticated?)
    middleware-params/wrap-params))

(defroutes app-routes
  config-routes
  api-routes
  (route/not-found "Not Found"))

(def app app-routes)
Community
  • 1
  • 1
pdoherty926
  • 9,895
  • 4
  • 37
  • 68

3 Answers3

2

The issue is that when you define your routes in this way:

(defroutes app-routes
  (ANY "*" [] api-routes)
  (ANY "*" [] config-routes)
  (route/not-found "Not Found"))

then any request will be matched by api-routes as long as it returns non-nil response. Thus api-routes does not swallow your request params but rather stealing the whole request.

Instead you should define your app-routes as (preferred solution):

(defroutes app-routes
  api-routes
  config-routes
  (route/not-found "Not Found"))

or make sure that your api-routes returns nil for unmatched URL path (e.g. it shouldn't have not-found route defined).

Piotrek Bzdyl
  • 12,965
  • 1
  • 31
  • 49
  • Thanks for putting this together. See my response to Steffen's answer, but the "preferred solution" seems to be order dependent, which is something I'd like to avoid. Do I need to somehow explicitly "return nil for unmatched URL path" when `api-routes` comes first but doesn't find a match? – pdoherty926 Apr 08 '17 at 12:32
  • It's hard to tell if you don't share the implementation of `api-routes`. Also `defroutes` will create a handler function that returns `nil` if its routes didn't match the request. It seems that your `api-routes` matches requests that you think shouldn't be. – Piotrek Bzdyl Apr 08 '17 at 12:41
  • I've updated my question with a sample based on my latest iteration. Though, I fear I'm beginning to run afoul of the "what makes a good question" guidelines. – pdoherty926 Apr 08 '17 at 12:50
1

Just a guess, but have you tried this:

(defroutes app-routes
   api-routes
   config-routes
   (route/not-found "Not Found"))
Steffen Frank
  • 1,220
  • 7
  • 14
  • Thanks, this is a very clean solution. I ended up using [this](http://stackoverflow.com/a/28017586/382982) approach, but will give this a try. – pdoherty926 Apr 08 '17 at 06:02
  • This works ... sort of. If `api-routes` comes first in the list, it is matching/swallowing the request and I'm back to where I started. Neither of my nested defroutes has a `not-found` handler, so I'm confused as to why that's happening. – pdoherty926 Apr 08 '17 at 12:30
0

You may find the following post useful. It talks about mixing api and app routes such that they don't interfere with each other and you avoid adding middleware from one to the toher etc. Serving app and api routes with different middleware using Ring and Compojure

Tim X
  • 4,158
  • 1
  • 20
  • 26