Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to manipulate handler response from the parser #20

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 16 additions & 1 deletion specs/untangled/server/impl/components/handler_spec.clj
@@ -1,6 +1,7 @@
(ns untangled.server.impl.components.handler-spec
(:require [untangled-spec.core :refer [specification assertions provided component behavior]]
[clojure.test :as t]
[untangled.server.core :refer [augment-response]]
[untangled.server.impl.components.handler :as h]
[com.stuartsierra.component :as component]
[om.next.server :as om]
Expand Down Expand Up @@ -34,12 +35,16 @@
(specification "An API Response"
(let [my-read (fn [_ key _] {:value (case key
:foo "success"
:foo-session (augment-response {:some "data"} #(assoc-in % [:session :foo] "bar"))
:bar (throw (ex-info "Oops" {:my :bad}))
:bar' (throw (ex-info "Oops'" {:status 402 :body "quite an error"}))
:baz (throw (IllegalArgumentException.)))})

my-mutate (fn [_ key _] {:action (condp = key
'foo (fn [] "success")
'overrides (fn [] (augment-response {} #(assoc % :body "override"
:status 201
:cookies {:foo "bar"})))
'bar (fn [] (throw (ex-info "Oops" {:my :bad})))
'bar' (fn [] (throw (ex-info "Oops'" {:status 402 :body "quite an error"})))
'baz (fn [] (throw (IllegalArgumentException.))))})
Expand Down Expand Up @@ -111,7 +116,17 @@
:data {:my :bad}}

(get-error baz-result) => {:type "class java.lang.IllegalArgumentException",
:message nil}))))))))
:message nil}))))))

(behavior "for updating the response"
(behavior "adds the response keys to the ring response"
(let [result (parse-result [:foo-session])]
(assertions
(:session result) => {:foo "bar"})))
(behavior "user can override response status and body"
(assertions
(parse-result ['(overrides)])
=> {:status 201, :body "override", :cookies {:foo "bar"}})))))

(def run #(%1 %2))
(specification "the handler"
Expand Down
20 changes: 20 additions & 0 deletions src/untangled/server/core.clj
Expand Up @@ -24,6 +24,26 @@
[a->b b->c]
(reduce (fn [result k] (assoc result k (->> k (get a->b) (get b->c)))) {} (keys a->b)))

(defn augment-response [core-response ring-response-fn]
"Augments the Ring response that's returned from the handler.

Use this function when you need to add information into the handler response, for
example when you need to add cookies or session data. Example:

(defmethod my-mutate 'user/sign-in [_ _ _]
{:action
(fn []
(augment-response
{:uid 42} ; your regular response
#(assoc-in % [:session :user-id] 42) ; a function resp -> resp
))})

If your parser has multiple responses with `augment-response`, they will be applied
in order, the first one will receive an empty map as input. Only root keys of your
response will be checked for augmented response.
"
(with-meta core-response {::augment-response ring-response-fn}))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OpenID helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down
6 changes: 5 additions & 1 deletion src/untangled/server/impl/components/handler.clj
Expand Up @@ -82,6 +82,10 @@
(assoc acc k v)))
{} resp))

(defn collect-response [data]
(->> (keep #(some-> (second %) meta :untangled.server.core/augment-response) data)
(reduce (fn [response f] (f response)) {})))

(defn api
"The /api Request handler. The incoming request will have a database connection, parser, and error handler
already injected. This function should be fairly static, in that it calls the parser, and if the parser
Expand All @@ -91,7 +95,7 @@
[{:keys [transit-params parser env] :as req}]
(let [parse-result (try (raise-response (parser env transit-params)) (catch Exception e e))]
(if (valid-response? parse-result)
{:status 200 :body parse-result}
(merge {:status 200 :body parse-result} (collect-response parse-result))
(process-errors parse-result))))

(defn generate-response
Expand Down