clojure - How to remove duplication in request validation? -
i have compojure app set of routes , handlers.
(defroutes app-routes (get "/stuff/:id" [:as request] (stuff/get-stuff request)) (post "/stuff/" [:as request] (stuff/create-stuff request))
each handler validates input, so
(defn create-stuff [request] (my-validation/validate-request request my-validation/create-stuff-validator stuff-ok-fn))
the validation code based on metis, , looks this:
(metis/defvalidator :create-stuff-validator [:db :presence]) (defn validate-request [request request-validator ok-function] (let [validation-result (request-validator request)] (if (empty? validation-result) (ok-function request) (bad-request validation-result))))
my problem code in create-stuff duplicated across each of route handlers; i.e get-stuff function looks create-stuff handler. thing differs validator function , the-validation-went-well-function.
how can abstract duplication in idiomatic clojure manner?
since functional language, suggest passing functions differentiate handlers generic handler function.
;;; in core.clj (defroutes app-routes (get "/stuff/:id" [:as request] (handlers/handle my-validation/get-stuff-validator stuff/get-stuff-ok-fn request)) (post "/stuff/" [:as request] (handlers/handle my-validation/create-stuff-validator stuff/create-stuff-ok-fn request))) ;;; in handlers.clj (defn handle [validator action request] (let [validation-result (validator request)] (if (empty? validation-result) (action request) (bad-request validation-result))))
stylistically, suggest code easier read if avoid the smurf naming convention. namespace tells if validating, or "stuff" operating on, don't need include in name of function. also, fact passing argument should callable sufficient, don't need put fn in name of function, fact passed ok branch tells thing when things go ok.
;;; in core.clj (defroutes app-routes (get "/stuff/:id" [:as request] (handlers/handle my-validation/get-stuff stuff/get request)) (post "/stuff/" [:as request] (handlers/handle my-validation/create-stuff stuff/create request))) ;;; in handlers.clj (defn handle [validator ok request] (let [errors (validator request)] (if (empty? errors) (ok request) (bad-request errors))))
if can reduce verbosity without losing clarity, improve correctness, because errors hide in verbosity.
Comments
Post a Comment