Search code examples
model-view-controllerweb-applicationsclojurecompojurenoir

Trouble getting defroutes to work in webnoir


So, I'm a clojure n00b, and I'm missing something when trying to get the routes for a project I'm building working.

I had some issues with circular dependencies, and after working with Django, I think it's much better to have routes all defined in one place, rather than peppered all over the codebase as seems to be done with defpage.

Onto the code:

This is my core.clj file:

(ns blktechies-home.core
  (:use compojure.core
        hiccup.middleware)
  (:require [compojure.route :as route]
            [blktechies-home.routes :as site-routes]
            [compojure.handler :as handler]
            [compojure.response :as response]))

(def app
  (-> (handler/site site-routes/app)
      (wrap-base-url)))

Then in my routes file I have the following:

(ns blktechies-home.routes
  (:use compojure.core
        noir.core
        hiccup.middleware)
  (:require [compojure.route :as route]
            [compojure.handler :as handler]
            [compojure.response :as response]
            [blktechies-home.views.common :as common]))

(defroutes app
  (GET "/" [] (common/main-layout
               (welcome/index-page)))
  (route/resources "/")
  (route/not-found "<h1>NOPE</h1>"))

Everything is 404'ing, and I'm not even sure where to go from here. I was able to use the site with defpage, but it just seemed ugly and not extensible as the number of routes grows.

So

  • What am I doing wrong here? Any insight into the underlying compojure/clojure/ring layers would be awesome
  • If this isn't the best way to define routes, what is?
  • Are there any good examples of big clj-noir sites on github? (My google-fu has failed me.)

Solution

  • In Noir you can put all your defpage's in the same namespace, one after another if you want to have them all in the same place. They can be as simple as delegating to other functions to do the "real" work, the same way you have defined the (GET "/" ...) route in your example.

    What am I doing wrong here? Any insight into the underlying compojure/clojure/ring layers would be awesome

    Not sure what are you doing wrong, your code works for me with a couple of minimal changes:

    The core with just adding the ring.adapter.jetty to start a jetty server when loading the file:

     (ns blktechies-home.core
      (:use compojure.core
            hiccup.middleware
            [ring.adapter.jetty :only [run-jetty]])
      (:require [compojure.route :as route]
                [blktechies-home.routes :as site-routes]
                [compojure.handler :as handler]
                [compojure.response :as response]))
    
    (def app
      (-> (handler/site site-routes/app)
        (wrap-base-url)))
    
    (run-jetty app {:port 8080 :join? false})
    

    Your routes file, without "views.common" namespace:

     (ns blktechies-home.routes
      (:use compojure.core
            noir.core
            hiccup.middleware)
      (:require [compojure.route :as route]
                [compojure.handler :as handler]
                [compojure.response :as response]))
    
     (defroutes app
       (GET "/" [] "the root path")
       (route/resources "/")
       (route/not-found "<h1>NOPE</h1>"))
    

    Now starting the repl:

    lein repl
    

    And loading the core:

    user=> (load-file "src/blktechies_home/core.clj")
    #<Server Server@9ae1ab>
    

    And wgetting the root:

    wget http://localhost:8080/ -O - -q
    the root path