Fork me on GitHub
#graphql
<
2018-03-09
>
urzds13:03:13

I have a question regarding Lacinia. I am wondering why resolver-map is a function, in https://lacinia.readthedocs.io/en/latest/tutorial/init-schema.html#schema-namespace It appears it is rather static, i.e. not requiring to be executed at run time. Any idea why the authors choose to make it a function anyway?

hlship14:03:06

This is just the tutorial; I wrote it this way because I knew I would be changing it later. I want the tutorial to be, as much as possible, a slow, small drip of understandable changes, refactoringa, improvements, and introductions of new ideas. Read on.

souenzzo13:03:34

@urzds you can, for example, on application init process, first connect to db, then call this resolver-map that will be "dynamic generated" basead on database. After all this, start the HTTP server

urzds13:03:44

Ok, so it is not required in this example, but there might be a use-case where it could be necessary to dynamically generate the resolver-map?

gklijs13:03:37

Yes, for example if you consume from kafka and the schema is changed from int to long, and you went the app to stay running, or maybe more relevant you found a bug in the resolver and you want to deploy the fix in a repl, or still more relevant your developing and made an error so your not getting back the correct values?

urzds13:03:35

But in the deploy-fix-via-REPL and developing-and-want-to-correct-something cases, I could as well re-execute a (def ...) in the REPL, could I not?

urzds13:03:14

Sorry if the question appears very basic, but I don't have that much experience in this area.

urzds13:03:32

Could you maybe give me a practical example (i.e. some code), where the resolver-map is a function and cannot easily be a var?

hlship14:03:24

Try the next page of the tutorial.

urzds13:03:40

Right now both the keys and the values of the resolver-map do not seem like things that could not be defed. But as I said, I am probably just lacking the experience with more advanced use-cases.

gklijs14:03:56

I haven't really looked at them, I put my data in an atom matching the values, so didn't have to use resolvers at all.

timgilbert20:03:51

Say, in lacinia can I rely on (:type-name context) being the type I'm supposed to return from inside of a resolver?

hlship21:03:39

What's your use case?

timgilbert20:03:44

Oh, oops, was looking at the wrong place in the data structure, hmm. In general is there an API I can use to get the return type that I've declared I'm returning for a given field / query / etc?

timgilbert21:03:17

I seem to be able to get to it via (-> context :com.walmartlabs.lacinia.constants/parsed-query :selections first :field-definition :type :type) but that seems like it's a little implementation-specific, plus I'm not sure which fragment my resolver is working on if there are multiple

guy21:03:02

I seem to recall there was maybe a function mentioned in the tutorial which might help

guy21:03:12

let me have a gander

timgilbert21:03:30

Aha, I think you're right: http://lacinia.readthedocs.io/en/latest/resolve/type-tags.html#using-tag-with-type > When a field resolver is invoked, the context value for key :com.walmartlabs.lacinia/container-type-name will be the name of the concrete type (a keyword) for the resolved value.

guy21:03:28

is that useful to you @timgilbert?

guy21:03:36

/what you wanted

timgilbert21:03:57

Somewhat, yeah. I'm finding that the value is nil in my top-level query resolver though

hlship21:03:40

It's the type of the containing field, not the type of the field being resolved. At the top, there is no containing field so it is nil.

hlship21:03:22

Lacinia doesn't expose this data and might have to expose it as a set (e.g., the members of a union or the implementers of an interface).

guy21:03:15

mmm interesting

guy21:03:07

I’m not sure thats what you want though :thinking_face:

guy21:03:32

You want to be able to extract from the context, what the return type that the resolver result should be?

guy21:03:16

I think its in the context

guy21:03:20

sorry i mean

timgilbert21:03:29

I'm using the same resolver for a few different queries that look for different things depending on some parameters I'm passing in the schema

guy21:03:51

interesting

guy21:03:57

Why not just split them out?

timgilbert21:03:22

For the most part it works fine without needing to specify types but in a few instances I might want slightly different behavior depending on the type

timgilbert21:03:48

I might be able to do that, but I'd like to keep it somewhat DRY if I can

guy21:03:57

ah sure sure

timgilbert21:03:28

I suppose I'll file a github issue, it does seem slightly like a bug that the value is nil in top-level queries

guy21:03:46

you might be doing it wrong i suppose

guy21:03:50

whats the code u are running?

guy21:03:39

maybe i could try and reproduce it

timgilbert21:03:26

Working on getting a small test case to work now, it's a little tough to extract from the rest of the code

guy21:03:53

ah sorry i just meant how getting the type out of the context

timgilbert21:03:37

Oh, that's just roughly:

(defn my-resolver
  [unique-attribute]
  (fn [context args value]
    (let [arg (:slug args)
          ref [unique-attribute arg]]
      (log/spy (:com.walmartlabs.lacinia/container-type-name context))
      {:my "thing"})))

timgilbert21:03:16

(Minus some complex stuff, but the main thing is that (:com.walmartlabs.lacinia/container-type-name context) is nil)

timgilbert21:03:19

...then the schema resembles

:queries
 {:get_person
  {:type    :Person
   :args    {:slug {:type (non-null ID)}}
   :resolve [:Query/EntityBySlug :person/slug]}

timgilbert21:03:15

On the back-end I'm hitting datomic, which takes a pretty dynamic-typing approach to data, so I can use this one resolver to look up a variety of fields that aren't necessarily the same type

guy21:03:23

i also get nil

guy21:03:36

how funny

timgilbert21:03:54

What I'm attempting to work towards is an interface where the resolver figures out that it's returning a :Person and its argument is a :slug and then it queries datomic for the entity with :person/slug "whatever"

guy21:03:44

well the simplest thing you could do is maybe

guy21:03:19

{:person/slug "thing} Then wrap ur resolver with a multi method and dispatch off the ns of the key

guy21:03:45

and have that query datomic maybe haha

guy21:03:04

:com.walmartlabs.lacinia/container-type-name never seems to give me a value

hlship21:03:53

There's no container value at the top level, so no type. It's for nested fields.

guy22:03:09

oooh got ya thanks man!

timgilbert21:03:08

I have something very similar to that working right now, yeah

timgilbert21:03:05

I'm thinking that it is probably set for the slug field if I query { get_person(slug: "foo") { slug } }

timgilbert21:03:11

But not the top-level query

timgilbert21:03:25

ie, the return value of get_person