I have defined the following schema:
(s/defschema Card
{:cardNumber s/Str
:cvv s/Str
:creditCardMonthValidity s/Str
:creditCardYearValidity s/Str
:cpf s/Str
:name s/Str
:phoneNumber s/Str})
and then in a route I'm using the same keys in the JSON response:
(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)})]))
is there an elegant way to avoid the repetitions of the key names? Something like a constructor method where i can just pass in the values? (maybe in some specific order)
something like this could work: you can define a macro that defines schema and constructor at once.
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)]})
this defresponse would be expanded into the following:
(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)}))
and then you can use your schema as usual, and card-response
like this:
(let [checkout (CheckoutApi/show checkoutId accessToken)
card (.getCard checkout)
contact (.getContact checkout)]
(ok (card-response card contact)))
(haven't tested this one, but it should work. otherwise will update it in the morning)