If you happen to build a Clojure web application, you will most probably use Compojure somewhere along the stack. In this article I will show how easy it is to implement a file upload endpoint using that library.
Let’s start by generating a basic Compojure application from a template
lein new compojure fupload
Next, we need to add POST
route inside src/fupload/handler.clj
(POST "/upload"
{{{tempfile :tempfile filename :filename} :file} :params :as params}
(io/copy tempfile (io/file "resources" "public" filename))
"Success")
A couple of things happen here, first we specify that a file should be passed
using a field named file
. Once the request is issued, a ring handler
transforms its parameters to the following map:
{ :size 1234,
:tempfile #<File /var/folders/hq/az8xf5d9zv7g4dvhli9nmr_c1000gn/T/ring-multipart-4366831661746413539.tmp>,
:content-type application/text,
:filename project.clj}
In route definition we immediately destruct that map by specifying we are only
interested in fields tempfile
and filename
.
Finally, we copy uploaded file to resources/public
on the server using clojure.java.io
and we return “Success”. You have to add the following line in src/fupload/handler.clj
under :require
.
[clojure.java.io :as io]
Let’s check if it works. We could build a form with file
field and proper, but
instead, for simplicity, we will simulate a file upload using curl
(a file can be referenced with @
sign). In the following example we will try
to upload project.clj
from the current directory:
curl -XPOST -F [email protected] localhost:3000/upload
Success
head -n 2 resources/public/project.clj
(defproject fupload "0.1.0-SNAPSHOT"
:description "FIXME: write description"