Fork me on GitHub

Hi, i don't know how to create resolvers to do the following

(pc/defresolver api-1 [{:keys [root-query] :as env} params]
                {::pc/output [:api/uri]}
                (let []
                  {:api-1/uri "uri"}))

(pc/defresolver api-items-1 [{:keys [root-query] :as env} params]
                {::pc/input #{:api-1/uri}
                 ::pc/output [:items [[:key1
                (let []
                  {:items [{:key1 1
                            :key2 2}]}))

(pc/defresolver api-2 [{:keys [root-query] :as env} params]
                {::pc/output [:api-2/uri]}
                (let []
                  {:api-1/uri "uri"}))

(pc/defresolver api-items-2 [{:keys [root-query] :as env} params]
                {::pc/input #{:api-2/uri}
                 ::pc/output [:items [[:key3
                (let []
                  {:items [{:key3 3
                            :key4 4}]}))

;-> this is what i would like to obtain 
{:api-1/uri "uri"
 :api-2/uri "uri"
 :items [{:key1 1
          :key2 2
          :key2 3
          :key2 4}]}


I am completly lost, trying lot of things but can't find a good way


If someone has a tip for this ? Many Thanks


One quick thing - input (`::pc/input`) is usually a set.


yes sorry i did try to reproduce an exmaple with fake code so it is a set in my code sorry


My query looks like this



Did you put debug in each of them to see which ones are 'being fired'?


But just looking at api-1 your output does not match what is being returned. Same with api-2.


Yes once :items is returned the other is not fired


and api-2 should return api-2/uri made a typo in the fake code


Don't know if it is a good way but this now work :

(pc/defresolver api-1 [{:keys [root-query] :as env} params]
                {::pc/output [:api/uri]}
                (let []
                  {:api-1/uri "uri"}))
(pc/defresolver api-items-1 [{:keys [root-query] :as env} params]
                {::pc/input #{:api-1/uri}
                 ::pc/output [:items [[:key1
                (let []
                  {:items [{:key1 1
                            :key2 2}]}))
(pc/defresolver api-2 [{:keys [root-query] :as env} params]
                {::pc/output [:api-2/uri]}
                (let []
                  {:api-1/uri "uri"}))
(pc/defresolver api-items-2 [{:keys [root-query] :as env} params]
                {::pc/input #{:api-2/uri}
                 ::pc/output [:key3 :key4]}
                (let []
                  {:key3 3
                   :key4 4}))


If there is a better way to do that i'm interested Thanks,


this is not the good way ...


That looks about right, if you want to achieve:

{:api-1/uri "uri"
 :api-2/uri "uri"
 :items [{:key1 1
          :key2 2
          :key2 3
          :key2 4}]}
You can probably hide some of the boilerplate (if you wish) by dropping down to pathom.connect/resolver and generating the resolvers dynamically, instead of using the macros.


(although in your psuedocode, api-items-2 needs to also have the nested :items output)


Many thanks @pithyless if i add items in the second one it is not called


with an eql query: [:api-1/uri :api-2/uri {:items [:key1 :key2 :key3 :key4]}] ?


Yes it was the case With you’re recommandations I have a solution I think I’ll post it once sure it works


i have something like that work i just have to add test on api-1 . api-2 to see if some corresponding keys are requested or not since tey are systematically called. But is ok


(pc/defresolver api-sales [{:keys [root-query] :as env} {:keys [api]}]
                {::pc/output [:api-1/id
                (let [api-id :
                      [uri label ns-path] (first (acrux/api-details api-id))]
                  (println "sales-resolver")
                  {:api-1/id 1
                   :api-2/id 2}))
; (println "ennv" @(:com.wsscode.pathom.core/entity env))

(pc/defresolver api-1 [{:keys [group-by] :as env} params]
                {::pc/input #{:api-1/id}
                 ::pc/output #{:items1 [:key1 :key2 :store]}}
                (let []
                  (println "api1" params)
                  {:items1 [{:store :b :key1 3 :key2 4} {:store :a  :key1 3 :key2 4}]}))

(pc/defresolver api-2 [{:keys [group-by] :as env} params]
                {::pc/input #{:api-2/id}
                 ::pc/output #{:items2 [:key2 :key4 :store]}}
                (let []
                  (println "api2" params)
                  {:items2 [{:store :a :key3 3 :key4 4} {:store :b :key3 3 :key4 4}]}))

(defn group-by-key
  (group-by :store items))

(pc/defresolver api-all [{:keys [group-by] :as env} params]
                {::pc/input #{:items1
                 ::pc/output #{:items}}
                (let [items1 (group-by-key (:items1 params))
                      items2 (group-by-key (:items2 params))
                      result (map (fn [[k  v]]
                                    (apply merge v))
                                  (merge-with into  items1 items2))]
                  (println "api-all")
                  {:items result}))


the strange thing is that i can't do a group-by inside the resolver api-all. I should do it in another function ???


I use 2.3.0-alpha5


I don't see why you need api-all at all. I think the problem is that Pathom is not recognizing the output join:

::pc/output #{:items1 [:key1 :key2 :store]}
should rather be:
::pc/output [{:items [:key1 :key2 :store]}]


Also, is :api-1/id and :api-2/id something you want to return to the client? Or is it just a temporary variable you're passing around to resolve the other keys? IIUC, you have two apis that use different identifiers for the same "thing", but return a different subset of information about the "thing".


these two keys should also return the url api to call


When i do what you suggest, api-2 is not called


yes that's it i have multiples api that return differents informations and i need to consolidate these data together. (e.g. on store key)


with this code

(pc/defresolver api-1 [{:keys [root-query] :as env} {:keys [api]}]
                {::pc/output [:api-1/id
                (let []
                  (println "api-1")
                  {:api-1/id 1
                   :api-2/uri "uri1"}))
(pc/defresolver api-2 [{:keys [root-query] :as env} {:keys [api]}]
                {::pc/output [:api-2/id
                (let []
                  (println "api-2")
                  {:api-2/id 1
                   :api-2/uri "uri2"}))

(pc/defresolver api-1-items [{:keys [group-by] :as env} params]
                {::pc/input #{:api-1/id}
                 ::pc/output [{:items [:key1 :key2 :store]}]}
                (let []
                  (println "api-1-items" params)
                  {:items [{:store :b :key1 1 :key2 2}
                           {:store :a  :key1 1 :key2 2}]}))

(pc/defresolver api-2-items [{:keys [group-by] :as env} params]
                {::pc/input #{:api-2/id}
                 ::pc/output [{:items [:key3 :key4 :store]}]}
                (let []
                  (println "api-2-items" params)
                  {:items [{:store :a :key3 3 :key4 4}
                           {:store :b :key3 3 :key4 4}]}))
only api-sales and api-2 resolvers are called. so if i have a query like this
[{:items [:key1 :store :key3]}]
the result is:
{:items [{:key1 1, :store : :key3 :com.wsscode.pathom.core/not-found} {:key1 1, :store :a, :key3 :com.wsscode.pathom.core/not-found}]} 


here is the parser

(def parser
   {::p/env     {::p/reader [p/map-reader
                 ::p/placeholder-prefixes #{">"}}
    ::p/mutate  pc/mutate-async
    ::p/plugins [(pc/connect-plugin {::pc/register app-registry})


OK, I've tried to come up with a minimal case:

(pc/defresolver api-1 [env input]
  {::pc/output [:api-1/id]}
  {:api-1/id 1})

(pc/defresolver api-1-items1 [env input]
  {::pc/input #{:api-1/id}
   ::pc/output [{:items [:key1]}]}
  {:items [{:key1 1}]})

(pc/defresolver api-1-items2 [env input]
  {::pc/input  #{:api-1/id}
   ::pc/output [{:items [:key2]}]}
  {:items [{:key2 2}]})
This does not work as I would have expected:
[:api-1/id {:items [:key1 :key2]}]
=> ignores :key1 if all 3 resolvers are in parser; will return :key1 if api-1-items2 is not in parser
Never hit this "bug", because I never modeled split-joins this way. Maybe @wilkerlucio can weigh in?


(Tested with pathom 2.2.30)


@pithyless in my mind model, it's expected I think that app-items should return [{:items [:id]}] then you do :id -> :key1 and :id -> key2


That would work and probably how I would have done it myself; but still surprised it does not follow the depedency-graph, but instead probably stops on first resolver that returns something with :items. I would have expected that joins would not short-circuit like that. ¯\(ツ)


So, for clarity; the suggestion @ouvasam is to perhaps model it like this:

(pc/defresolver api-items [env input]
  {::pc/output [{:items [:api-1/id :api-2/id]}]}
  {:items [{:api-1/id 1
            :api-2/id 2}]})

(pc/defresolver api-1 [env input]
  {::pc/input #{:api-1/id}
   ::pc/output [:key1 :key2]}
  {:key1 1
   :key2 2})

(pc/defresolver api-2 [env input]
  {::pc/input  #{:api-2/id}
   ::pc/output [:key3 :key4]}
  {:key3 3
   :key4 4})
And then you query like this:
[{:items [:key1 :key2 :key3 :key4]}]

  [{:items [:api-1/id :api-2/id :key1 :key2 :key3 :key4]}]


I did something like this also but once :items is return it does not go throught the other resolvers


^ I tested the above code in my repl.


ah ok sorry i'll give it a try now


[{:items [:api-1/id :api-2/id :key1 :key2 :key3 :key4]}]
=> {:items [{:api-1/id 1, :api-2/id 2, :key2 2, :key1 1, :key3 3, :key4 4}]}


My problem is that api-1 api-2 return both a list of [`{:key1 1 :key2 2}]` not just a single hash-map


the more i think about this, the more the solution with a global resolvers that receive items1 and items2 to merge the results should be the safier


many thanks for taking some time for this !


Do you mean modifying it for batch requests?

(pc/defresolver api-1 [env input]
  {::pc/input #{:api-1/id}
   ::pc/output [:key1 :key2]
   ::pc/transform pc/transform-batch-resolver}
  (mapv #(fn [{:keys [:api-1/id]}]
           {:key1 1
            :key2 2})
Or that for a single api-1/id there will be multiple key1 's? That I would just model by returning it as a map of key1 => [values]


in my previous example, i d othe following api-1 return the uri from a db to get the items. api-1-items, use this uri to call an api and get the a list of keys (key1, key2). With this i do a single call for api1. A s there is lot of apis that return differents keys. if some keys from a different api are requested i'd like to do only one call by api. So api-2 work the same as api-1 but with a different uri and different keys. As i watched your video about pathom. I retain "FLAT" which is exactly what i need for the rest of the app. using namespaces keys is really interesting. Hope i am clear ? Another problem i have is that, all these apis don't return the same length of list. So i should be able to consolidate data in specific manners. That's why i think a global resolver should do the trick


Flat namespaced keys for different apis is IMO a good way to approach this problem.

👍 4

That is what i should do to prove that to my customer. I can make it work with this global resolver but i am new to pathom so if there is better solution to do i am interested


I did use triple stores for other jobs and uri's were very powerful


And thanks for your videos !


Please share links if you can 🙂 I only found “Domain Modeling with Datalog”;t=9s


Thanks, always nice to hear someone is getting something out of them. 😊 Need to go afk for a bit, good luck with the modeling ;]

👍 4