Nesting site/api routes with Friend

66 views
Skip to first unread message

Jonathon McKitrick

unread,
Aug 8, 2014, 10:34:10 AM8/8/14
to comp...@googlegroups.com
I'd like to have my site routes and an api route with an 'api/' context.  I have that working fine.  But when I add Friend authentication, it breaks things.

The main site pages only work with Friend if they are listed first in the routes.  But in that case, the 'api/' context routes are not matched when they are requested.

Any suggestions?

(defroutes api-routes
  (context "/api" []
;; All api routes here
           (route/not-found "ERROR")))

(defroutes www-routes
  (GET "/admin" req (friend/authorize #{::admin} "Admin only"))
  (GET "/authorized" req (friend/authorize #{::user} "Users only"))
  (GET "/home" [] (response/file-response "home.html" {:root "resources/public"}))
  (GET "/login" [] (response/file-response "login.html" {:root "resources/public"}))
  (friend/logout (ANY "/logout" req (response/redirect "/")))
  (GET "/" [] (response/redirect "index.html"))
  (route/resources "/")
  ;;(route/not-found "Not Found")
  )

(def app
  (routes
   (-> www-routes
       (friend/authenticate {
                             :credential-fn (partial creds/bcrypt-credential-fn users)
                             :workflows [(workflows/interactive-form)]})
       handler/site)
   (-> api-routes
       handler/api
       wrap-restful-format)))

James Reeves

unread,
Aug 8, 2014, 3:07:01 PM8/8/14
to Compojure
Hi Jonathan

There are a few problems with your routes and the order in which you apply middleware.

It's important to realise that the routing mechanism for Compojure is very simple. The request is sent to each route in order, until a route returns a non-nil response.

In your case, you've set it up so that every single request is sent through the authenticate middleware, regardless of whether it's for the api-routes or www-routes. You also apply middleware twice, which can be a problem when consuming streams.

Your app wants to look more like:

(def app
  (routes
   (context "/api" [] (handler/api api-routes))
   (handler/site (friend/authenticate www-routes auth-options)
   (route/not-found "Not found")))

If you pass this code an api request, it applies the api middleware, then heads into the api-routes.

If you pass this code a www request, it skips the api-routes due to the context, then applies the site and authenticate middleware, then heads into the www-routes.

Incidentally you could write your www-routes like:

(def www-routes
  (routes
   (GET "/admin" [] (friend/authorize #{::admin} "Admin only"))
   (GET "/authorized" [] (friend/authorize #{::user} "Users only"))
   (GET "/home" [] (io/resource "public/home.html"))
   (GET "/login" [] (io/resource "public/login.html"))
   (GET "/" [] (io/resource "public/index.html"))
   (friend/logout (ANY "/logout" [] (response/redirect "/")))
   (route/resources "/")))

The clojure.java.io/resource function will return a URL to a resource, which Compojure can use to serve as a response.

- James


--
You received this message because you are subscribed to the Google Groups "Compojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compojure+...@googlegroups.com.
To post to this group, send email to comp...@googlegroups.com.
Visit this group at http://groups.google.com/group/compojure.
For more options, visit https://groups.google.com/d/optout.

Jonathon McKitrick

unread,
Aug 8, 2014, 3:41:26 PM8/8/14
to comp...@googlegroups.com
First of all, thanks, it all works, after a minor tweak to wrap-restful-format on the api handlers.

But how can I make sure the api calls are authenticated as well?

James Reeves

unread,
Aug 8, 2014, 3:58:15 PM8/8/14
to Compojure
You could just add authentication middleware to your api-routes as well as the www-routes. You probably want different authentication options for your API routes anyway.

- James


Jonathon McKitrick

unread,
Aug 8, 2014, 5:26:59 PM8/8/14
to comp...@googlegroups.com
Odd that wasn't working before (wrapping each handler separately) but it is now.  Thanks!


On Friday, August 8, 2014 10:34:10 AM UTC-4, Jonathon McKitrick wrote:
Reply all
Reply to author
Forward
0 new messages