Избегать повторения при использовании 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)})]))
Есть ли элегантный способ избежать повторений имен ключей? Что-то вроде метода конструктора, где я могу просто передать значения? (возможно в каком-то определенном порядке)
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)))
(не проверял этот, но он должен работать. иначе обновит его утром)