Support file uploading in Clojure client

This commit is contained in:
xhh 2015-11-18 17:21:32 +08:00
parent 473d34ef76
commit 473aab2d8e
9 changed files with 88 additions and 37 deletions

View File

@ -1,11 +1,12 @@
{{=< >=}}(ns <package>.<classname>
(:require [<projectName>.core :refer [call-api check-required-params]]))
(:require [<projectName>.core :refer [call-api check-required-params]])
(:import (java.io File)))
<#operations><#operation>
(defn <nickname>
"<&summary><#notes>
<&notes></notes>"<#hasOptionalParams>
([<#allParams><#required><paramName> </required></allParams>] (<nickname><#allParams><#required> <paramName></required></allParams> nil))</hasOptionalParams>
<#hasOptionalParams>(</hasOptionalParams>[<#allParams><#required><paramName> </required></allParams><#hasOptionalParams>{:keys [<#allParams><^required><paramName> </required></allParams>]}</hasOptionalParams>]<#hasRequiredParams>
([<#allParams><#required><#isFile>^File </isFile><paramName> </required></allParams>] (<nickname><#allParams><#required> <paramName></required></allParams> nil))</hasOptionalParams>
<#hasOptionalParams>(</hasOptionalParams>[<#allParams><#required><#isFile>^File </isFile><paramName> </required></allParams><#hasOptionalParams>{:keys [<#allParams><^required><#isFile>^File </isFile><paramName> </required></allParams>]}</hasOptionalParams>]<#hasRequiredParams>
<#hasOptionalParams> </hasOptionalParams>(check-required-params<#allParams><#required> <paramName></required></allParams>)</hasRequiredParams>
<#hasOptionalParams> </hasOptionalParams>(call-api "<path>" :<httpMethod>
<#hasOptionalParams> </hasOptionalParams> {:path-params {<#pathParams>"<baseName>" <paramName> </pathParams>}

View File

@ -3,6 +3,7 @@
[clojure.string :as str]
[clj-http.client :as client])
(:import (com.fasterxml.jackson.core JsonParseException)
(java.io File)
(java.util Date TimeZone)
(java.text SimpleDateFormat)))
@ -90,17 +91,24 @@
path-params)]
(str (:base-url *api-context*) path)))
(defn normalize-param
"Normalize parameter value, handling three cases:
for sequential value, normalize each elements of it;
for File value, do nothing with it;
otherwise, call `param-to-string`."
[param]
(cond
(sequential? param) (map normalize-param param)
(instance? File param) param
:else (param-to-str param)))
(defn normalize-params
"Normalize parameters values: remove nils, format to string with `param-to-str`."
[params]
(reduce (fn [result [k v]]
(if (nil? v)
result
(assoc result k (if (sequential? v)
(map param-to-str v)
(param-to-str v)))))
{}
params))
(->> params
(remove (comp nil? second))
(map (fn [[k v]] [k (normalize-param v)]))
(into {})))
(defn json-mime? [mime]
"Check if the given MIME is a standard JSON MIME or :json."
@ -136,6 +144,13 @@
;; for non-JSON response, return the body string directly
:else body))
(defn form-params-to-multipart
"Convert the given form parameters map into a vector as clj-http's :multipart option."
[form-params]
(->> form-params
(map (fn [[k v]] (array-map :name k :content v)))
vec))
(defn call-api
"Call an API by making HTTP request and return its response."
[path method {:keys [path-params query-params header-params form-params body-param content-types accepts]}]
@ -144,12 +159,16 @@
content-type (or (json-preferred-mime content-types)
(and body-param :json))
accept (or (json-preferred-mime accepts) :json)
multipart? (= "multipart/form-data" content-type)
opts (cond-> {:url url :method method}
content-type (assoc :content-type content-type)
accept (assoc :accept accept)
(seq query-params) (assoc :query-params (normalize-params query-params))
(seq header-params) (assoc :header-params (normalize-params header-params))
(seq form-params) (assoc :form-params (normalize-params form-params))
(and content-type (not multipart?)) (assoc :content-type content-type)
multipart? (assoc :multipart (-> form-params
normalize-params
form-params-to-multipart))
(and (not multipart?) (seq form-params)) (assoc :form-params (normalize-params form-params))
body-param (assoc :body (serialize body-param content-type))
debug (assoc :debug true :debug-body true))
resp (client/request opts)]

View File

