Compojure: Nested route issue - clojure

I'm trying to set up routes in my application such that:
/:locale/ -> Home, with locale binding
/:locale/search -> Search,
with locale binding
Thus far, my routing code is:
(defn controller-routes [locale]
(home/c-routes locale)
(search/c-routes locale)))
(defroutes app-routes
(route/resources "/")
(context "/:locale" [locale]
(controller-routes locale))
no-locale-route
(route/not-found "Not Found"))
search/c-routes:
(defn c-routes [locale]
(GET "/search" [] (index locale)))
home/c-routes:
(defn c-routes [locale]
(GET "/" [] (index locale)))
I can't understand why this doesn't work properly, but currently "/uk/search/" matches correctly, but "/uk/" gives the 404 page.
Any help would be appreciated. Thanks.

controller-routes is a normal function which as of now returns the last route i.e search and hence only search works. What you need is make controller-routes a route using defroutes and changing the c-routes as well:
search/c-routes:
(def c-routes (GET "/search" [locale] (index locale)))
home/c-routes:
(def c-routes (GET "/" [locale] (index locale)))
Where you use above routes:
(defroutes controller-routes
home/c-routes
search/c-routes)
(defroutes app-routes
(route/resources "/")
(context "/:locale" [locale]
controller-routes)
no-locale-route
(route/not-found "Not Found"))

Related

Registering multiple handlers while running server

Is there any way to register multiple handlers while running an http-kit server:
(defroutes rest-main-app
(GET "/" "Welcome"))
(defroutes rest-events-app
(GET "/events" "Event API"))
(defn -main []
(run-server rest-main-app {:port 5000}))
How can I pass both routes to the run-server e.g both rest-main-app and rest-events-app ?
You can use compojure's routes function. You can also pass several handlers to defroutes, an example is provided below:
(defroutes get-routes
(GET "/events" [] "Event API")
(GET "/" [] "Welcome"))
(defroutes post-routes
(POST "/events" [] "Post Event API"))
(def all-routes
(routes
get-routes
post-routes))
(defn -main []
(run-server all-routes {:port 5000}))

How do I add webjars resources to lib-noir's app-handler?

How do I add webjars resources to lib-noir's app-handler?
I used to do this only using Ring like this:
(def app
(-> handler
(wrap-resource "public")
(wrap-resource "/META-INF/resources")
;;resources from webjars
))
Now I'm trying to figure out how to do this with lib-noir.
I tried this:
(def app (noir-middleware/app-handler [home-routes app-routes]
:ring-defaults {:static
{:resources
"/META-INF/resources"}}))
and it works, but I get a problem when posting forms after configuring this. The params are empty in the ring request now.
This seems to do it:
(defroutes app-routes
(route/resources "/")
(route/resources "/" {:root "META-INF/resources/"})
(route/not-found "Not Found"))

Friend authentication empty param

I am trying to implement friend authentication on my web app but when i try to login i get this */login?&login_failed=Y&username=*...my param is empty and i cant login,what am i doing wrong?
these are my routes...
(defroutes routes
(GET "/" [] (index))
(GET "/indexMessage" [] (indexMessage))
(GET "/login" req (index))
(POST "/insert-user" {params :params}
(let [firstname (get params "firstname")
lastname (get params "lastname")
email (get params "email")
password (get params "password")
sex (get params "sex")
year (get params "year")
month (get params "month")
day (get params "day")]
(def date (str year"-"month"-"day))
(insert-user firstname lastname email password sex date)))
(route/resources "/public")
(route/not-found "Page not found")
)
i used all the middleware needed...
(def page (handler/site
(friend/authenticate
routes
{:allow-anon? true
:login-uri "/login"
:default-landing-uri "/"
:unauthorized-handler #(-> (html5 [:h2 "You do not have sufficient privileges to access " (:uri %)])
resp/response
(resp/status 401))
:credential-fn #(creds/bcrypt-credential-fn #users %)
:workflows [(workflows/interactive-form)]})
(wrap-keyword-params routes)
(wrap-nested-params routes)
(wrap-params routes)
(wrap-session routes)
))
and this is how i start up my jetty server...
(defn -main []
(run-jetty page {:port 8080 :join? false}))
users is a map like this...
{"username" {:username "username" :password "password"}}
is :roles a must in the map?maybe it's because of that?
I am pretty new to Friend as well but from the Friend source code I can say that the parameters name of your POST request matters. I guess you are following this example, if not, it's the best hint you can get actually. Notice the name of the form fields
https://github.com/cemerick/friend-demo/blob/master/src/clj/cemerick/friend_demo/interactive_form.clj#L22-l24
All credential functions take a single argument, a map containing the available credentials, so
as there is no explicit POST "/login" route, the Friend midleware is catching and using them as credentials for your credential-fn as shown here https://github.com/cemerick/friend/blob/master/src/cemerick/friend/workflows.clj#L76-78
So "username" and "password" should be the names of the parameters POSTed to the :login-uri
For newcomers that example is runnable here http://friend-demo.herokuapp.com/interactive-form/

