Serving binary files from a database using compojure

I have the following route definition:

(require '[compojure.core :as ccore] '[ring.util.response :as response]) (def *main-routes* (ccore/defroutes avalanche-routes (ccore/GET "/" [] "Hello World 2") (ccore/GET "/images/:id" [id] (get-image-response id)))) 

In this example, the request / works like a charm and returns the expected Hello World 2 .

The get-images-response method is defined as follows:

 (defn get-image-response [id] (let [record (db/get-image id false)] (-> (response/response (:data record)) (response/content-type (:content-type record)) (response/header "Content-Length" (:size record))))) 

I get 404, though, since serving the binaries still doesn't quite work. Any ideas why?

Edit: Well, the problem is that images are being requested on /images/name.jpg . As soon as I delete .jpg , the caller calls the handler. So the question is, how can I match anything other than an extension?

+4
source share
2 answers

The real answer in this case was that an error occurred in the clojure -couchdb library. The patch is available on github here .

This boils down to adding the map parameter and the value of the {: as: byte-array} parameter to the request sent via clj-http to the couch api.

Another problem in my code was that ring does not know what to do with byte arrays when rendering them. Instead of fixing the ring, I just wrapped the byte array in java.io.ByteArrayInputStream . Here is the complete code for handling the download:

 (defn get-image-response [id] (let [record (db/get-image id false)] (-> (response/response (new java.io.ByteArrayInputStream (:data record))) (response/content-type (:content-type (:content-type record))) (response/header "Content-Length" (:size record))))) 
+3
source

Compojure uses clout to map routes. The dot symbol is of particular importance in driving directions. It is a marker separator, similar to a slash character. The following characters have this value in the meaning: / . , ; ? / . , ; ? .

This means that a route like "/images/:id" will not match the uri of the form /images/name.jpg , since images , name and jpg each represents a separate token in clout.

To match this, you can make your route in several ways, depending on your needs.

If all your images have a .jpg extension, the easiest way to do this is to:

 (GET "/images/:id.jpg" [id] ...) 

If the extension expands, you can do the following:

 (GET "/images/:name.:extension" [name extension] ...) 

If you want to restrict the extension, you can pass the regular expression to compojure / clout:

 (GET ["/images/:name.:ext", :ext #"(jpe?g|png|gif)"] [name ext] ...) 

You can also use a wildcard that is less accurate and matches any uri starting with /images/ :

 (GET "/images/*" [*] ...) 
+10
source

All Articles