@ -0,0 +1 @@
Hello world!

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.api.pet
(:require [swagger-petstore.core :refer [call-api check-required-params]]))
(:require [swagger-petstore.core :refer [call-api check-required-params]])
(:import (java.io File)))
(defn update-pet
"Update an existing pet
@ -97,7 +98,7 @@
"uploads an image
"
([pet-id ] (upload-file pet-id nil))
([pet-id {:keys [additional-metadata file ]}]
([pet-id {:keys [additional-metadata ^File file ]}]
(call-api "/pet/{petId}/uploadImage" :post
{:path-params {"petId" pet-id }
:header-params {}

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.api.store
(:require [swagger-petstore.core :refer [call-api check-required-params]]))
(:require [swagger-petstore.core :refer [call-api check-required-params]])
(:import (java.io File)))
(defn get-inventory
"Returns pet inventories by status

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.api.user
(:require [swagger-petstore.core :refer [call-api check-required-params]]))
(:require [swagger-petstore.core :refer [call-api check-required-params]])
(:import (java.io File)))
(defn create-user
"Create user

View File

@ -3,6 +3,7 @@
[clojure.string :as str]
[clj-http.client :as client])
(:import (com.fasterxml.jackson.core JsonParseException)
(java.io File)
(java.util Date TimeZone)
(java.text SimpleDateFormat)))
@ -90,17 +91,24 @@
path-params)]
(str (:base-url *api-context*) path)))
(defn normalize-param
"Normalize parameter value, handling three cases:
for sequential value, normalize each elements of it;
for File value, do nothing with it;
otherwise, call `param-to-string`."
[param]
(cond
(sequential? param) (map normalize-param param)
(instance? File param) param
:else (param-to-str param)))
(defn normalize-params
"Normalize parameters values: remove nils, format to string with `param-to-str`."
[params]
(reduce (fn [result [k v]]
(if (nil? v)
result
(assoc result k (if (sequential? v)
(map param-to-str v)
(param-to-str v)))))
{}
params))
(->> params
(remove (comp nil? second))
(map (fn [[k v]] [k (normalize-param v)]))
(into {})))
(defn json-mime? [mime]
"Check if the given MIME is a standard JSON MIME or :json."
@ -136,6 +144,13 @@
;; for non-JSON response, return the body string directly
:else body))
(defn form-params-to-multipart
"Convert the given form parameters map into a vector as clj-http's :multipart option."
[form-params]
(->> form-params
(map (fn [[k v]] (array-map :name k :content v)))
vec))
(defn call-api
"Call an API by making HTTP request and return its response."
[path method {:keys [path-params query-params header-params form-params body-param content-types accepts]}]
@ -144,12 +159,16 @@
content-type (or (json-preferred-mime content-types)
(and body-param :json))
accept (or (json-preferred-mime accepts) :json)
multipart? (= "multipart/form-data" content-type)
opts (cond-> {:url url :method method}
content-type (assoc :content-type content-type)
accept (assoc :accept accept)
(seq query-params) (assoc :query-params (normalize-params query-params))
(seq header-params) (assoc :header-params (normalize-params header-params))
(seq form-params) (assoc :form-params (normalize-params form-params))
(and content-type (not multipart?)) (assoc :content-type content-type)
multipart? (assoc :multipart (-> form-params
normalize-params
form-params-to-multipart))
(and (not multipart?) (seq form-params)) (assoc :form-params (normalize-params form-params))
body-param (assoc :body (serialize body-param content-type))
debug (assoc :debug true :debug-body true))
resp (client/request opts)]

View File

@ -77,11 +77,9 @@
(delete-pet id)
(is (thrown? RuntimeException (get-pet-by-id id)))))
(comment
;; TODO support file uploading
(deftest test-upload-file
(let [{:keys [id] :as pet} (make-random-pet)
_ (add-pet {:body pet})
file (io/file (io/resource "hello.txt"))]
;; no errors
(upload-file id {:file file :additionalMetadata "uploading file with clojure client"}))))
(deftest test-upload-file
(let [{:keys [id] :as pet} (make-random-pet)
_ (add-pet {:body pet})
file (io/file (io/resource "hello.txt"))]
;; no errors with upload-file
(upload-file id {:file file :additional-metadata "uploading file with clojure client"})))

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.core-test
(:require [clojure.test :refer :all]
(:require [clojure.java.io :as io]
[clojure.test :refer :all]
[swagger-petstore.core :refer :all])
(:import (java.text ParseException)))
@ -87,8 +88,17 @@
"/pet" {"id" 1} "http://petstore.swagger.io/v2/pet"
"/pet/{id}" nil "http://petstore.swagger.io/v2/pet/{id}"))
(deftest test-normalize-param
(let [file (-> "hello.txt" io/resource io/file)]
(are [param expected]
(is (= expected (normalize-param param)))
[12 "34"] ["12" "34"]
file file
"abc" "abc"
[[12 "34"] file "abc"] [["12" "34"] file "abc"])))
(deftest test-normalize-params
(is (= {:a "123" :b ["4" "5,6"]}
(is (= {:a "123" :b ["4" ["5" "6"]]}
(normalize-params {:a 123 :b [4 [5 "6"]] :c nil}))))
(deftest test-json-mime?