error while composing routes in compojure

The following compojure routes work.
(defroutes app-routes
(GET "/" [] (index))
(GET "/twauth" [] (tw/authorize))
(ANY "/twcallback" [] (do
(tw/callback)
(index)))
(route/resources "/")
(route/not-found "Not Found"))
(def app (handler/site app-routes))
However I get error with the following. It throws a java.nullpointer.exception. What am I doing wrong here ?
(defroutes app-routes
(GET "/" [] (index))
(GET "/twauth" [] (tw/authorize))
(ANY "/twcallback" [] (do
(tw/callback)
(index))))
(defroutes base-routes
(route/resources "/")
(route/not-found "Not Found"))
(def app
(-> app-routes
base-routes
handler/site))
Your base-routes matches all requests. I think the following illustrates it better:
(defroutes base-routes
(route/not-found "Not found"))
(def app
(-> app-routes
base-routes
handler/site))
No matter what you do in app-routes above, base-routes is checked after and will always return not-found. Note that each request is threaded through both routes, not first match wins.
So you need to either move the base-routes into your app-routes as fallbacks -- like you already did in your working example -- or compose them in app:
(def app
(-> (routes app-routes base-routes)
handler/site))
Here the composed routes ensures that the first match wins.

Compojure: how to map query parameters

I'm trying to make any of the following mappings work to map http://mysite.org/add?http://sitetoadd.com or http://mysite.org/add?u=http://sitetoadd.com
(GET "/add?:url" [url] url)
(GET "/add?u=:url" [url] url)
(GET "/add" {params :params} (params :u))
(GET "/add" {params :params} (params "u"))
(GET "/add" [u] u)
But it just fails and I don't know why. On the other hand, this works:
(GET "/add/:url" [url] url)
but I can't use it because I have to pass a url and http://mysite.org/add/http://sitetoadd.com is invalid while http://mysite.org/add?http://sitetoadd.com is ok.
EDIT: dumping request i've seen that params is empty. I thought that it would contain POST and GET parameters, but the only place where I can find the params I pass is in :query-string ("u=asd"). It seems that a middleware is needed to parse query strings. My question stands still, by the way.
See https://github.com/weavejester/compojure under Breaking Changes. The params map is no longer bound by default. If you have your example routes inside a "(defroutes main-routes ... )", make sure you activate it through "(handler/site main-routes)" as explained on https://github.com/weavejester/compojure/wiki/Getting-Started as it is the site or api method that makes sure the params map gets bound by default.
Here's an example that works:
(ns hello-world
(:use compojure.core, ring.adapter.jetty)
(:require [compojure.route :as route]
[compojure.handler :as handler]))
(defroutes main-routes
(GET "/" {params :params} (str "<h1>Hello World</h1>" (pr-str params)))
(route/not-found "<h1>Page not found</h1>"))
(defn -main [& m]
(run-jetty (handler/site main-routes) {:port 8080}))