使用 schema.core 时避免重复
avoiding repetition while using schema.core
我定义了以下架构:
(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)})]))
有没有一种优雅的方法来避免键名的重复?类似于构造函数方法,我可以在其中传递值? (也许以某种特定顺序)
这样的方法可行:您可以定义一个同时定义架构和构造函数的宏。
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)]})
这个defresponse将扩展为以下内容:
(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)))
(这个没测试过,不过应该可以,不然早上更新)
我定义了以下架构:
(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)})]))
有没有一种优雅的方法来避免键名的重复?类似于构造函数方法,我可以在其中传递值? (也许以某种特定顺序)
这样的方法可行:您可以定义一个同时定义架构和构造函数的宏。
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)]})
这个defresponse将扩展为以下内容:
(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)))
(这个没测试过,不过应该可以,不然早上更新)