Reputation: 2223
I'm creating a static file server in Clojure with Compojure and I'm stuck on reading an image from the filesystem and displaying that image through a Compojure route.
slurp unfortunately doesn't handle binary data very well, and I've tried this 100 different ways since, but this is my latest failed attempt:
(defn image-output [filepath]
(try
(let [contents (apply str (with-open [rdr (io/reader filepath)]
(into #{} (line-seq rdr))))]
{
:status 200
:headers
{
"Content-Type" "image/jpeg",
"Content-Length" "",
"Cache-Control" "",
"Expires" ""
}
:body contents
}))
(catch Exception e {:status 404})))
(defn endpoint_view [params]
(if (contains? params :bucket)
(image-output (join "/" [data_path (:bucket params) (:dir params) (:filename params)]))))
(defroutes main-routes
(GET "/view/:bucket/:dir/:filename" {params :params} (endpoint_view params))
(route/files "/")
(route/resources "/s" {:root "./public/s"})
(route/not-found "Page not found"))
It seems this current attempt suffers the same fate as using slurp, where I can echo the contents string and it's and encoded string, but when I change the content-type to image/jpeg it's a broken image.
I spent all day yesterday Google searching, but none of the examples accomplished the same goal, and while they helped me understand a little more about Java IO, they weren't clear enough to help me get where I needed to go, or produced the same results I was already getting (example: Best way to read contents of file into a set in Clojure).
(Imaginary bonus points if you can tell me how to get the content type from the filepath as well as that's my next question!)
Upvotes: 6
Views: 1143
Reputation: 91857
Just make the body be (io/file filepath)
- Ring is perfectly happy to serve files for you.
Edit for bonus points: you can use ring.middleware.file-info/wrap-file-info
to get file metadata for the files you return. Or, you could just serve a whole directory with (compojure.route/files "/public")
, which does all this mess for you.
Upvotes: 7