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> {{=< >=}}(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> <#operations><#operation>
(defn <nickname> (defn <nickname>
"<&summary><#notes> "<&summary><#notes>
<&notes></notes>"<#hasOptionalParams> <&notes></notes>"<#hasOptionalParams>
([<#allParams><#required><paramName> </required></allParams>] (<nickname><#allParams><#required> <paramName></required></allParams> nil))</hasOptionalParams> ([<#allParams><#required><#isFile>^File </isFile><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> <#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>(check-required-params<#allParams><#required> <paramName></required></allParams>)</hasRequiredParams>
<#hasOptionalParams> </hasOptionalParams>(call-api "<path>" :<httpMethod> <#hasOptionalParams> </hasOptionalParams>(call-api "<path>" :<httpMethod>
<#hasOptionalParams> </hasOptionalParams> {:path-params {<#pathParams>"<baseName>" <paramName> </pathParams>} <#hasOptionalParams> </hasOptionalParams> {:path-params {<#pathParams>"<baseName>" <paramName> </pathParams>}

View File

@ -3,6 +3,7 @@
[clojure.string :as str] [clojure.string :as str]
[clj-http.client :as client]) [clj-http.client :as client])
(:import (com.fasterxml.jackson.core JsonParseException) (:import (com.fasterxml.jackson.core JsonParseException)
(java.io File)
(java.util Date TimeZone) (java.util Date TimeZone)
(java.text SimpleDateFormat))) (java.text SimpleDateFormat)))
@ -90,17 +91,24 @@
path-params)] path-params)]
(str (:base-url *api-context*) path))) (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 (defn normalize-params
"Normalize parameters values: remove nils, format to string with `param-to-str`." "Normalize parameters values: remove nils, format to string with `param-to-str`."
[params] [params]
(reduce (fn [result [k v]] (->> params
(if (nil? v) (remove (comp nil? second))
result (map (fn [[k v]] [k (normalize-param v)]))
(assoc result k (if (sequential? v) (into {})))
(map param-to-str v)
(param-to-str v)))))
{}
params))
(defn json-mime? [mime] (defn json-mime? [mime]
"Check if the given MIME is a standard JSON MIME or :json." "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 ;; for non-JSON response, return the body string directly
:else body)) :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 (defn call-api
"Call an API by making HTTP request and return its response." "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]}] [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) content-type (or (json-preferred-mime content-types)
(and body-param :json)) (and body-param :json))
accept (or (json-preferred-mime accepts) :json) accept (or (json-preferred-mime accepts) :json)
multipart? (= "multipart/form-data" content-type)
opts (cond-> {:url url :method method} opts (cond-> {:url url :method method}
content-type (assoc :content-type content-type)
accept (assoc :accept accept) accept (assoc :accept accept)
(seq query-params) (assoc :query-params (normalize-params query-params)) (seq query-params) (assoc :query-params (normalize-params query-params))
(seq header-params) (assoc :header-params (normalize-params header-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)) body-param (assoc :body (serialize body-param content-type))
debug (assoc :debug true :debug-body true)) debug (assoc :debug true :debug-body true))
resp (client/request opts)] resp (client/request opts)]

View File

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

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.api.pet (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 (defn update-pet
"Update an existing pet "Update an existing pet
@ -97,7 +98,7 @@
"uploads an image "uploads an image
" "
([pet-id ] (upload-file pet-id nil)) ([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 (call-api "/pet/{petId}/uploadImage" :post
{:path-params {"petId" pet-id } {:path-params {"petId" pet-id }
:header-params {} :header-params {}

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.api.store (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 (defn get-inventory
"Returns pet inventories by status "Returns pet inventories by status

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.api.user (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 (defn create-user
"Create user "Create user

View File

@ -3,6 +3,7 @@
[clojure.string :as str] [clojure.string :as str]
[clj-http.client :as client]) [clj-http.client :as client])
(:import (com.fasterxml.jackson.core JsonParseException) (:import (com.fasterxml.jackson.core JsonParseException)
(java.io File)
(java.util Date TimeZone) (java.util Date TimeZone)
(java.text SimpleDateFormat))) (java.text SimpleDateFormat)))
@ -90,17 +91,24 @@
path-params)] path-params)]
(str (:base-url *api-context*) path))) (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 (defn normalize-params
"Normalize parameters values: remove nils, format to string with `param-to-str`." "Normalize parameters values: remove nils, format to string with `param-to-str`."
[params] [params]
(reduce (fn [result [k v]] (->> params
(if (nil? v) (remove (comp nil? second))
result (map (fn [[k v]] [k (normalize-param v)]))
(assoc result k (if (sequential? v) (into {})))
(map param-to-str v)
(param-to-str v)))))
{}
params))
(defn json-mime? [mime] (defn json-mime? [mime]
"Check if the given MIME is a standard JSON MIME or :json." "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 ;; for non-JSON response, return the body string directly
:else body)) :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 (defn call-api
"Call an API by making HTTP request and return its response." "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]}] [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) content-type (or (json-preferred-mime content-types)
(and body-param :json)) (and body-param :json))
accept (or (json-preferred-mime accepts) :json) accept (or (json-preferred-mime accepts) :json)
multipart? (= "multipart/form-data" content-type)
opts (cond-> {:url url :method method} opts (cond-> {:url url :method method}
content-type (assoc :content-type content-type)
accept (assoc :accept accept) accept (assoc :accept accept)
(seq query-params) (assoc :query-params (normalize-params query-params)) (seq query-params) (assoc :query-params (normalize-params query-params))
(seq header-params) (assoc :header-params (normalize-params header-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)) body-param (assoc :body (serialize body-param content-type))
debug (assoc :debug true :debug-body true)) debug (assoc :debug true :debug-body true))
resp (client/request opts)] resp (client/request opts)]

View File

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

View File

@ -1,5 +1,6 @@
(ns swagger-petstore.core-test (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]) [swagger-petstore.core :refer :all])
(:import (java.text ParseException))) (:import (java.text ParseException)))
@ -87,8 +88,17 @@
"/pet" {"id" 1} "http://petstore.swagger.io/v2/pet" "/pet" {"id" 1} "http://petstore.swagger.io/v2/pet"
"/pet/{id}" nil "http://petstore.swagger.io/v2/pet/{id}")) "/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 (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})))) (normalize-params {:a 123 :b [4 [5 "6"]] :c nil}))))
(deftest test-json-mime? (deftest test-json-mime?