-
-
Save awkay/86a3d7b3be912f79961e7bffba91a6f2 to your computer and use it in GitHub Desktop.
Pathom Wrapper Macros (Pathom 2)
This file contains 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.lib.pathom.connect-macros | |
(:require | |
[app.lib.pathom.registry :refer [register!]] | |
[clojure.spec.alpha :as s] | |
[com.fulcrologic.fulcro.algorithms.do-not-use :as futil] | |
[com.wsscode.pathom.connect :as pc] | |
[com.wsscode.pathom.core :as p] | |
[taoensso.timbre :as log] | |
[taoensso.tufte :as tufte])) | |
(def ^:dynamic *disable-permissions* false) | |
(s/def ::check (s/or :sym symbol? :expr list?)) | |
(s/def ::mutation-args (s/cat | |
:sym simple-symbol? | |
:doc (s/? string?) | |
:arglist vector? | |
:config map? | |
:body (s/* any?))) | |
(defn defpathom-backend-endpoint* [endpoint args update-database?] | |
(let [{:keys [sym arglist doc config body]} (futil/conform! ::mutation-args args) | |
internal-fn-sym (symbol (str (name sym) "__internal-fn__")) | |
fqsym (if (namespace sym) | |
sym | |
(symbol (name (ns-name *ns*)) (name sym))) | |
{:keys [check ex-return]} config | |
config (dissoc config :check :ex-return) | |
env-arg (first arglist) | |
params-arg (second arglist) | |
ex-msg (str fqsym " unauthorized, " check " violated")] | |
(when (nil? check) | |
(throw (IllegalArgumentException. "Config map MUST contain a :check key"))) | |
`(do | |
;; Use this internal function so we can dynamically update a resolver in | |
;; dev without having to restart the whole pathom parser. | |
(defn ~internal-fn-sym [env# params#] | |
(let [~env-arg env# | |
~params-arg params# | |
result# (if (or *disable-permissions* (~check {:env env# :params params#})) | |
(do | |
(when *disable-permissions* | |
(log/debug "Permissions disabled. Allowing resolver")) | |
(log/debug "Permissions passed for" (quote ~fqsym)) | |
(tufte/p (quote ~fqsym) | |
~@body)) | |
(do | |
(log/error ~ex-msg {:params params# | |
:query-params (:query-params env#)}) | |
nil))] | |
;; Pathom doesn't expect nils | |
(cond | |
(sequential? result#) (vec (remove nil? result#)) | |
(nil? result#) {} | |
:else result#))) | |
(~endpoint ~(cond-> sym | |
doc (with-meta {:doc doc})) [env# params#] | |
~config | |
(~internal-fn-sym env# params#)) | |
(app.lib.pathom.registry/register! ~sym) | |
::done))) | |
(defmacro | |
^{:doc "Defines a server-side PATHOM mutation. | |
Example: | |
(defmutation do-thing | |
\"Optional docstring\" | |
[params] | |
{::pc/input [:param/name] ; PATHOM config (optional) | |
::pc/output [:result/prop] | |
:check security-check} | |
...) ; actual action (required)" | |
:arglists '([sym docstring? arglist config & body])} defmutation | |
[& args] | |
(defpathom-backend-endpoint* `pc/defmutation args true)) | |
(defmacro ^{:doc "Defines a pathom resolver but with authorization. | |
Example: | |
(defresolver resolver-name [env input] | |
{::pc/input [:customer/id] | |
:check s.checks/ownership | |
...} | |
{:customer/name \"Bob\"}) | |
" | |
:arglists '([sym docstring? arglist config & body])} defresolver | |
[& args] | |
(defpathom-backend-endpoint* `pc/defresolver args false)) | |
(defn final | |
"Tell Pathom the result is complete, and needs no further resolution. | |
This is a performance optimization. | |
Use this around collections being returned by a resolver when you are *certain* that the real query for the item(s) | |
in question are *completely* resolved. Pathom will stop working on those items. | |
Examples: | |
* A resolver returning `{:x [...]}` should instead return `{:x (final [...])}`. | |
* A resolver using a helper function that returns a map with a nested collection can use the arity 2 of this function: | |
`(final :x result)`, which is just a convenient form for `(update result :x final)` | |
" | |
([data] | |
(some-> data (vary-meta assoc ::p/final true))) | |
([at-k data] | |
(some-> data | |
(update at-k vary-meta assoc ::p/final true)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment