This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-06
Channels
- # announcements (12)
- # asami (3)
- # babashka (59)
- # beginners (20)
- # biff (1)
- # calva (87)
- # cherry (8)
- # clj-kondo (41)
- # clj-together (4)
- # cljdoc (5)
- # cljfx (4)
- # cljs-dev (2)
- # cljsrn (6)
- # clojure (63)
- # clojure-europe (22)
- # clojure-nl (1)
- # clojure-norway (35)
- # clojure-uk (4)
- # clojurescript (5)
- # conjure (2)
- # datalevin (4)
- # datascript (8)
- # datomic (16)
- # events (1)
- # figwheel-main (1)
- # fulcro (9)
- # hyperfiddle (4)
- # introduce-yourself (1)
- # jobs (3)
- # kaocha (10)
- # lambdaisland (2)
- # lumo (7)
- # nbb (1)
- # off-topic (29)
- # pathom (15)
- # re-frame (80)
- # releases (1)
- # remote-jobs (4)
- # shadow-cljs (13)
- # spacemacs (9)
- # sql (25)
- # squint (32)
- # tools-deps (6)
- # uncomplicate (6)
- # xtdb (15)
For instance, I have obtained an error with error-data
being nil
, which I didn't expect:
{:com.wsscode.pathom3.error/error-message "Don't know how to create ISeq from: clojure.lang.Symbol", :com.wsscode.pathom3.error/error-data nil, :com.wsscode.pathom3.error/error-stack "java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol\n\tat clojure.lang.RT.seqFrom(RT.java:557)\n\tat clojure.lang.RT.seq(RT.java:537)\n\tat clojure.lang.APersistentMap.cons(APersistentMap.java:40)\n\tat clojure.lang.RT.conj(RT.java:677)\n..."}
Pathom-relevant part of the stack trace, btw:
at clojure.core$update_in.invokeStatic(core.clj:6175)
at clojure.core$update_in.doInvoke(core.clj:6161)
at clojure.lang.RestFn.invoke(RestFn.java:467)
at edn_query_language.core$call__GT_ast.invokeStatic(core.cljc:154)
at edn_query_language.core$call__GT_ast.invoke(core.cljc:151)
at edn_query_language.core$expr__GT_ast.invokeStatic(core.cljc:207)
at edn_query_language.core$expr__GT_ast.invoke(core.cljc:199)
at clojure.core$map$fn__5880$fn__5881.invoke(core.clj:2746)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:343)
at clojure.core$transduce.invokeStatic(core.clj:6885)
at clojure.core$into.invokeStatic(core.clj:6901)
at clojure.core$into.invoke(core.clj:6889)
at edn_query_language.core$query__GT_ast.invokeStatic(core.cljc:165)
at edn_query_language.core$query__GT_ast.invoke(core.cljc:158)
at com.wsscode.pathom3.interface.eql$process.invokeStatic(eql.cljc:67)
at com.wsscode.pathom3.interface.eql$process.invoke(eql.cljc:35)
at com.wsscode.pathom3.interface.eql$boundary_interface$boundary_interface_internal__54301.invoke(eql.cljc:192)
at com.wsscode.pathom3.interface.eql$boundary_interface$boundary_interface_internal__54301.invoke(eql.cljc:196)
do you believe this is a bug in pathom? im not sure from that stack, if so, please send a repro and I'll be happy to look into it :)
I think the error-data
obtained from boundary-interface
should never be nil
, and boundary-interface
should specify how to distinguish when there has been an error in the EQL query, or an exception thrown by resolvers, or an exception in the Pathom engine. I will look into how to reproduce the error above. I think it was just an incorrect EQL txn.
Thanks for your response.
Hi gang, a bit of a long-shot question. I've lately been thinking and reading about hexagonal/[diplomat](https://youtu.be/ct5aWqhHARs) architectural patterns and was ruminating on how to marry this with Pathom mutations. The #interceptors approach (cfr Sieppari and Pedestal) offers a nice way of composing functionality using interceptor operators on a context map. Now my question is: when using Fulcro/Pathom, how could I break up a classic pathom mutation into an interceptor chain or part of an interceptor chain?
Roughly the interceptor chain would consist of:
:enter phase
=> [param coercion] -> [param resolution (using pathom)] -> [do permission checks] -> [pure functional business logic operation on ctx map (aka mutation body)] -> ["sync" side-effects (e.g. db transactions)] -> ["async" side effect (e.g. posting messages to queues)]
:leave phase
=> [resolving eql mutation join] -> [redaction of eql results in function of authorization policy rules] -> [error response handling]
The two steps in bold are what typical processing of a pathom mutation entails, but in the above schematic they are broken up into two discrete interceptor phases. I'm thinking in the direction of having an interceptor at the start of the chain the inspects the eql AST and dynamicall injects the interceptor building blocks in the chain, based on a data representation that describe pathom mutations (name, params and body) as well as the interceptor chains involved.
The main objective of this approach would be to increase the compositional nature of mutations in a Fulcro/Pathom app.
Thoughts, comments, ideas?
The pathom plugin systems might be a good starting point for this. It's not explicitly mentioned in the Pathom docs, but the https://pathom3.wsscode.com/docs/plugins#adding-plugins looks exactly like an interceptor-based system.
Also worth looking at ::pco/transform
https://pathom3.wsscode.com/docs/resolvers/#resolver-transform
@U052A8RUT I landed on this exact pattern after learning pedestal https://github.com/dvingo/my-clj-utils/blob/99d3820b1b2bc77ba33c792b493017645786b947/src/main/dv/pathom.clj#L187 I made this helper some time ago, I have a more recent version in a project that uses sieppari instead because it has cljc support
the pathom context substitutes exactly for the pedestal context in a http request lifecycle
hello @U052A8RUT, as you found out, the plugins is the right way to handle that generically for a pathom system, also as @U49U72C4V pointed out, the ::pco/transform
is another way to extract this kind of behavior, but instead of applying it globally, its uses are per mutation case.
and here is the sieppari version https://gist.github.com/dvingo/95e3dc2be3d7d1629079f459b9086a1e
note that sieppari is apparently being sunset, but this https://github.com/exoscale/interceptor is a good alternative
@U051V5LLP oh is it? Good to know, thanks. Thanks all for sharing your perspective.
๐งช๐ฌ:male-scientist: ๐งซ I cooked up something to illustrate my idea:
https://gist.github.com/tmoerman/c4c863c00e5364932ad209f921d9e7d2
Instead of running interceptors in a mutation body, the eql-processor becomes a (2-phase) interceptor itself!
I used 2 Pathom plugins, each of which is added to the env
to modify the behavior of p.eql/process
: one for the :enter
phase of an interceptor, one for the :leave
phase. This means the p.eql/process
fn is run twice.
In :enter
the result of the mutation step is captured in acc
atom, the mutation join is stripped off the ast
.
In :leave
the captured result is used instead of executing the mutation.
With some more plumbing, I would then only allow pure functions in the mutation body, capturing transactions and other side-effects in the interceptor context map, for other downstream interceptors to pick up and apply. When the :leave
phase of the eql-processing interceptor is reached, the side effects have already been done and the mutation join is sure to resolve data in function of an updated DB.
Not sure this approach will turn out to be more useful than running an interceptor stack in mutation bodies, but I had a good time learning about pathom plugins ๐ The plugin system is very cool @U066U8JQJ!
What do you guys think? Cheers!