1

我已经定义了以下架构:

(s/defschema Card
 {:cardNumber s/Str
  :cvv s/Str
  :creditCardMonthValidity s/Str
  :creditCardYearValidity s/Str
  :cpf s/Str
  :name s/Str
  :phoneNumber s/Str})

然后在一条路线中,我在 JSON 响应中使用相同的键:

(GET "/card" []
        :summary "fetches card info given the access token & checkout id"
        :query-params [accessToken :- String checkoutId :- String]
        :return Card
        (let [checkout  (CheckoutApi/show checkoutId accessToken)
              card      (.getCard checkout)
              contact   (.getContact checkout)
              (ok {:cardNumber (.getAccountNumber card)
                   :cvv "000"
                   :creditCardMonthValidity (.getExpiryMonth card)
                   :creditCardYearValidity (.getExpiryYear card)
                   :cpf (.getNationalID contact)
                   :name (.getFirstName contact)
                   :phoneNumber (.getPhoneNumber contact)})]))

有没有一种优雅的方法来避免键名的重复?类似于构造函数的方法,我可以只传递值吗?(也许以某种特定的顺序)

4

1 回答 1

1

这样的事情可能会起作用:您可以定义一个同时定义模式和构造函数的宏。

user> (defmacro defresponse [schema constructor-name constructor-params data]
        `(do
           (s/defschema ~schema ~(into {} (map (fn [[k [t _]]] [k t])
                                               data)))
           (defn ~constructor-name ~constructor-params
             ~(into {} (map (fn [[k [_ init]]] [k init])
                            data)))))
#'user/defresponse
user> (defresponse Card card-response [card contact]
        {:cardNumber [s/Str (.getAccountNumber card)]
         :cvv [s/Str "000"]
         :creditCardMonthValidity [s/Str (.getExpiryMonth card)]
         :creditCardYearValidity [s/Str (.getExpiryYear card)]
         :cpf [s/Str (.getNationalID contact)]
         :name [s/Str (.getFirstName contact)]
         :phoneNumber [s/Str (.getPhoneNumber contact)]})

这种取消响应将扩展为以下内容:

(do
  (s/defschema
    Card
    {:cardNumber s/Str,
     :cvv s/Str,
     :creditCardMonthValidity s/Str,
     :creditCardYearValidity s/Str,
     :cpf s/Str,
     :name s/Str,
     :phoneNumber s/Str})
  (defn card-response [card contact]
    {:cardNumber (.getAccountNumber card),
     :cvv "000",
     :creditCardMonthValidity (.getExpiryMonth card),
     :creditCardYearValidity (.getExpiryYear card),
     :cpf (.getNationalID contact),
     :name (.getFirstName contact),
     :phoneNumber (.getPhoneNumber contact)}))

然后你可以像往常一样使用你的模式,card-response就像这样:

(let [checkout  (CheckoutApi/show checkoutId accessToken)
      card      (.getCard checkout)
      contact   (.getContact checkout)]
  (ok (card-response card contact)))

(还没有测试过这个,但它应该可以工作。否则会在早上更新它)

于 2017-01-12T21:48:27.717 回答