Fork me on GitHub
#graphql
<
2017-09-14
>
hmaurer12:09:55

@karlstefan can you explain your problem in a bit more details and/or post your schema (and resolvers)?

karlstefan12:09:56

Anyone here got experience with lacinia? I'm writing a graphQL proxy for a REST api, and I'm having problems traversing the REST endpoint and building tree data based on the response.

karlstefan12:09:00

Give me asec

hmaurer12:09:10

I have some (limited) experience with Lacinia

hmaurer12:09:14

but hopefully enough to answer your query

karlstefan12:09:40

Uhm, what paste tool do you prefer for edn files?

hmaurer12:09:18

@karlstefan I tend to use gist

karlstefan12:09:45

It works for the first level

hmaurer12:09:45

@karlstefan can you paste your resolvers too please?

hmaurer12:09:44

(you can put multiple files in a single gist by the way :p)

hmaurer12:09:53

can you also paste a sample reply from your API?

karlstefan12:09:53

oh, thanks hehe

hmaurer12:09:55

also when do you use the read-object-key resolver?

karlstefan12:09:49

The api is constructed with different 'model roots', which correspons to whatever domain the data belongs to. If the client/request-backend is called with nil it returns all of them in a hashmap.

karlstefan12:09:55

This works, I've tested it.

karlstefan12:09:14

But building the three from object { children { object { children ... etc does not

karlstefan12:09:33

When the endpoint answers a call for an rid, and the object has children, it is returned as an array with of objects, and they all have the keys :rid :name :id

karlstefan12:09:05

Somehow the object does not resolve children objects

hmaurer12:09:35

can you tell me what the result of (get :body) is in read-object-rid?

hmaurer12:09:44

(what the value returned by the resolver is)

karlstefan12:09:01

Thats the body of an REST call, contains json data that is converted to a hashmap

karlstefan12:09:19

(get :status) would yeild i.e 200 for OK or 401 for auth fail

hmaurer12:09:19

so it contains the data that’s under the object key?

hmaurer12:09:30

or is it wrapped in data -> object -> ...

hmaurer12:09:04

oh nevermind sorry, that’s your reply from the graphql API

hmaurer12:09:12

I meant to ask if you could paste the response from your backend API

hmaurer12:09:25

then one you call with client/request-backend

hmaurer12:09:43

just to see the json structure there

karlstefan12:09:12

Oh, sure I'll show what a curl does. (I'm not sure how to pipe output in the REPL)

hmaurer12:09:26

a curl will do 🙂

karlstefan12:09:26

Thats an object which has children

karlstefan12:09:51

There is a lot going on in that output, but only the rid, and children are relevant properties

hmaurer12:09:16

oh hang on, actually I think the issue is pretty simple

hmaurer12:09:23

you cannot have a resolver for an object

hmaurer12:09:30

the key :resolve under an object has no meaning

hmaurer12:09:39

I didn’t spot it at first

hmaurer12:09:11

resolvers only make sense on fields (or queries, which are essentially fields)

hmaurer12:09:22

so you need to put a resolver on :children

hmaurer12:09:35

which will be given the array of children

karlstefan12:09:37

under :Object?

karlstefan12:09:04

I see, so just to be clear, I put the resolver under :object {:Object and not :queries ?

hmaurer12:09:51

the resolver should be here:

:children {:type (list Object) :resolve :my-resolver}

hmaurer12:09:55

(under the Object)

hmaurer12:09:08

you need to have one under queries too, to get the initial object from the API

hmaurer12:09:20

but after that (to traverse nested children), it will use the field resolver

karlstefan12:09:33

I see, lemme try! 😄

karlstefan12:09:33

I'm probably being stupid now, but I need a new resolver for this, right?

hmaurer12:09:58

the one I posted in a comment

hmaurer12:09:08

(I did’t try it though, maybe I got it slightly wrong)

hmaurer12:09:31

(yes to you needing a new resolver, not being stupid :p)

hmaurer12:09:17

(1) get rid of :resolve :resolve-read-object-rid under :object :Object in your edn schema

hmaurer12:09:44

(2) add :resolve :my-resolver (or whatever other name you want) under :object :Object :fields :children

hmaurer12:09:11

then register a resolver under :my-resolver mapping to the following function (which I hopefully got right):

hmaurer12:09:17

(fn [context args _value]
  (map (fn [val]
              (:body (client/request-backend (:rid val)))) _value)

karlstefan12:09:33

I think the resolver function is wrong, the repl throws an "Unsupported binding form" error

hmaurer12:09:24

ah I missed a parentheses maybe?

hmaurer12:09:34

(fn [context args _value]
  (map (fn [val]
              (:body (client/request-backend (:rid val)))) _value))

karlstefan12:09:11

(defn read-objects-rid [context args _value] (map (fn [val (:body (client/request-backend (:rid val))) _value])))

karlstefan12:09:47

my bracket matcher at work

karlstefan12:09:42

"message": "Field resolver returned a single value, expected a collection of values.",

karlstefan12:09:53

from graph i QL

hmaurer12:09:37

@karlstefan are you sure you got the resolver right?

karlstefan12:09:45

counting brackets

hmaurer12:09:25

😄 are you sure you are using read-objects-rid and not read-object-rid too? @karlstefan

karlstefan12:09:17

Lets see now

karlstefan12:09:01

It seems to be working somehow, but its stuck in an infinite loop hitting the API

hmaurer12:09:14

well, that’s progress

hmaurer12:09:48

I am not sure how it could be stuck in an infinite loop though

karlstefan12:09:17

Thats a tricky one

karlstefan12:09:40

But I got something to go on now, thanks a lot for your help!

karlstefan12:09:12

I see the problem now

karlstefan12:09:21

I'm requesting an enormous tree

karlstefan12:09:24

@hmaurer Do you know whats passed in _value in the reducer?

hmaurer12:09:59

@karlstefan the value under children in the api payload

hmaurer12:09:11

@karlstefan ah hang on, no, sorry

hmaurer12:09:16

_value will be the full object

hmaurer12:09:45

instead of mapping over _value, try to map over (:children _value)

hmaurer12:09:53

as in

(fn [context args _value]
  (map (fn [val]
              (:body (client/request-backend (:rid val)))) (:children _value)))

hmaurer12:09:37

I think with the previous (wrong) code your client/request-backend was being called with nil as argument

hmaurer12:09:41

which blew everything up

karlstefan12:09:47

Thanks! 😄

hmaurer12:09:51

you’re welcome

karlstefan12:09:04

This is my first attempt at clojure, very excited!

hmaurer12:09:19

It’s a fun language 🙂

hmaurer12:09:50

So remember: resolves are always placed on fields, and they get passed the value of their containing object

hmaurer12:09:02

(queries are fields on a root “Query” object)

hmaurer12:09:17

(and mutations are fields on a root “Mutation” object)

karlstefan12:09:20

i see, so args in args and their value in _value

karlstefan12:09:30

Whats the context for then, if you dont mind me asking

hmaurer12:09:40

@karlstefan passing down some stuff to all resolvers. For example, you might want to pass down a database connection, the authentication status, etc

karlstefan13:09:16

Where would I specify what to pass down?

hmaurer13:09:36

when calling execute

hmaurer13:09:09

see, there they are passing two nil arguments

hmaurer13:09:16

it’s one of them; I can’t remember which

hmaurer13:09:35

ah, it’s the last one

hmaurer13:09:36

> The two nils are variables to be used executing the query, and an application context.

hmaurer13:09:11

e.g. (execute schema query nil {:answer 42})

hmaurer13:09:34

and you would then be able to retrieve :answer in resolvers on the first argument

hmaurer13:09:46

note that if you printed out the first argument you would see a lot more than :answer

hmaurer13:09:58

that’s because Lacinia uses the context for its own bookkeeping

hmaurer13:09:14

you don’t need to care about that for now, but it does contain some useful stuff for more advanced use-cases

karlstefan13:09:50

I'll read up in the docs! 🙂 Thanks again for your time!

hlship21:09:21

Please do! We've worked hard on them. But always more to do.

karlstefan10:09:19

I watched and enjoyed your talk on YouTube, good stuff 🙂