Jump to navigation

Nikola Plejić

File upload in Clojure & Compojure

2010-09-02 in clojure

How to handle multipart HTTP POST equests in compojure.

Compojure is coming to be a really nice framework which is, together with the excellent Enlive templating/transformation library, enough to make this Lisp n00b take a shot at developing a toy project or two in a Lisp dialect. I struggled a bit today to do a file upload: it’s a relatively recent feature in the framework and although it’s pretty straightforward, it took me a while to get it up to speed. Here’s a really basic and primitive example which assumes you have clojure.contrib, Ring, Compojure and Enlive installed.

The key step is to wrap your upload handling route with the wrap-multipart-params middleware from the ring.middleware.multipart-params namespace. The route responsible for the file upload is the latter one:

(defroutes public-routes
      (GET "/" [] (render (index)))
        (mp/wrap-multipart-params
            (POST "/file" {params :params} (upload-file (get params "file")))))

(file in the (get params "file") call is the name of the input field.)

Next, here’s the upload-file handler function called by the route which just takes the file and copies it to a file named file.out in the current project directory:

(defn upload-file
          [file]
                (ds/copy (file :tempfile) (ds/file-str "file.out"))
                      (render (upload-success)))

(ds is an alias for the clojure.contrib.duck-streams namespace, and render is a function which takes a template and returns its string representation. upload-success is an Enlive template.)

Voila! Not hard at all. Also check out the gist with complete code and template files.