Created
October 27, 2017 12:45
-
-
Save danielneal/537b18d4532560529e92dd4f214a6ecf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns app.graphql-interceptor | |
(:require [re-frame.core :as reframe :refer [->interceptor]] | |
[cljs.spec.alpha :as s] | |
[app.reg-event :refer [reg-event-fx]] | |
[app.util :as util] | |
[clojure.set :as set])) | |
(set! *warn-on-infer* true) | |
(def graphql->http | |
(->interceptor | |
:id :graphql->http | |
:after (fn [context] | |
(let [token (get-in context [:coeffects :db :app.db/auth :auth/token]) | |
db (get-in context [:coeffects :db])] | |
(update context :effects | |
(fn [effects] | |
(let [{:keys [graphql]} effects] | |
(if graphql | |
(do | |
(s/assert :graphql-interceptor/data graphql) | |
(let [{:keys [on-success on-unauthorized on-failure query variables timeout-ms]} (s/conform :graphql-interceptor/data graphql)] | |
(-> effects | |
(assoc :http {:url (util/route-for db :routes.api/graphql) | |
:method "POST" | |
:headers (cond-> | |
{"Accept" "application/json" | |
"Content-Type" "application/json"} | |
token (assoc "authorization" (str "Bearer " token))) | |
:params {:query query | |
:variables variables} | |
:timeout-ms timeout-ms | |
;; Wrap success response, because there may be errors | |
:on-success [:handlers.graphql.http-response/success {:on-success on-success, :on-failure on-failure, :on-unauthorized on-unauthorized}] | |
:on-failure [:handlers.graphql.http-response/failure {:on-success on-success, :on-failure on-failure, :on-unauthorized on-unauthorized}]}) | |
(dissoc :graphql)))) | |
effects)))))))) | |
;; At the moment we only handle one special graphql error - the unauthorized error. | |
(defn graphql-error->error | |
[error] | |
(-> error | |
(update :error/type (fn [error-type] | |
(case error-type | |
"error.types.auth/unauthorized" :error.types/unauthorized | |
:error.types/unidentified))))) | |
(reg-event-fx | |
:handlers.graphql.http-response/success | |
(fn [{:keys [db]} [_ {:keys [on-success on-unauthorized on-failure]} {:keys [data errors]}]] | |
;; Graphql errors come through as http 200 | |
;; This handler, when combined with the graphql->http interceptor | |
;; ensures the _on-failure handler_ of graphql gets called if | |
;; errors are present. | |
(let [errors (map graphql-error->error errors) | |
unauthorized? (and (seq errors) (some #(= (:error/type %) :error.types/unauthorized) errors)) | |
expired-session? (and (contains? (get data :me) :customer_id) | |
(nil? (get-in data [:me :customer_id])))] | |
(cond | |
(and (or unauthorized? expired-session?) on-unauthorized) {:dispatch (conj on-unauthorized {:data data, :errors errors})} | |
(and (or unauthorized? expired-session?) (not on-unauthorized)) {:dispatch (conj on-failure {:data data, :errors errors})} | |
(empty? errors) {:dispatch (conj on-success {:data data})} | |
:else {:dispatch (conj on-failure {:data data, :errors errors})})))) | |
(reg-event-fx | |
:handlers.graphql.http-response/failure | |
(fn [{:keys [db]} [_ {:keys [on-unauthorized on-failure]} {:keys [errors]}]] | |
(if (and on-unauthorized (some #(= (:error/type %) :error.types/unauthorized) errors)) | |
{:dispatch (conj on-unauthorized {:errors errors})} | |
{:dispatch (conj on-failure {:errors errors})}))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment