24 Oct 2013, 17:20
Generic-user-small

Erik Backman (7 posts)

Hello there.

First off, thank you for a wonderfull book.

b3 here, and I’m having issues with getting the liberator-services app running correctly with the route to “/”.

I’m getting a resource not found. Addressing the html directly works fine however and so does adding new users etc

Tried to compare to the source package but see no differences.

25 Oct 2013, 00:34
Profile_pic_pragsmall

Dmitri Sotnikov (35 posts)

Hi Erik,

That’s actually a bug in the code. The problem is that you can’t actually check if a file exists inside a jar. So, it works fine when you run with lein ring server, but when you do lein ring uberjar and run java -jar myjar.jar then the path to the resource is inside the jar and can’t be accessed the same way.

I’ll fix this up for the next revision. Sorry about that. :)

25 Oct 2013, 02:39
Profile_pic_pragsmall

Dmitri Sotnikov (35 posts)

So, a better way to check if the resource exists is as follows:

(defresource home
    :available-media-types ["text/html"]

    :exists?
    (fn [context]
      [(io/get-resource "/home.html")
       {::file (file (str (io/resource-path) "/home.html"))}])

    :handle-ok
    (fn [{{{resource :resource} :route-params} :request}]
      (clojure.java.io/input-stream (io/get-resource "/home.html")))

    :last-modified
    (fn [{{{resource :resource} :route-params} :request}]
      (.lastModified (file (str (io/resource-path) "/home.html")))))

When we call get-resource we’ll get a URL back if the file exists file and a nil if it doesn’t. This will work reliably both with regular files and with resources inside a jar.

Also, the handler for a Liberator service can be simpler as well. Since Liberator takes care of checking file types we can simply use the following for the app definition:

(def app (routes home-routes))
25 Oct 2013, 15:11
Generic-user-small

Erik Backman (7 posts)

Hello Dmitir, thanks for a rapid response!

I was running with lein actually, no use of uberjar at this stage in my oppinion.

However the function for :exists? above now serves up the page as expected for me, so thanks a bunch!

oh and the simplified app routes works + looks more sane too ;)

25 Oct 2013, 15:38
Generic-user-small

Erik Backman (7 posts)

One more thing, the handler.clj seem to need handler/site from compojure aswell or posting new users won’t work (no wrap-params renders you an empty user param on post).

26 Oct 2013, 00:09
Profile_pic_pragsmall

Dmitri Sotnikov (35 posts)

Ah nice catch with the handler/site middleware, and good to hear it solved the problem. Glad you found it before the book is out of beta. :)

08 Feb 2014, 04:21
Generic-user-small

Richard Burgis (6 posts)

A question.

Using the current versions of liberator and cheshire the first example in the liberator chapter would not compile saying that resource does not exist. When I backed them both back to the versions you used (0.9.0 and 5.2.0 respectively) the snippet compiled. Did one of these libraries change to no longer include the request?

If not what else could be the problem.

Thank you

08 Feb 2014, 04:51
Profile_pic_pragsmall

Dmitri Sotnikov (35 posts)

I’m not able to reproduce the problem using [liberator "0.10.0"] and [cheshire "5.3.1"]. Could you see if running lein clean and then lein ring server from the terminal would help?

09 Feb 2014, 19:53
Generic-user-small

Richard Burgis (6 posts)

That seems to have done it.

I ran your version of the complete project and am getting resource not found. Is that the problem you mention above.

Thank you very much Rich

10 Feb 2014, 23:08
Profile_pic_pragsmall

Dmitri Sotnikov (35 posts)

I’m still not entirely sure what caused the problem, but it could be the fact that it got compiled before the resource was added and cleaning forced a recompile.

The project.clj file in the book uses a global :aot :all flag that forces resources to be compiled. However, the new recommended approach is to add the :aot flag to the :uberjar profile, e.g:

:profiles
  {:uberjar {:aot :all},
   :production
   {:ring
    {:open-browser? false, :stacktraces? false, :auto-reload? false}},
   :dev
   {:dependencies [[ring-mock "0.1.5"] [ring/ring-devel "1.2.1"]],
    :env {:dev true}}}

This way :aot will only be called when the application is packaged.

  You must be logged in to comment