Fork me on GitHub

I'm trying to convert the autocomplete demp ( to use pathom. I cannot get the resolver to handle the query (the resolver is being registered). The original query looks like this.

(defquery-root :autocomplete/airports
  (value [env {:keys [search]}] (airport-search search)))
this is my pathom resolver
(defresolver autocomplete-airports
  [env {:autocomplete/keys [search]}]
  {::pc/input  #{:autocomplete/search}
   ::pc/output [:autocomplete/airports]}
  (log/info "Resolving Airport search")
  {:autocomplete/airports (airport-search search)})


At first glance your resolver looks fine; I think we will need more information on what is going wrong to help you out


Hmm, I'm trying to integrate this autocomplete example in to a bare bones lein new fulcro project. My transact gets logged by the parser Pathom transaction: [(:autocomplete/airports {:autocomplete/search "abc"})] i see my resolver in the pathom-registry.

#object[zenchor.model.user$autocomplete_airports__31708 0xf84740c "[email protected]"],
  :com.wsscode.pathom.connect/input #{:autocomplete/search},
  :com.wsscode.pathom.connect/output [:autocomplete/airports]


but the resolver just never gets called


Are there any other details i could give?


@U7V6UECH1 you shouldn’t run a transaction to call a pathom resolver; you should run a load (with df/load)


transactions map to Pathom mutations


ach sorry my bad there. Yeah it's doing a load

              component ; state
              :autocomplete/airports ;store it under this key, also what to query for
              nil ; don't load any query from a component
              {:params               {:autocomplete/search new-value} ; opts
               :marker               false
               :post-mutation        `populate-loaded-suggestions
               :post-mutation-params {:id id} :target               (conj (autocomplete-ident id) :autocomplete/loaded-suggestions)}))]


@U7V6UECH1 in what file did you define the pathom resolver?


model/user.clj (the file contains pathom resolvers )


I’m not too sure, sorry 😞


Thanks anyway for taking a look ^^


@U7V6UECH1 I have more time now, if you are around and if this is still an issue


I think the issue might be that you are passing the search value as a parameter, but your Pathom resolver is expecting it to be an input


but I have not personally used parameters yet so don’t take my word for it; just a lead


Thanks mate, that was exactly what i needed. Dropping the input field and pulling the search argument out of the params worked!

🎉 5

In the book, at chapter 25.1 ( , Dynamic Routing and Spliting. The routing and the rest looks fine, but I can't create join query from page componanet. How are you guys handling join query with dynamic routing? my query look like this

(fn [] [r/dynamic-route-key
           {[:znet-spa/active-cg '_] (prim/get-query ContentGroup)}])
but that return error
[ 13.114s] [znet.web-app.client.fulcro.client.routing] Route load failed for :content-group-page. Attempting retry.
Ok, I think there were a bug from Fulcro itself. The error message came when I do join with component that has recursive query on it. :The ContentGroup component:
(defsc ContentGroup [this {::cg/keys [id] :as props}]
  {:query (fn [] [::cg/id
                  {::cg/sub '3}
   :ident (fn [] [::cg/by-id id])
   :initial-state (fn [_] {::cg/id 2
                           ::cg/name "momonosuke"
                           ::cg/slugged-name "momonusuke"
                           ::wp/content "jabaja"
                           ::cg/sub [{::cg/id 3 ::cg/name "tatsu"}]
  (let []
      (dom/pre (with-out-str (cljs.pprint/pprint props)))
      (dom/h2 "This is Content Group"))))

Mark Addleman20:02:28

Tutoring question of the day: I have started with the fulcro lein-template and modified the upsert-user mutation to require several address attributes. My understanding of pathom is that it will determine that user-address-resolver can supply the address info given a :user/id so address values will be supplied to upsert-user. That isn't happening. Instead, the upsert-user mutation is being invoked with nil for the address attributes.

(defmutation upsert-user
  "Add/save a user. Required parameters are:

  :user/id - The ID of the user
  :user/name - The name of the user

  Returns a User (e.g. :user/id) which can resolve to a mutation join return graph.
  [{:keys [config ring/request]} {:user/keys [id name]
                                  :address/keys [street city state postal-code]}]
  {::pc/params #{:user/id :user/name
                 :address/street :address/city :address/state :address/postal-code}
   ::pc/output [:user/id]}
  (log/debug "Upsert user with server config that has keys: " (keys config))
  (log/debug "Ring request that has keys: " (keys request))
  (log/debug "Address info" [street city state postal-code])
  (when (and id name)
    (swap! user-database assoc id {:user/id   id
                                   :user/name name})
    ;; Returning the user id allows the UI to query for the result. In this case we're "virtually" adding an address for
    ;; them!
    {:user/id id}))


I don’t think that’s how it works for mutation params


Only for resolvers


@mark340 hello mark, in mutations your params will never be auto-completed, you get as is


what pathom would do for you is find the name if you request it in a mutation response


something like: [{(upsert-user {:user/name "..." :user/id "..."}) [:user/id :user/name]}]


you could also request a lookup yourself inside of your mutation if that's desired (but most times it's not):

Mark Addleman21:02:58

I guess I'm a little surprised that the mutation doesn't work the same way as the resolver. Seems like the symmetry would cut down on some code in typical cases.


from experience I think if we got that way people would get a lot of confusing results, like you send incomplete information, pathom tries to figure but gets something that's not coherent, and I can tell you that I rarely need to call resolution in mutations, usually their input needs to come from the client


that said, you can trigger a resolve yourself, example:


(defmutation create-user
  [env params]
  {::pc/params [:user/id :user/name]
   ::pc/output [:user/id]}
  (let-chan [{:keys [user/name]}
             (p/entity! (assoc env ::p/entity params) [:user/name])]


@mark340 and one more thing, the ::pc/params format is a vector like output, doesn't matter now but might matter in the future

Mark Addleman21:02:46

Where does let-chan come from?

Mark Addleman21:02:57

And while I'm picking brains 🙂 ... Is there a way to hot reload mutations / resolvers without restarting the server?


let chan comes from [com.wsscode.common.async-clj :refer [let-chan]]

👍 5

the auto-reload depends a lot, no fixed answer at this time

Mark Addleman21:02:51

I took a naive approach to reload by changing defpathom-endpoint* to create a delegate fn:

(defn defpathom-endpoint* [endpoint args]
  (let [{:keys [sym arglist doc config body]} (util/conform! ::mutation-args args)
        config (dissoc config :security)
        env-arg (first arglist)
        params-arg (second arglist)]
       (defn ~(symbol (str sym "'")) [env# params#]
         (let [~env-arg env#
               ~params-arg params#]
           [email protected]))
       (~endpoint ~(cond-> sym
                           doc (with-meta {:doc doc})) [env# params#]
         ;; Example of how to integrate a security check into all mutations and resolvers
         #_(let [~env-arg env#
                 ~params-arg params#]
             [email protected])
         (~(symbol (str sym "'")) env# params#))
       (meetingz.server-components.pathom-wrappers/register! ~sym))))