Thursday, 9 March 2017

How to do an upload using REST (Swagger) and Clojurescript (ajav

Hoping to help someone else that is also struggling with this.
I have used Luminus with Reagent to try this.
Luminus come with Swagger for REST API, it's a great tool because it gives you the possibility to try the API as soon as you have write it.
This is the code to write a REST end-point that accept a file in upload

(ns your-clojure-ns
  (:require [ring.util.http-response :refer :all]
            [compojure.api.sweet :refer :all]
            [schema.core :as s]
            [ring.swagger.upload :as upload])

(defapi service-routes
  {:swagger {:ui "/swagger-ui"
             :spec "/swagger.json"
             :data {:info {:version "1.0.0"
                           :title "Sample API"
                           :description "Sample Services"}}}}

  (context "/your-context" []
    :tags ["Your Context"]

    (POST "/upload" []
      :multipart-params [file :- upload/TempFileUpload]
      :middleware       [upload/wrap-multipart-params]
      (ok (let [{:keys [filename tempfile]} file ]
            (do-something-with tempfile)
            {:success true}))))



You should already have the right imports in the file created by Luminus, the only one that you have to add is [ring.swagger.upload :as upload] that will give you the Middleware to use for your request.
Once you have added this. You should see in your Swagger ui (localhost:3000/swagger-ui) your new API, with the possibility to already send a file to try your logic (do-something-with)
Now let's go to the Clojurescript call (that is the hardest part, I lost an evening to figure out the right combination)

(ns your-clojurescript-ns
  (:require [ajax.core :refer [GET POST]]))

(defn upload-file [file]
  (letfn [(handle-response-ok [] (js/alert "File Uploaded")
          (handle-response-error [] (js/alert "There were problems during the upload"))]
    (let [form-data (doto
                      (js/FormData.)
                      (.append "file" file))]
      (POST "/your-context/upload"
            {:body form-data
             :response-format :json
             :keywords? true
             :handler handle-response-ok
             :error-handler handle-response-error}))))



(.append "file" file) is very important, file is the same name you used in the clojure namespace as parameter, also you have to send the form-data as :body, if you try to send it as a :params (like is written around in internet) you will have an error.
Hope this post will be useful.

Coming soon... How to style your input with a file using Bootstrap, Reagent and Clojurescript. How changing the label using a Reagent atom can give you some headache.

1 comment: