spotifyovercastrssapple-podcasts

elm-gql with Matthew Griffith

Matthew Griffith joins us to share his new type-safe GraphQL tool, and to compare the query builder and query generator approaches.
November 21, 2022
#70

Transcript

[00:00:00]
Hello, Jeroen.
[00:00:01]
Hello, Dillon.
[00:00:02]
You know what's starting to become almost as common as a Martin sighting on Elm Radio?
[00:00:09]
Are you talking about Matt's?
[00:00:11]
I am talking about our good friend Matt Griffith, who is back with us again today to talk about
[00:00:17]
Elm GQL.
[00:00:18]
Matt, thanks for coming back.
[00:00:19]
I'm glad to be back.
[00:00:20]
This is always a lot of fun.
[00:00:22]
Yes.
[00:00:23]
I hope your sleep has been more peaceful recently and your generation nightmares have subsided.
[00:00:29]
Yeah, you know, largely.
[00:00:30]
Largely.
[00:00:31]
I feel pretty good.
[00:00:33]
Yeah.
[00:00:34]
Thank you.
[00:00:35]
Thank you.
[00:00:36]
So now we're going from nightmares to epic battles between two GraphQL tool creators.
[00:00:46]
I wonder how epic this, how much of a fight this will be.
[00:00:50]
Fight of the century.
[00:00:51]
Yeah, I mean, mutual respect, you know, I think that's where it is.
[00:00:54]
Like, I don't know if it's, yeah.
[00:00:56]
No, I think it's a really interesting area.
[00:00:59]
So and I think we have some fundamentally different approaches, right?
[00:01:03]
And that's cool to talk about.
[00:01:05]
Yeah, absolutely.
[00:01:07]
So we've got two different approaches.
[00:01:08]
We've got Query Builder and Query Generator, which we'll get into.
[00:01:13]
Elm GQL is a query generator library.
[00:01:16]
So what is Elm GQL?
[00:01:18]
Tell us about it.
[00:01:19]
Yeah.
[00:01:20]
So Elm GQL, this is under the namespace of vendor inc slash Elm GQL, and the main approach
[00:01:26]
of the library is that you point it at a GraphQL schema and you point out a GraphQL schema.
[00:01:33]
It pulls down, like it introspects the schema, and then maybe you write some queries in your,
[00:01:38]
in like a local GraphQL file, some queries or mutations.
[00:01:42]
And when you run Elm GQL, the command line tool, it will read those queries or mutations.
[00:01:48]
So it's basically just a simple command line tool.
[00:01:51]
So you write a query, you write a query, and then you point it at a GraphQL schema.
[00:01:57]
It will make sure that there are no collisions in as far as like fields that basically might
[00:02:01]
need to be aliased.
[00:02:03]
And if everything, it'll either give you one of those Elm like nice messages, or just saying,
[00:02:09]
you know, maybe your declared variables aren't quite correct or like you're selecting on
[00:02:13]
fields that don't exist.
[00:02:15]
Use that file to ask for that data or run that mutation.
[00:02:19]
So this is a CLI that generates, that takes GraphQL schemas in GraphQL queries, enters
[00:02:26]
them into Elm code, which you can then import and start using as you see fits, right?
[00:02:33]
That's right.
[00:02:34]
It's not a Elm package at all.
[00:02:36]
It's just a CLI.
[00:02:37]
It's actually, yeah, it's actually not.
[00:02:38]
I realized that there wasn't a whole heck of a lot that I needed to actually be in a
[00:02:45]
package.
[00:02:46]
Like the actual API that is common across GraphQL APIs is not very big.
[00:02:51]
So like an example being like, oh yeah, you can map the result or whatever.
[00:02:56]
So instead of publishing a package that was maybe only a few functions to sort of help
[00:03:00]
you out, it just generates that file for you when it generates stuff.
[00:03:04]
Yeah.
[00:03:05]
That sounds good.
[00:03:06]
Yeah.
[00:03:07]
Right.
[00:03:08]
So if you were to try to workflow, like if someone were to try this out, the first thing
[00:03:11]
they would probably do would be to, you know, install the NPM package, coin it at a GraphQL
[00:03:18]
endpoint or a JSON file for a GraphQL schema.
[00:03:23]
That's right.
[00:03:24]
And then they would probably go to, you know, some GraphQL playground or some, you know,
[00:03:30]
insomnia or some sort of tool for playing around with GraphQL APIs.
[00:03:34]
There are a lot of nice tools because it's this like typed schema and it's a very tooling
[00:03:40]
focused community.
[00:03:42]
You use all these nice tools to auto complete out a GraphQL query in one of these tools,
[00:03:48]
execute it against the API, looks good.
[00:03:52]
And then you copy paste that string into a.gql file in your, I believe in your source
[00:03:58]
directory.
[00:03:59]
Yeah, that's right.
[00:04:00]
So generally my flow for writing these GraphQL files, I was using sort of insomnia, which
[00:04:06]
has a little GraphQL plugin for a while, but I found in VS code, you can just install a
[00:04:10]
good GraphQL plugin directly in VS code and then just create the file and you get the,
[00:04:16]
you know, the big thing, yeah, like you mentioned is the auto complete or like little squigglies
[00:04:20]
of a field is marked as deprecated.
[00:04:22]
You can sort of see like, oh, this was deprecated because of, and then when you say something's
[00:04:27]
deprecated in GraphQL, you give a reason.
[00:04:30]
So like a little text like, oh, you should be using this thing instead.
[00:04:33]
And the way code organization kind of works is that let's say you have a file that's called
[00:04:40]
like, you know, my queries.graphql and you put in a number of queries in there.
[00:04:45]
What will happen is there will be a folder generated right next to it called my queries.
[00:04:50]
And within it, there will be an individual Elm file for each query that is listed in
[00:04:56]
the file.
[00:04:57]
So what this means is you have two choices that I think could make sense depending on
[00:05:02]
your, your, your preference.
[00:05:05]
One of them is it means you can put these things sort of in line.
[00:05:07]
So like at vendor, we have each page has an API.graphql.
[00:05:13]
And then so you can go to that page and you can like introspect exactly what are the calls
[00:05:17]
that it makes and it generates it sort of, I suppose not in line, but basically co located
[00:05:23]
with the page that's using it.
[00:05:25]
I think it would be reasonable too, if you wanted to have a top level folder with just
[00:05:29]
all your graphql and just generate it there.
[00:05:32]
But this tool would allow you to do either.
[00:05:35]
So if you have multiple queries in a single GQL file, then it will create a folder with
[00:05:41]
multiple files.
[00:05:42]
That's right.
[00:05:43]
How are these files named?
[00:05:44]
Do you give names to your?
[00:05:46]
Yeah.
[00:05:47]
So there, so in, in graphql, you can add an optional tag, like a name to a query.
[00:05:53]
So there is a built in idea of a naming in graphql.
[00:05:56]
So in our case, we want every query to be named.
[00:05:58]
So you just type in a name for it and it'll use that name to gen to name the Elm file.
[00:06:04]
Okay.
[00:06:05]
Does that mean that you require a name as well?
[00:06:08]
If you have more than one query, you will need to have a name.
[00:06:11]
It will default to query if you don't have one, which obviously you could use for like
[00:06:16]
one, but probably, probably usually you grow out of the one query thing fairly quickly.
[00:06:21]
So it's really good.
[00:06:24]
The name is really good for analytics on the backend and pretty common to use.
[00:06:29]
Right.
[00:06:30]
Actually, why do you create multiple files if you can, if you have different names?
[00:06:35]
Well, yeah, that's one of the main challenges.
[00:06:37]
And I know Dillon, you're in this head space as well, is figuring out how to make ergonomic
[00:06:44]
namespaces.
[00:06:45]
So the naming rules in Elm GQL, which is basically like if there's a naming scheme for the generated
[00:06:51]
code for different pieces of it, and it will actually detect if there's going to be a collision
[00:06:56]
and it has a rule to make a more complicated name, but that won't collide.
[00:07:01]
And I can kind of get into those, what the, what that looks like.
[00:07:05]
But cause there was a lot of thought and how do you make that a nice process.
[00:07:09]
But the reason why not put it in one big file is you increase the likelihood of collisions
[00:07:14]
and also reading these files.
[00:07:17]
I wanted it to be very clear when you were reading a given file for a query, what data
[00:07:22]
is being used as like the arguments going into a query, what data is going to be returned
[00:07:28]
from the query.
[00:07:29]
And if you had more than one query in a file, cause sometimes these queries get pretty bonkers
[00:07:33]
huge.
[00:07:34]
So that there was a high likelihood that it would just be very hard to parse as a human.
[00:07:42]
And that was one of the goals.
[00:07:43]
I wanted people to be able to go to these files, like use them as a primary reference
[00:07:47]
of what's happening and have it be fairly trivial to navigate.
[00:07:50]
Yeah.
[00:07:51]
So just to, to make sure we've painted a picture for listeners here, because it's always a
[00:07:57]
challenge to talk about lots and lots of code in an audio format.
[00:08:03]
Yeah.
[00:08:04]
I want to know more about conflicts.
[00:08:08]
So you take your example query, let's say you're, you know, getting, listing out all
[00:08:15]
of the GitHub repositories for a particular user.
[00:08:18]
So for MD Griffith user, maybe you've got a, you know, so you say query all repos for
[00:08:26]
user.
[00:08:27]
So that's the name of the query.
[00:08:29]
And then you, you have parentheses in this GraphQL query syntax where you can declare
[00:08:34]
variables, GraphQL as a notion of variables.
[00:08:36]
So you say dollar sign username, colon string bang to say the type.
[00:08:43]
To say like, this is a required string.
[00:08:45]
So if you're not familiar with GraphQL, one of the things that's interesting as far as
[00:08:50]
squaring it with Elm is that it's sort of optional by default required.
[00:08:55]
You have to have additional annotation and obviously in Elm it's the opposite, right?
[00:09:02]
So.
[00:09:03]
Right, right.
[00:09:04]
Yeah.
[00:09:05]
In GraphQL, they like to end with a bang.
[00:09:06]
So when you say variable, you mean in an argument or perhaps.
[00:09:12]
That's right.
[00:09:13]
Yeah.
[00:09:14]
The GraphQL terminology is variable, but you're right that it more intuitively, we would think
[00:09:20]
of that as a parameter for almost like a function, like the query is like a function and the
[00:09:24]
variables like a parameter.
[00:09:25]
Yeah.
[00:09:26]
So that's a good analogy.
[00:09:27]
So then now you, you have a GraphQL query that you're writing and in scope, you have
[00:09:32]
this string, which is the username, and then you just write a regular GraphQL query for
[00:09:37]
the GitHub API, which is a really nice API.
[00:09:40]
You can open up the Explorer, we'll drop a link to the GraphQL API Explorer for the GitHub
[00:09:45]
API.
[00:09:46]
It's really fun to play with, but then you use, go and make your query for getting all
[00:09:51]
repositories for the given username.
[00:09:54]
And then you run a Elm GQL on that copy pasted query that you build up.
[00:09:59]
And let's say you select, you know, all of the repos and for each repo you get the repo
[00:10:05]
name and the number of stars.
[00:10:07]
Perfect.
[00:10:08]
So now you run Elm GQL.
[00:10:12]
Elm GQL knows that it knows the types of all these things you're selecting.
[00:10:16]
It knows the shape of everything basically.
[00:10:18]
Yeah.
[00:10:19]
Right.
[00:10:20]
So now you're going to get, you know, like a type.
[00:10:23]
So in your generated code, so if we, if we called our query, all repos for user, now
[00:10:30]
you're going to have a file, all repos for user.elm, and you're going to have a type
[00:10:34]
alias repo that's generated by Elm GQL, and it's going to have named colon string and
[00:10:42]
star gazers colon into something like that.
[00:10:45]
Right.
[00:10:46]
So it is, so if you contrast it to like a query builder approach, like, like my own
[00:10:51]
GraphQL package, you're not writing these type aliases and mapping it into types.
[00:10:56]
You're writing your query and it gives you all of the type aliases for that.
[00:11:00]
Right.
[00:11:01]
So, right.
[00:11:02]
So just to reframe, or not reframe, but just to reiterate, cause it's like the critical
[00:11:06]
thing is like, okay, Elm vendor Elm GQL is you take GraphQL and you make Elm.
[00:11:14]
And Dillon Kern's Elm GraphQL is you write Elm code.
[00:11:19]
You're sort of composing this in Elm and that will generate the GraphQL query.
[00:11:25]
So the main thing you're interacting with in Dillon's library is the Elm.
[00:11:29]
And the main thing you're interacting with, at least initially in my library is the GraphQL
[00:11:35]
itself.
[00:11:36]
Right.
[00:11:37]
And then once you have that, you now have some Elm code, which we had that example of
[00:11:43]
having a username variable in the GraphQL query.
[00:11:48]
Now you have that as a parameter in Elm code.
[00:11:51]
So you call that Elm code.
[00:11:54]
That's right.
[00:11:55]
So in my library, the names are so similar.
[00:11:59]
In vendors GraphQL library, the part you do interact with the generated code, the inputs,
[00:12:05]
you're still composing in Elm because you can, obviously you want to be able to change
[00:12:08]
those, like set the date, from what dates do you get the comments or something.
[00:12:16]
So yeah.
[00:12:17]
Yep.
[00:12:18]
I have to admit that the first time I heard about Elm GQL, I was like, that's a weird
[00:12:23]
name.
[00:12:24]
It's just not to conflict with Elm GraphQL from Dillon.
[00:12:28]
Then I learned that GQL files are a thing.
[00:12:32]
So then it kind of makes sense.
[00:12:34]
Naming is tough.
[00:12:35]
I'm trying to emphasize the author, which I think was the original intent with the literal
[00:12:40]
naming convention.
[00:12:42]
So the differentiator is Dillon versus, in this case, it's published under the vendor
[00:12:49]
namespace for my library.
[00:12:52]
Right.
[00:12:53]
Although ironically, it's npm install at Dillon current slash Elm GraphQL, and then it's npm
[00:12:59]
install Elm dash GQL.
[00:13:02]
I didn't name space.
[00:13:03]
That's a good piece anyway.
[00:13:05]
And forget about vendoring the vendor one.
[00:13:09]
That's just a whole can of worms.
[00:13:11]
Right.
[00:13:12]
He's shaking his head in shame.
[00:13:19]
I haven't done anything wrong.
[00:13:21]
Shame for the podcast.
[00:13:23]
That you know of.
[00:13:26]
Right.
[00:13:27]
Okay, cool.
[00:13:29]
So where do we go from here?
[00:13:31]
As they say in that Guns N Roses song, where do we go now?
[00:13:35]
Do the gloves come off now?
[00:13:37]
I would like to get into it.
[00:13:39]
Yeah, for sure.
[00:13:40]
Hopefully people have a basic idea of the fundamental approach and maybe we can go into
[00:13:47]
what this means.
[00:13:48]
Yeah.
[00:13:49]
Yeah.
[00:13:50]
So the way that I understand this is that if you are used to writing GraphQL queries,
[00:13:59]
which is likely the case if you have been using GraphQL and haven't used Dillon's version,
[00:14:04]
then Elm GQL might be more intuitive at least.
[00:14:09]
And I know that there is some confusion with Dillon's API because it's pretty complex.
[00:14:16]
It looks like JSON decoders, but even a bit more complicated because you both ask for
[00:14:21]
things and you map them.
[00:14:24]
The way I see it, the main difference is that in Dillon's version, it's more complex, but
[00:14:30]
you can do wrap early, unwrap late.
[00:14:34]
Basically your version, Matt, is generating primitives.
[00:14:39]
It's generating type adresses that don't necessarily have guarantees that you...
[00:14:45]
So it doesn't always generate primitives.
[00:14:50]
It generates what the GraphQL schema is dictating.
[00:14:54]
So we're saying that the domain modeling lives in the schema, but it will generate...
[00:14:59]
So in GraphQL, there's a notion of a union, which maps really nicely to Elm's custom types.
[00:15:06]
Oh, cool.
[00:15:07]
These are named.
[00:15:08]
Are these enums or are these...
[00:15:10]
So there's a concept of an enum, which maps really nicely to Elm's custom types just without
[00:15:16]
any data.
[00:15:17]
Both, I think...
[00:15:18]
So Dillon and my library, they both handle enums basically the same.
[00:15:23]
Maybe some trivial differences in naming conventions or whatever, but it's basically like, okay,
[00:15:28]
great.
[00:15:29]
It's a custom type.
[00:15:30]
You can refer to it.
[00:15:31]
Wonderful.
[00:15:32]
As far as a union, that gets more interesting because in Dillon's library, you have the ability
[00:15:38]
to sort of, when you're calling a union, mapping that into whatever you want it to be.
[00:15:44]
So you need to define a type to kind of capture the information and make that decision about
[00:15:51]
where you're putting it.
[00:15:53]
And in Elm GQL, you basically would...
[00:15:56]
You would select for a union, a union being like one of...
[00:16:01]
It's like this can be one of these five objects, right?
[00:16:04]
And they all have a concrete name.
[00:16:07]
And so what Elm GQL will do when you're selecting that, depending on the data you select for
[00:16:11]
each one, it would generate a custom type where you'd have a variant for each union
[00:16:16]
that can be selected.
[00:16:18]
And with the data that you've selected for a given variants on that variant, right?
[00:16:25]
Okay.
[00:16:26]
So you would have a variant or a union type for every query.
[00:16:31]
That's right.
[00:16:32]
Right.
[00:16:33]
And this probably gets into one of the interesting bits, which is questions or an exploration
[00:16:40]
around code reuse or query reuse and sort of type compatibility.
[00:16:47]
So you can imagine in Dillon's library...
[00:16:48]
So to frame...
[00:16:50]
So before I actually jump into this, there's a few things I want to sort of establish.
[00:16:54]
One at vendor and blissfully before that, we use Dillon's library extensively.
[00:16:58]
We did that for the last five years or so or four years.
[00:17:02]
I was only there for three and a half years.
[00:17:05]
But it was there before me.
[00:17:07]
And so we had a lot of code that was using Dillon's library.
[00:17:11]
We still have a lot of code using Dillon's library.
[00:17:13]
We were just moving over to this new approach.
[00:17:17]
And one thing that I want to also mention, because I think everyone on this podcast just
[00:17:22]
like we're so used to it that we don't say it.
[00:17:25]
Both these libraries have similar guarantees as far as you can't make a query...
[00:17:30]
You can't ask your API for data that doesn't exist.
[00:17:34]
So we're both checking against the schema.
[00:17:36]
Both of these are type safe and have this approach that Dillon talked about in his types
[00:17:42]
without borders talk about how can you get more type safety outside of just the internal
[00:17:48]
Elm language.
[00:17:49]
I just wanted that to be an explicit thing that was said.
[00:17:51]
So people...
[00:17:52]
Because sometimes it's like...
[00:17:53]
Yeah.
[00:17:54]
I didn't even think about mentioning it.
[00:17:57]
Yeah, I know.
[00:17:58]
It's because we're all Elm programmers.
[00:17:59]
So like, yeah, of course it's type safe.
[00:18:00]
Like that's not even a question.
[00:18:03]
Yeah.
[00:18:04]
And this is a huge benefit from both libraries that we get.
[00:18:07]
That is probably one of the first motivators.
[00:18:10]
And if either library didn't have this, it would be significantly less appealing.
[00:18:15]
But we enjoy this at work where we know the front end cannot ask for...
[00:18:19]
Cannot compose an incorrect query, at least as regards to the schema.
[00:18:25]
And cannot ask for data that's incorrect.
[00:18:27]
And even do things like protect against alias collisions or like field name collisions,
[00:18:33]
or things like you have to have a...
[00:18:35]
For variables, right?
[00:18:36]
You have to declare them correctly and they have to match what's in.
[00:18:40]
So you say like, I have three variables, their name X, Y, and Z.
[00:18:42]
And it's like, great.
[00:18:44]
None of them are in the query.
[00:18:45]
You're not using them.
[00:18:46]
That's technically, I think, invalid GraphQL.
[00:18:48]
So anyway, I wanted to level set a little bit there.
[00:18:51]
But then, yeah, code reuse, which I think is interesting.
[00:18:56]
So in Dillon's library, I realize I'm speaking a lot.
[00:18:58]
So please feel free to interrupt me.
[00:19:00]
In Dillon's library, you could map a thing into a common type.
[00:19:03]
In fact, that's sort of the thing you would naturally do, is you'd commonize selecting
[00:19:08]
for a given union.
[00:19:09]
And then in Elm GQL, you would have...
[00:19:13]
These types would be generated separate for each query.
[00:19:15]
But there is a mechanism that I just added to leverage GraphQL fragments.
[00:19:22]
Shared fragments.
[00:19:23]
Okay, cool.
[00:19:24]
So you wouldn't be able to change the type being returned.
[00:19:27]
But you could say, if you're using the same fragment, a fragment in this case is like
[00:19:31]
a subquery.
[00:19:32]
It's basically like a little named set of fields and data that you're selecting.
[00:19:35]
The intention with fragments would be that if you're using that fragment, that will generate
[00:19:40]
the same type in Elm, and those would be handleable.
[00:19:43]
Where do you define a fragment?
[00:19:44]
Is it something that you can define in another GQL file or...
[00:19:50]
Right now it's just in a given query file.
[00:19:53]
But I do want a notion of a global fragment that's basically like global across your project.
[00:19:58]
I haven't implemented that yet, but I think it's pretty reasonable.
[00:20:03]
Okay, there's nothing built in to GQL language.
[00:20:07]
Right now, no.
[00:20:08]
No.
[00:20:09]
I mean, there's a notion of a fragment.
[00:20:11]
I'm not sure what they would have to add on a language.
[00:20:13]
Yeah, there's that.
[00:20:14]
Right, they would have to have imports.
[00:20:16]
There's definitely no import resolution.
[00:20:18]
All GraphQL has a notion of is there's this big GQL formatted thing that you send over
[00:20:26]
to the server and then we run it.
[00:20:29]
And it can include fragments and whatever, but fragments, queries, that's all they have
[00:20:34]
the idea of.
[00:20:35]
So just to paint a picture of what this would look like for anyone who might not know union
[00:20:40]
types in GraphQL in general.
[00:20:43]
If you're listing all users in a system and you've got teachers and students, then now
[00:20:52]
you're going to have to say, well, if it's a teacher, give me this data.
[00:20:56]
If it's a student, give me this data.
[00:20:57]
So that's sort of a polymorphic selection set you could call it.
[00:21:02]
It's just deciding based on the type which fields to select and GraphQL has this awareness
[00:21:12]
of the types, if it's this type or if it's that other type.
[00:21:15]
And in the generated Elm code, you would have a corresponding union type in Elm GQL that's
[00:21:21]
automatically generated because it knows these are the two different types you're selecting.
[00:21:25]
So I'm going to create a custom type with those two different selections and the subset
[00:21:31]
of things you've selected for each given one.
[00:21:34]
So there will be a variant for each.
[00:21:36]
And Elm GraphQL, my Elm GraphQL library, it's, I mean, and this is sort of like a bit of
[00:21:42]
the philosophical interesting difference between the vendor approach, your approach and my
[00:21:49]
approach is the query builder approach that my Elm GraphQL library does.
[00:21:54]
Everything is very explicit and hand tailored, which means you have full control over the
[00:22:01]
types you build up.
[00:22:02]
That also means you have to explicitly write everything that you build up.
[00:22:08]
You have to explicitly control everything.
[00:22:11]
So there's more wiring to do to explicitly pull.
[00:22:14]
And as Jeroen was mentioning earlier, that can be a bit difficult for beginners sometimes
[00:22:20]
because you have to get comfortable with, oh, I have to map all of these types.
[00:22:25]
I create a type alias.
[00:22:26]
Wait a minute is like what happens when I do selection set dot map for some type alias
[00:22:33]
name?
[00:22:34]
What is that doing?
[00:22:35]
And it's like, oh, well it implicitly defines a function that takes four values because
[00:22:40]
it's a type alias for a record with four values and it's a little bit confusing.
[00:22:44]
So there are trade offs there, inherent trade offs.
[00:22:48]
Yeah.
[00:22:49]
The way I kind of think about it is that Dillon's library allows you to remodel the data coming
[00:22:57]
in, meaning like you've asked for this data and you can refine it in some sort of way.
[00:23:02]
So you can say, I want to select these fields and I want to actually create a new abstraction,
[00:23:07]
something different, a different type.
[00:23:09]
And this is how I primarily want to interact with this data.
[00:23:13]
In Elm GQL in my library, I think the thinking is that GraphQL itself has an expressive enough
[00:23:21]
type system that the design work of the modeling the domain, we want actually to be very close
[00:23:29]
to what like basically is in the schema.
[00:23:32]
Like usually we found that there are a few cases where it's like, okay, this wasn't quite
[00:23:37]
expressed correctly.
[00:23:38]
Either the schema wasn't designed correctly or there's just this weird invariant we can't
[00:23:42]
capture in the schema or whatever.
[00:23:44]
We're also in the headspace of we are in control of our own schema.
[00:23:48]
And I realized that that's, some people are using talking to other schemas.
[00:23:52]
And so like for us, it's like, oh yeah, we have opinions about how GraphQL schemas should
[00:23:57]
be built.
[00:23:59]
And it's a primary discussion we have a lot at Vendor.
[00:24:04]
And so for us that modeling idea, we want it to live in the schema as much as possible.
[00:24:11]
And so, right.
[00:24:13]
And not sure where we want to go from there.
[00:24:16]
So does that mean that you pretty much never map whatever you got to a non primitive type?
[00:24:24]
You never write it?
[00:24:25]
Again, we're not, I mean, if custom types are primitives, then I guess I can agree,
[00:24:29]
but like we're generating, it's not, everything's not a Boolean, right?
[00:24:32]
So it's like we still have the expressive type system and GraphQL that is actually surprisingly
[00:24:37]
close to Elm except for a few weird nuances.
[00:24:41]
There's I think a really interesting area that I did not quite, I was worried about
[00:24:48]
and led me to some interesting observations, which relates directly to what you're talking
[00:24:53]
about, which is with Elm GQL, I think the meaning you have a GraphQL query, you're generating
[00:25:01]
probably a decent size set of Elm code or data types to represent that.
[00:25:07]
The worry is that, oh, I can't map this and you might say like, well, where do I keep,
[00:25:13]
like the first question is like, where do I keep my UI state?
[00:25:16]
So like, let's say I needed to have a UI widget.
[00:25:19]
It was something that required its own like little state.
[00:25:22]
I think most widgets don't need this, but in some cases you do, right?
[00:25:27]
Where do I put that?
[00:25:29]
Usually when we are using the Dillon's approach or building things in Elm, the thing what
[00:25:35]
we would do is we would stuff that UI state right next to the thing it was operating on.
[00:25:40]
So maybe you're a few like levels deep and you have a list of stuff and you want to be
[00:25:47]
able to, like maybe it's a table.
[00:25:50]
So it's a list of rows.
[00:25:51]
You want to be able to click into a table and maybe edit some data and capture some
[00:25:56]
temporary state.
[00:25:57]
So at the level of the row, we would stuff in some stuff and then we write some code
[00:26:02]
to traverse, like to go into the code, do the updates in our update statement, right?
[00:26:08]
Or not statement, sheesh update function.
[00:26:10]
You'd write some code to go into your data, you know, perform the update and like do the
[00:26:15]
thing.
[00:26:16]
So it was like, okay, well what is the approach with Elm GQL?
[00:26:18]
If I can't literally extend the types that are within that thing, what do I do?
[00:26:23]
The approach that I found to be very valuable, which I think actually Richard has talked
[00:26:29]
about in some cases, there was a talk at ElmConf that the name of it escapes me.
[00:26:35]
But usually with GraphQL, you have, this is coming from a database, you usually have primary
[00:26:41]
identifiers.
[00:26:42]
Like you have IDs or you may have like in GitHub for a repo, they identify it by like
[00:26:46]
owner and username, right?
[00:26:49]
So you have some notion of a primary key.
[00:26:51]
If you think of your model, just like a little tiny little baby database, that UI information
[00:26:57]
can live really nicely in a top level dictionary.
[00:27:01]
And you basically can address things by ID.
[00:27:04]
And what's interesting is the code you need to write to update that, the update code becomes
[00:27:09]
much smaller.
[00:27:10]
Because like all of a sudden you're basically just like, oh, I just, I have the ID because
[00:27:13]
they clicked on this row, right?
[00:27:15]
And I can just like update that dictionary by ID and then, and be good.
[00:27:22]
And it's like, we might be worried about what if that entry doesn't exist, right?
[00:27:28]
For a given thing.
[00:27:29]
And I think that there are some interesting strategies to make sure that that's not an
[00:27:33]
issue.
[00:27:34]
Sometimes with UI state, it can be done sort of just in time.
[00:27:39]
So usually UI state may not need, usually there's a, for a UI state, there is like the
[00:27:44]
essential data, which is like, okay, the essential data in this case, maybe we have a person
[00:27:48]
picker, right?
[00:27:49]
It's a dropdown picks a person.
[00:27:50]
So the essential data is from the GraphQL query.
[00:27:53]
It's the literal person selected.
[00:27:54]
But the UI state, which is like, is the dropdown open or not?
[00:27:58]
That has a natural default, like where it's just like, well, it's going to be closed by
[00:28:02]
default.
[00:28:03]
Great.
[00:28:04]
And it means you don't actually have to instantiate a bunch of these empty things.
[00:28:07]
It's just like, oh, well, when they click on this, I'm going to go to that dictionary.
[00:28:11]
I'm going to say like, they clicked on this ID, open it.
[00:28:14]
And in dropdowns, it's actually really interesting because dropdown state, you have this potentially
[00:28:20]
subtle thing.
[00:28:21]
You only want one dropdown open, except in maybe interesting cases.
[00:28:25]
So like, you know, I mean, if it's like a nested dropdown is what I'm sort of referring
[00:28:29]
to, but usually it's like, there's one dropdown.
[00:28:31]
If there are multiple dropdowns open, that's a problem.
[00:28:34]
So now addressing things by ID, you naturally get that ability.
[00:28:38]
There's a very specific place where this can happen.
[00:28:40]
It's not a dictionary of open dropdowns.
[00:28:42]
In that case, it's, it's literally a maybe ID of a dropdown that's open.
[00:28:47]
That's a singular thing.
[00:28:49]
So there's kind of a natural way to that.
[00:28:51]
That's how at vendor things started to like, we started to organize things.
[00:28:56]
I actually really like it.
[00:28:59]
That's a fascinating insight from, from your experience with that.
[00:29:03]
It's, it's cool to hear about not only like, you know, this tool that you've created, but
[00:29:09]
your best practices that you've learned working with it.
[00:29:13]
That's really interesting.
[00:29:14]
I like this idea in general a lot.
[00:29:16]
And by the way, the the Richard Feldman talk you were referencing is called immutable relational
[00:29:21]
data.
[00:29:22]
I wonderful.
[00:29:23]
Yes, that's right.
[00:29:24]
We'll drop a link in the show notes.
[00:29:26]
And yeah, I really like this idea of like cross referencing bits of data to derive state
[00:29:33]
in Elm rather than being sort of feeling like you have to model your data a specific way,
[00:29:40]
being, being able to say, this is the natural shape of this data.
[00:29:43]
This is the natural shape of this other data, and I can derive state using both of those
[00:29:48]
things and I can create some state that references this other state and, and have sort of compound
[00:29:54]
state by, by cross referencing those two things.
[00:29:58]
Right.
[00:29:59]
So, so, right.
[00:30:00]
So like a, a very common pattern, ignoring maybe the interactive UI, but the very common
[00:30:06]
pattern we have is usually for a given page, there will be a primary list of something,
[00:30:11]
right?
[00:30:12]
So it's like the list of whatever.
[00:30:13]
So in, in GitHub, it's like a list of repos or maybe a list of issues, right?
[00:30:18]
Or a list of PRs.
[00:30:20]
And then usually there's also a concept of a detail.
[00:30:23]
So usually you don't want to select absolutely all the data in your first go around because
[00:30:27]
you're probably just displaying a table or a list of something.
[00:30:30]
And if you were to select all the details for all the items, it's sort of, I've sort
[00:30:35]
of thing it's the antithesis of what GraphQL is good for, which is selecting exactly what
[00:30:39]
you need so that you can optimize these different things.
[00:30:42]
So what we do in these cases is you usually have a primary list and that's the query you
[00:30:47]
run when the page boots, right?
[00:30:49]
And then when they click on something, we'll have a detail query that's like get the details
[00:30:54]
for this specific thing.
[00:30:55]
And then that comes back and usually is shoved into a dictionary, which is mapped like ID
[00:31:00]
to details.
[00:31:01]
Right.
[00:31:02]
Interesting.
[00:31:03]
Would that be at all related to, we had Martin Janacek on to, to talk about, oh yeah.
[00:31:10]
So Martin called it the Elm store pattern was the term that he used for this idea of
[00:31:14]
sort of he, he used remote data to model these states of if something is loading or, and
[00:31:22]
then he, you know, had this way you could sort of say, I'm requesting this data.
[00:31:26]
So would that be at all related to, would that be at all similar to that pattern?
[00:31:30]
I think you could definitely use remote data for people who aren't familiar.
[00:31:34]
Yeah.
[00:31:35]
Remote data is loading, you know, or have it, or it's been requested, you know, those
[00:31:39]
different states.
[00:31:40]
Yeah.
[00:31:41]
I think, I think it's very amenable to that.
[00:31:42]
You could have in your details dictionary, it could be a dictionary of an ID to a remote
[00:31:48]
data of your details.
[00:31:51]
Sometimes we kind of, this might be, this is probably like messy modeling, but for that
[00:31:55]
specific case, I know I've done the thing where it's like if it's not in there, I assume
[00:32:00]
it's loading.
[00:32:01]
That's probably not totally correct, but there, there is the case of like, well, the, the,
[00:32:05]
you know, the idea lookup failed, which you have to handle that case anyway.
[00:32:09]
So right now I think we're using sort of an implicit remote data, even though that's,
[00:32:14]
that may not be ideal, but I think it's amenable to however you want to model that part.
[00:32:18]
I think for sure.
[00:32:20]
Right.
[00:32:21]
So, so one other thing, looking at this comparison between how you, how you work with types between
[00:32:28]
Elm GQL and Elm GraphQL.
[00:32:31]
One thing we haven't touched on is custom scalers in GraphQL.
[00:32:35]
So custom scalers is this really cool tool where you can give names to types other than
[00:32:42]
string bool int in GraphQL.
[00:32:44]
So you can say, you know, you could say this is a username.
[00:32:48]
You can say this is, this is a time, you know, this is a date stamp.
[00:32:52]
Yeah.
[00:32:53]
This is a timestamp.
[00:32:54]
This is a.
[00:32:55]
Right.
[00:32:56]
Is that equivalent to a type address in Elm or can you do a.
[00:32:59]
It's not really, you can do more powerful things.
[00:33:01]
So I think actually Dillon and I, our libraries are actually very similar in this, how we
[00:33:05]
handle scalers.
[00:33:06]
So what happens is there are a set of primitives, right?
[00:33:10]
So float int boolean string that are just there and those decode to primitives, but
[00:33:17]
the schema can declare custom scalers like, like Dillon mentioned.
[00:33:21]
And what the client side libraries like Dillon's library and my library, I guess mine's a tool,
[00:33:27]
whatever is you declare like, so when you start up a Elm GQL project, it generates
[00:33:35]
a file for you where you can't, which you have to own.
[00:33:37]
So it generates it first, like once, and then you have to kind of like adjust it and own
[00:33:42]
it.
[00:33:43]
But what you can do is you can say like, okay, if you get a timestamp scalar, and we know
[00:33:46]
all these scalers statically from the schema, get a timestamp.
[00:33:50]
I know that this is like an ISO.
[00:33:53]
What is it?
[00:33:54]
4808601.
[00:33:55]
8601.
[00:33:56]
I just made the numbers.
[00:33:57]
I got the 01.
[00:33:58]
It's been a long time since we've mentioned those.
[00:34:01]
Yeah, it's 48.
[00:34:02]
I wonder what that is.
[00:34:04]
So you know, you can say, okay, I want to parse that comes down as a string.
[00:34:09]
Custom scalers, I believe always are backed by strings.
[00:34:12]
I'm not sure if that's true.
[00:34:13]
I think you can technically send arbitrary JSON with them, which gets a little wonky.
[00:34:20]
That does get a little wonky.
[00:34:22]
So well, let's for the sake of argument, assume that this comes down as a string and what
[00:34:27]
you can do, and both of our libraries do this, you would define in Elm a decoder and an encoder
[00:34:34]
to basically say like, this is how I could turn it into something that we want to use
[00:34:37]
like in Elm, it'd be a time posix or maybe a different like data type if you wanted.
[00:34:44]
So you just have to add the decoder and encoder part.
[00:34:48]
And then anything of that type.
[00:34:50]
Right.
[00:34:51]
Or even just wrapping it.
[00:34:52]
There's another primitive called ID, which is generally a string, but we keep it's an
[00:34:55]
ID type, right?
[00:34:58]
Which we keep as a separate thing from like string.
[00:35:01]
Right.
[00:35:02]
Yeah.
[00:35:03]
That's the kind of thing that I was thinking of.
[00:35:05]
Those things you would like to put them into a separate type just to not confuse.
[00:35:10]
Exactly.
[00:35:11]
So you could, as long as it's differentiated in the schema, in the GraphQL schema is like,
[00:35:15]
these are separate scalers, then on the Elm side, on both of these libraries, you could
[00:35:19]
do whatever you wanted.
[00:35:20]
Right.
[00:35:21]
So it really helps to have full control over the schema then.
[00:35:26]
I mean, yeah.
[00:35:31]
What does happen sometimes is when you have GraphQL schemas that are designed for non
[00:35:38]
typed consumers, you get number one, a lot of maybes, a lot of nullable types.
[00:35:47]
You get nullable lists of nullable strings.
[00:35:51]
That's very common.
[00:35:52]
Yeah.
[00:35:53]
They show up.
[00:35:54]
Yeah.
[00:35:55]
Nullable lists of nullable strings.
[00:35:56]
We probably in our schema, we definitely push the backend developers through like, can we
[00:35:59]
just make this require, can you just remove the null here?
[00:36:03]
Because it's technically expressible, but it's never meaningful.
[00:36:08]
Exactly.
[00:36:09]
Yeah.
[00:36:10]
So that happens a lot.
[00:36:11]
And then custom scalers are heavily underused because you don't really necessarily gain
[00:36:17]
a lot from them if you don't have a type aware consumer.
[00:36:21]
Yeah.
[00:36:22]
That's right.
[00:36:23]
But if you control your schema, then it is so valuable to use those custom scalers in
[00:36:33]
your schema, in your GraphQL schema.
[00:36:36]
Basically the way I think about, and I think we talked about this on our Elm GraphQL episode
[00:36:40]
a while back, but the way I think about custom scalers in GraphQL is it's a contract.
[00:36:48]
Yeah.
[00:36:49]
Absolutely.
[00:36:50]
It's a promise that this conforms to this specification, ISO 8601.
[00:36:54]
And it's like, how do you trust the contract?
[00:36:59]
Well, because usually like a GraphQL framework, like a backend framework for GraphQL, if it
[00:37:06]
knows that a value is type date time, then it's going to use the same serialization and
[00:37:13]
deserialization function to manage incoming inputs of that type and to serialize outgoing
[00:37:21]
data of that type.
[00:37:23]
And so you can sort of trust that it's going through this pinch point where it's treating
[00:37:27]
it through the same logic.
[00:37:30]
So it doesn't mean you can't have bugs where you incorrectly serialize or deserialize it,
[00:37:35]
but it's going through one pinch point.
[00:37:37]
So it's a really valuable tool.
[00:37:38]
Yeah.
[00:37:39]
It's interesting.
[00:37:40]
I've definitely had thoughts about how to take it, especially when you control the schema,
[00:37:43]
to take it maybe farther than I think the average schema.
[00:37:47]
Like an example is usually IDs, like we sort of say like, oh, all IDs are the same.
[00:37:52]
It's like, well, they're not.
[00:37:53]
You can use an ID for one thing, for another thing, and then it doesn't make any sense.
[00:37:57]
So one thing I've thought about is like, okay, well, is this a user ID or is this a, you
[00:38:03]
know, you have the idea of a flavored ID, right?
[00:38:06]
So basically you flavor it by the entity or the encoding of it.
[00:38:09]
And I think that doesn't show up as much specifically because people aren't using things like Elm
[00:38:15]
as a consumer.
[00:38:17]
But in Elm, it's actually great because it means like you could have the guarantee like,
[00:38:21]
oh, this mutation takes a user ID and like you can get that user ID from, you know, this
[00:38:28]
call.
[00:38:29]
It's like, great.
[00:38:30]
There's some immediate additional type safety.
[00:38:32]
So I realized we're going, but I wanted to, I don't think we talked about this, but one
[00:38:37]
of the primary motivators for Elm GQL and why we leaned into the GraphQL approach was
[00:38:42]
we have, you know, we have a really awesome set of Elm developers at vendor.
[00:38:47]
It's super exciting.
[00:38:48]
We're also hiring, just so you know, but we also have a lot of developers on the backend
[00:38:53]
with a lot of different experience.
[00:38:55]
Some of them jump into the Elm code pretty easily.
[00:38:58]
Some of them are farther back, I suppose.
[00:39:01]
I don't know, but what we found was very valuable is just if someone comes to you and asks you
[00:39:07]
the question, what data does this page request?
[00:39:10]
The story around that is so great.
[00:39:13]
So if someone, if a database engineer who's trying to debug a performance issue says what,
[00:39:18]
and they're not really touching Elm at all and they're like, okay, this page is, I know
[00:39:22]
it's a problem.
[00:39:23]
You know, where can I get a query so I can test this stuff?
[00:39:28]
And you have the query as a static file, it's great.
[00:39:31]
And then they learn, they can just go and get it.
[00:39:33]
They don't need to, well, I want more people to learn Elm.
[00:39:36]
It's fine if they don't have to.
[00:39:39]
So that was a big motivator, just like clarity.
[00:39:42]
We did have, in some cases with the same visibility approach, one of the primary things to think
[00:39:47]
about with GraphQL is over querying for data.
[00:39:51]
So like, I think there's a question of, we kind of mentioned this, but there's deduplication
[00:39:56]
in your queries, which in Elm GQL is held by fragments, but there's also like reuse
[00:40:02]
of others in another sense.
[00:40:05]
And what we found is that you actually, so also with fragments, we have gone about a
[00:40:10]
year with an older version of Elm GQL, my library, and we've not really had a massive
[00:40:16]
need for fragments.
[00:40:17]
We do now, there are a few cases where this shows up, but I think the gut intuition that
[00:40:22]
we have is that if queries are easy to write and they're quick and you have really wonderful
[00:40:27]
editor support, you should think about not worrying about sharing stuff.
[00:40:32]
You should just write a new query because that'll allow two separate instances to diverge
[00:40:36]
when they need to.
[00:40:37]
And the opposite of that, when you've overshared between stuff, can be very painful because
[00:40:43]
you'll be like, this page is very slow.
[00:40:45]
I don't know why.
[00:40:46]
It's like, oh, we were selecting this other data that this page technically doesn't really
[00:40:50]
even care about.
[00:40:53]
It's the classic don't repeat yourself dilemma between repeating code and repeating knowledge.
[00:40:59]
And if you deduplicate code that doesn't represent the same knowledge, then those two things
[00:41:06]
don't want to change together.
[00:41:09]
And we found that the speed of being able to write these queries changes the math you
[00:41:13]
need to do.
[00:41:15]
Because it's like, if you can write a query easily and you can adjust it easily and you
[00:41:18]
know you're never unsafe, then it doesn't feel like, oh, great, I'm just going to write
[00:41:23]
a new one.
[00:41:24]
It's not that big of a deal.
[00:41:27]
Yeah.
[00:41:28]
So you shared a few motivations.
[00:41:33]
Now I'm wondering, you were using Dillon's version before.
[00:41:36]
That's right.
[00:41:37]
We still are.
[00:41:38]
Yeah, you still are.
[00:41:39]
What pain points did you have that led you to wanting to write a new version?
[00:41:44]
Yeah, the main pain points we had was questions over sharing of queries.
[00:41:53]
And we went through a few iterations of performance trying to get some of these pages down to
[00:41:59]
load reasonably.
[00:42:01]
And one of the biggest challenges we found was that, oh, there was a shared what's called
[00:42:06]
the selection set in Dillon's library, which is basically just a selection of fields.
[00:42:09]
There was a shared selection set that one page was using and probably driving, needed
[00:42:16]
a lot more data.
[00:42:17]
But then you have the detail page is selecting a bunch of data.
[00:42:21]
And then maybe the page that lists a bunch of things is also using that.
[00:42:25]
And so then you're accidentally over querying a bunch of stuff.
[00:42:30]
So untangling those, that was challenging.
[00:42:34]
So you can do separate queries, but you felt pushed towards reusing the same queries.
[00:42:42]
There's a really interesting discussion around incentives and how those sort of can change
[00:42:50]
depending on what is easy.
[00:42:53]
And so, yeah, that's right.
[00:42:55]
And the other big motivator with the GraphQL thing was the writing experience when you
[00:43:01]
have a plugin is really nice.
[00:43:03]
Yeah, there's a lot of good tooling.
[00:43:06]
Autocomplete is like a superpower.
[00:43:09]
And so that was really wonderful.
[00:43:10]
And the last one is we're growing at a sort of a ridiculous pace and wanting to remove
[00:43:17]
barriers to knowledge.
[00:43:19]
And we know that GraphQL is sort of our primary domain modeling is the GraphQL layer because
[00:43:24]
that's how we coordinate all this stuff.
[00:43:27]
And so making that more accessible on both sides as much as we could was beneficial.
[00:43:32]
So those cases where if someone needs to drop into a page and understand, oh, we know that
[00:43:37]
this page takes five seconds to load.
[00:43:39]
What the heck?
[00:43:41]
Do they have at their fingertips enough information to debug that in a nice way?
[00:43:46]
Any comments, Steven, as to these pain points?
[00:43:51]
You're totally wrong, Matt.
[00:43:53]
You're totally wrong.
[00:43:55]
Yeah.
[00:43:56]
So it's really interesting to hear that story.
[00:44:01]
And one thing you didn't bring up also, but we've talked about this before, is input objects.
[00:44:08]
Oh, right.
[00:44:09]
Yeah, yeah.
[00:44:10]
I know, like, I mean, from...
[00:44:11]
Can you share some light on what an input object is?
[00:44:15]
Yeah.
[00:44:16]
So I know from my own experience using, as an Elm GraphQL user, it can be really painful
[00:44:23]
to just...
[00:44:26]
So input objects can get into these deeply nested data types, these deeply nested key
[00:44:32]
value pairs.
[00:44:34]
So basically, for example, if you're sending up...
[00:44:41]
You've got a user profile page, you're on the page, you select all the stuff for the
[00:44:47]
user profile, the email address, date of birth, and now you want to update that.
[00:44:52]
What do you do?
[00:44:53]
You're not selecting data, you're sending data back.
[00:44:57]
And so GraphQL has this idea of input objects.
[00:45:00]
So you're probably going to do not a query, but a mutation GraphQL request.
[00:45:06]
It's just a semantic difference.
[00:45:07]
Otherwise, the syntax is the same.
[00:45:10]
But you're going to be sending data up, which means you're building an input object.
[00:45:14]
You can also have an input object for specifying filters to filter the data on.
[00:45:20]
It's just your input data to your GraphQL query.
[00:45:25]
Which contains a lot of optional things, right?
[00:45:27]
You're right.
[00:45:28]
The main irritation that Dillon and I have bonded over is in GraphQL, the default, actually,
[00:45:39]
you have to mark something as required.
[00:45:40]
So the default is that something's optional.
[00:45:42]
But the supremely irritating thing about it is that optional is actually kind of squishy
[00:45:49]
and weird.
[00:45:50]
So what optional means is actually there are three states it can be in, not two.
[00:45:54]
So it's like null times again.
[00:45:57]
So what it can be is, let's say you have, if you think about it as just like a JavaScript
[00:46:02]
record, you can have the value either it is present, or it can be where the field is there,
[00:46:09]
but it's null, or the field is not there.
[00:46:13]
Now the irritating part about this is that null is generally rarely used.
[00:46:19]
It is used to say like delete this thing sometimes.
[00:46:22]
Sometimes people, so it's like one of those things where it's like irritatingly in some
[00:46:27]
small cases, it's semantically valid.
[00:46:31]
But usually people mean absent, meaning don't send up this optional thing.
[00:46:36]
Because in Elm we have to be explicit, we have to sort of represent all three of these.
[00:46:40]
And I think the confounding factor that Dillon and I have both had to design around is that
[00:46:45]
if something's optional, you have an optional argument to your query, we want to make sure
[00:46:49]
that the generated Elm code, if someone changes the schema and adds another optional query,
[00:46:57]
we don't want your Elm code to break, it should still compile.
[00:47:00]
So the default of like, I'm going to make a full record that represents all the arguments
[00:47:05]
and everything's going to be, you know, maybe we represent it not with a like, this like
[00:47:10]
super maybe, which is like, which Dillon and I have both messed with, which is present
[00:47:15]
with the data absent or null.
[00:47:18]
But if you drop that in a full record in Elm, it means your code's not going to compile
[00:47:23]
if someone adds an optional argument, which people get, they're like, why?
[00:47:28]
Yeah, and the Elm syntax doesn't have a way to do records with optional fields, except
[00:47:36]
explicitly having a data type that represents that optionality.
[00:47:40]
So you can't just leave off a field in your record.
[00:47:45]
And then Elm says, Oh, well, I'll use this default absent value for the things you leave
[00:47:50]
off, which is very cumbersome for users, if there are 100 different options, which is
[00:47:57]
not unheard of in a GraphQL schema, that are possible inputs for an input object you could
[00:48:03]
build.
[00:48:04]
These are the possible fields you could provide.
[00:48:06]
These are the possible filters you could filter on for this table of data.
[00:48:09]
And now, so there are two different things here.
[00:48:14]
One is the approach to the generated code for building up input objects in Elm GQL,
[00:48:21]
which I want to talk about.
[00:48:22]
You've taken an interesting approach there.
[00:48:25]
Probably one that might be well suited, like maybe Elm GraphQL, it would be a good fit
[00:48:30]
for, and I could try that out.
[00:48:32]
It's not incompatible with the approach.
[00:48:33]
But the second thing is this query generator approach that Elm GQL uses, you can actually
[00:48:40]
bypass that where actually you don't need to pass in any of that data.
[00:48:45]
So in our example of the GraphQL repository that you're selecting all repositories for
[00:48:53]
the user, you're just passing in a string of the username.
[00:48:56]
So for the consumer in the Elm code, you need to pass in a string, not an input object.
[00:49:04]
Building up that input object is handled in the GraphQL query itself.
[00:49:11]
And therefore, you don't, so you can skip all these levels.
[00:49:15]
Whereas in Elm GraphQL, my Elm GraphQL library, what you need to do is you need to explicitly
[00:49:20]
build that up to express a valid query.
[00:49:22]
So that means since Elm doesn't have a way to do records with like an implicit default
[00:49:30]
for fields you don't mention, what Elm GraphQL does is the generated code lets you build
[00:49:37]
these things up with functions where you build up an input object.
[00:49:42]
It passes you a record with all the defaults set as absent.
[00:49:46]
And then you can do the record field update syntax where you explicitly set the fields
[00:49:52]
you don't want to be absent.
[00:49:55]
And it works, it's type safe, it's perfectly type safe, but you get all of these nested
[00:50:01]
things where you're passing these functions that give you the default records and it's
[00:50:06]
very much not ideal.
[00:50:07]
So that's definitely a real pain point.
[00:50:10]
And I believe that was one of the motivating cases for you as well.
[00:50:15]
It was one of the things that we were thinking about for sure is you mentioned filtering.
[00:50:21]
And filters are usually across the board they are big complicated inputs.
[00:50:28]
It's like you have like, I want to filter by this and this and this and this and we're
[00:50:32]
going to add them together and then we're going to add that with an or thing and then
[00:50:35]
we're going to set this value.
[00:50:37]
And we had some pretty complicated filtering which emphasized that pain.
[00:50:41]
And in a vendor Elm GQL, the things that we found that were surprising after we started
[00:50:48]
messing with it, I mean, one of them that is exactly what you mentioned, right?
[00:50:53]
So it's like you can just actually build most of the input object in your query, like where
[00:50:58]
you just have the records there and it's really convenient.
[00:51:01]
Another few things you can do is that, you know, something can be optional in the schema,
[00:51:07]
but could can be required for your query.
[00:51:10]
So an example being like, maybe the query you're like setting requires both if we're
[00:51:16]
talking to GitHub, requires both the owner and the username, right?
[00:51:23]
Or the name of the repo, right?
[00:51:26]
And I think those might be required, but in the schema, let's say they were nullable,
[00:51:31]
they were optional.
[00:51:33]
You could actually in Elm GQL, you could actually flag them because you have a little declaration
[00:51:37]
at the top, here are my variables and what the types are.
[00:51:40]
And you could actually say like, actually, for this query, these things are required.
[00:51:43]
And that simplifies the code generation a lot because you basically, this concern doesn't
[00:51:49]
show up.
[00:51:50]
So you can just skip it sort of entirely.
[00:51:52]
Yeah, absolutely.
[00:51:53]
Yeah.
[00:51:54]
So, so I think it's really, really cool.
[00:51:57]
Like I love the motivation of like having shareable GraphQL syntax between different
[00:52:05]
teams that can speak the same language.
[00:52:09]
And I think, again, like just sometimes you fire off a mutation request and most of what
[00:52:16]
you care about is building up this big input object and you don't care that much about
[00:52:21]
the data or sometimes the data is really, your schema defines it pretty nicely and you
[00:52:29]
don't need that much fine grain control.
[00:52:31]
So I think it's great having both of these approaches.
[00:52:36]
I could certainly imagine myself, like, I mean, I certainly personally, I do really
[00:52:42]
like having fine grained control over my types.
[00:52:46]
The types.
[00:52:47]
Yeah, sure.
[00:52:48]
Not only through the mechanisms of how I define my GraphQL variables in the query and the
[00:52:54]
fight starts now.
[00:52:59]
Like scalers are a great tool for that.
[00:53:02]
And yeah, the variables.
[00:53:04]
But I personally do really like having like super fine grained control over that.
[00:53:10]
I wrote a blog post a while ago called types without borders isn't enough.
[00:53:15]
That's about my original design of actually maybe a little deja vu here on TypeScript
[00:53:23]
Interop.
[00:53:24]
Oh yeah, there we go.
[00:53:25]
On TS Interop.
[00:53:26]
Oh, oh, okay.
[00:53:27]
Okay.
[00:53:28]
Yeah.
[00:53:29]
Yeah.
[00:53:30]
So I disambiguated my own tool.
[00:53:38]
We talked about that in our Elm TS Interop episode.
[00:53:41]
But in a nutshell, the approach that Elm TypeScript Interop took was you have all of these ports
[00:53:48]
in your Elm code and it sort of statically analyzes all of that code and it knows all
[00:53:53]
of the ports you define and all of the types of those ports.
[00:53:57]
And then it generates TypeScript bindings for that.
[00:54:01]
So it knows the type information for your Elm application, which is kind of cool.
[00:54:07]
But then what happens when you want to serialize a custom type?
[00:54:12]
So in that particular case, there's no way to serialize anything that turns into a custom
[00:54:18]
type, which is unfortunate.
[00:54:20]
So that's a hard one.
[00:54:21]
No way like automatically.
[00:54:22]
Is that what you mean?
[00:54:25]
Right.
[00:54:26]
So you could serialize a JSON encode value over to the report, but now it's untyped as
[00:54:33]
far as TypeScript is concerned.
[00:54:35]
So I wrote about that journey in this blog post of how I went with a more explicit approach
[00:54:42]
where you build up the mappings of the types.
[00:54:46]
It allows you to decouple how you might want to represent something in TypeScript from
[00:54:51]
how you might want to represent something in Elm, all these classic things that we're
[00:54:53]
familiar with with this idea of JSON decoders.
[00:54:56]
So I certainly think both of these approaches have their benefits and their uses.
[00:55:05]
But I think it's really cool to have both of them out there.
[00:55:08]
And yeah, really cool to hear about your journey there.
[00:55:12]
So actually, Matt, you still have both in your project, right?
[00:55:16]
At Thunder.
[00:55:17]
That's right.
[00:55:18]
We're using Dillon's library and we're also using Elm GQL.
[00:55:20]
I think we're probably like 50 50 right now.
[00:55:22]
But you're basically intending to use Elm GQL?
[00:55:25]
We're intending to use Elm GQL.
[00:55:27]
That's right.
[00:55:28]
Okay.
[00:55:29]
Yeah, that was my question.
[00:55:30]
Yeah.
[00:55:31]
Oh, man.
[00:55:32]
I know we've gone long.
[00:55:33]
There's a whole other interesting discussion around generating using a schema to generate
[00:55:39]
mocked values.
[00:55:40]
This is something that I don't neither library like I wanted this in here or as a concept
[00:55:45]
because it's something that neither library does right now.
[00:55:48]
But it would be really fascinating for testing.
[00:55:53]
I could use an example.
[00:55:54]
Yeah, totally.
[00:55:55]
Exactly.
[00:55:56]
So we had there's a little bit of a story here in that vendor or previously blissfully,
[00:56:02]
we wanted to use the project Elm program test, which is a way to like basically run, you
[00:56:07]
know, tests that say like, you know, click this button.
[00:56:11]
And if you click this button, then this request would be made.
[00:56:14]
Now, which is cool and valuable, the biggest challenge to using that is data.
[00:56:21]
For example, for loading a given page, I need to have a certain set of data to actually
[00:56:26]
just show the page, right?
[00:56:29]
So we had a version this existed or exists actually in the vendor code base, where it
[00:56:34]
would look at the query that's being issued by that page to boot it up.
[00:56:38]
And it would like, look at the schema and say like, okay, I can make you something that
[00:56:43]
like looks like that.
[00:56:45]
Even if it's not semantically meaningful at all.
[00:56:48]
But it's like, here's Oh, a string, great, I'm gonna have a string called placeholder.
[00:56:52]
And then you'd be able to render the right HTML, this is all done in memory, right?
[00:56:56]
So this is kind of like, you think about browser automation, but there's no browser being booted
[00:57:01]
here.
[00:57:02]
This is a pure piece of JavaScript that's being run again, via Elm program tests.
[00:57:07]
And so if you can view that page, you can do stuff, you can click buttons, and you can
[00:57:11]
actually in Elm program test, you can say, well, you know, if this button is clicked,
[00:57:15]
I want to ensure that this query is fired off.
[00:57:20]
And one of the and what was interesting, though, is we ran into some challenges with just giving
[00:57:25]
hard coded scalars back, where it's like, oh, if it's asking for a string, we're gonna
[00:57:30]
give this string, like one string for all strings, right to rule them all.
[00:57:34]
So an approach that I'm really interested in exploring, and that Dillon actually mentioned,
[00:57:38]
suggested, I'm like, oh, that sounds great, is using the schema, or even a query and generating
[00:57:44]
a set of fuzzers that you could have the query you're asking for.
[00:57:49]
And then you could craft exactly what, or not exactly, but with the level of definition
[00:57:53]
you want for what data is returned for a given request.
[00:57:56]
So what that means of what you could do is, let's say you have a thing where you're keying
[00:58:02]
something by ID, and you want to make sure like, you know, if I get this data, then the
[00:58:08]
thing the data that we got is being rendered in the UI, you could actually do that test
[00:58:13]
because you know, like, okay, I know that the ID is specifically this, you know, and
[00:58:18]
whatever it is for that page.
[00:58:20]
And I know that it's being attached as a class or CSS class or something, you can actually
[00:58:24]
ask Elm program test, hey, is that is that visible?
[00:58:27]
Anyway, that's, that's the sketched out idea.
[00:58:31]
Basically generate fuzzers, generate auto mockers or whatever that you could adjust
[00:58:35]
if you want to.
[00:58:36]
Like, if you, you could have the auto generate one and if you want something that's more
[00:58:39]
specific, copy it out, adjust it as you need.
[00:58:42]
I'm really excited about that idea.
[00:58:44]
I think it's yeah.
[00:58:45]
Yeah, the code generation opens up so many, so many cool possibilities.
[00:58:49]
Yeah.
[00:58:50]
So one thing I wanted to point out too, as a difference, so there is there is a limitation
[00:58:55]
of my Elm GraphQL library, which is currently there's no way to use GraphQL variables at
[00:59:02]
all.
[00:59:03]
And that is, you know, sometimes people will use GraphQL variables to try to mask certain
[00:59:09]
sensitive values in their backend logging or...
[00:59:13]
Oh, interesting.
[00:59:14]
Okay.
[00:59:15]
I didn't know that, but that makes sense.
[00:59:16]
Yeah.
[00:59:17]
Caching reasons.
[00:59:18]
Are those the same as the function parameters again or?
[00:59:23]
Yes.
[00:59:24]
They can be, but essentially, yeah.
[00:59:29]
But it's a piece of GraphQL syntax that allows you to have a named value, which you can reuse
[00:59:39]
throughout a query, right?
[00:59:40]
So in Elm GraphQL, there's no such thing.
[00:59:46]
You have values, you know, you have input objects, you have selection sets, you have
[00:59:52]
variables, but there's no place...
[00:59:56]
The generated GraphQL query that's produced by Elm GraphQL will never include a GraphQL
[01:00:03]
variable in it.
[01:00:04]
Because it just drops the values directly in line.
[01:00:06]
Exactly.
[01:00:07]
So I'm guessing that's not a problem, but it makes the query bigger.
[01:00:12]
Is that it?
[01:00:13]
Well, if you have a particular use case where your backend uses, like, for example, it says,
[01:00:21]
hey, if you say, get all this data by user ID, and we take in that query, and we cache
[01:00:30]
it based on this key of the ID that's passed in as a variable.
[01:00:36]
So certain use cases like that, so that's definitely a limitation, which vendor inc.
[01:00:43]
Elm GQL does not have that limitation.
[01:00:45]
So that's definitely one thing to be aware of if you have that use case.
[01:00:48]
Right.
[01:00:49]
So when you're sorting out variables, there can be some performance things that you can
[01:00:53]
do.
[01:00:54]
Like, it's not just caching based on...
[01:00:56]
Or it can be caching based on the inputs.
[01:00:59]
But also, if you have a query that is totally...
[01:01:03]
Is not varying all the time, you can actually cache parsing that query where the backend
[01:01:08]
can just actually hash that query, and then it doesn't have to parse it and validate it
[01:01:13]
and everything.
[01:01:14]
Yeah.
[01:01:15]
And so that can skip some overhead.
[01:01:17]
We thought about that, but it's not highest on our list of things we need to resolve performance
[01:01:23]
wise.
[01:01:24]
But yeah, there is that option.
[01:01:27]
What is that technique called again, where you can send a hashed version of a query?
[01:01:36]
Yeah.
[01:01:37]
You can take it one farther where instead of sending the query, you basically the front
[01:01:41]
end and the backend know the hash, and they just send up the hash.
[01:01:47]
Along with some variables, essentially?
[01:01:49]
And variables.
[01:01:50]
Yeah, variables are in all of these cases in a different field.
[01:01:54]
Interesting.
[01:01:55]
It's really interesting.
[01:01:56]
It also makes me nervous, but I get it.
[01:01:59]
It's cool.
[01:02:00]
One of the interesting things there is you can have an allow list for things that...
[01:02:05]
Oh, really?
[01:02:06]
For like hashing behavior or something?
[01:02:08]
Well, you say like, these are the blessed queries and anything else is...
[01:02:14]
We just won't run.
[01:02:15]
We'll just throw an error, right?
[01:02:16]
So if somebody's poking around trying to do a DDoS attack by finding deeply nested GraphQL
[01:02:24]
queries or things, you don't have to worry about that.
[01:02:28]
It's also interesting too, because you could potentially have a backend where you say,
[01:02:32]
well, I'm going to conform to the shape that I promised to send by this query, but I don't
[01:02:38]
need to use any of the GraphQL formalities for safely doing the data loader pattern to
[01:02:45]
make sure I don't have N plus one database queries and stuff.
[01:02:48]
I can just pretend like it's a rest response, but promise to conform to that shape.
[01:02:53]
So it's an interesting space that sort of relates to the Elm GQL query generator approach.
[01:03:01]
So interesting space to explore.
[01:03:04]
And another thing about Elm GraphQL, so there are certain high level things about the field
[01:03:10]
aliases are built up for you automatically, for better and for worse.
[01:03:14]
Like you said in Elm GQL, you get a build time guarantee.
[01:03:18]
So it makes sure you've done that correctly.
[01:03:20]
And it is the aliasing thing is interesting.
[01:03:22]
Just as a small note, you do have a little bit of ability in Elm GQL to influence what
[01:03:27]
code is generated, what names are used.
[01:03:30]
Elm GQL specifically emphasizes aliases that you've provided as names that are, it would
[01:03:37]
prefer to use versus like calculating something from the schema directly.
[01:03:41]
So if you add an alias, that's a nice way to have some, like know that like that type
[01:03:50]
for that selected field is going to be named that or that field name in the generated code.
[01:03:55]
So yeah, which is a thing that like as a concept, cause there's no code generation in Elm GraphQL
[01:04:01]
as far as queries or stuff.
[01:04:03]
Yeah, it's just a totally separate thinking.
[01:04:06]
Right.
[01:04:08]
So one thing I was curious about was, so you mentioned before the recording that like originally
[01:04:17]
you started out this exploration, not with a query generator style as it is now, but
[01:04:23]
with a query builder style akin to Elm GraphQL.
[01:04:25]
So what was that story?
[01:04:26]
What did that look like?
[01:04:27]
Yeah.
[01:04:28]
So originally our big, the big pain point started everything I think was building up
[01:04:33]
these big input objects, these big filters.
[01:04:36]
We had this very big input objects and it became very challenging to extend beyond a
[01:04:43]
certain point.
[01:04:45]
Was it that bad?
[01:04:46]
The challenge?
[01:04:47]
Yeah, it was rough.
[01:04:49]
Like again, when you're dealing with the, in Elm, you know, you have to deal with the
[01:04:54]
entire option space explicitly.
[01:04:56]
So when you have a lot, especially there's this really interesting interaction with optional
[01:05:00]
stuff.
[01:05:01]
If the schema goes, and to be fair, that schema, we, I think know better now as far as how
[01:05:08]
we create our GraphQL schemas.
[01:05:11]
And probably if we redid that feature, we wouldn't go quite as nuts as we did, but we
[01:05:16]
still had to deal with it and sort of compose it.
[01:05:19]
And so there was a lot of exploration around simplifying input objects initially.
[01:05:22]
And I think initially also we were kind of wary of the, it had come up, but we're like,
[01:05:26]
I'm not sure, like, I don't know about the GraphQL to Elm path.
[01:05:31]
And then I know at a certain point we were just like, no, this seems at the very least
[01:05:36]
useful in a lot of simpler cases.
[01:05:39]
And after using it, we're like, oh yeah, no, this actually works in even very complex cases.
[01:05:45]
We feel pretty good about this.
[01:05:46]
So that was kind of the progression.
[01:05:47]
So Elm GQL had a whole version of it that was basically very similar to Dillon's library
[01:05:53]
with some small changes around input objects.
[01:05:57]
And then the discovery was we really preferred this GraphQL to Elm approach.
[01:06:02]
And then partially I was like, okay, does it make sense to have both in one library?
[01:06:06]
I'm like, I mean, there might be some circumstances where like I thought about you could specify
[01:06:13]
fragments in sort of like, like in the Dillon way, but partially I'm going to let that need
[01:06:23]
sort of naturally arise.
[01:06:24]
I know supporting fragments is like in GraphQL, it's like that makes sense because it's in
[01:06:29]
the spec.
[01:06:32]
But so I took out that other part that mirrored Dillon's library and just focused on the GraphQL
[01:06:37]
to Elm approach.
[01:06:38]
That's really interesting.
[01:06:40]
I could certainly imagine a hybrid where you have a query builder style where you could,
[01:06:50]
for example, like have just like in Elm test files, you have exposed values of type test
[01:06:57]
and it registers those into the test runner.
[01:07:02]
You could do something like that where you have these like query builder queries, GraphQL
[01:07:07]
selection sets that are exposed from a file and those are your fragments.
[01:07:13]
And then Elm GQL lets you compose those fragments in and then it will use the appropriate types
[01:07:20]
from those.
[01:07:21]
Yeah.
[01:07:22]
So like that was definitely along the lines.
[01:07:25]
And I think in my previous or strange loop talk where I talk about Elm GQL very briefly,
[01:07:29]
I mentioned that that was like a thing we're supporting.
[01:07:31]
Now I'm currently like, well, let's see.
[01:07:37]
Because I feel as is with just the, without having the defined stuff in Elm, I feel pretty
[01:07:46]
good about the project.
[01:07:47]
I'm not ruling it out because ruling out stuff is not always beneficial.
[01:07:54]
But yeah, it was definitely on my mind of this hybrid approach.
[01:07:58]
So now that you're using these GQL files, you say that you have auto completion that
[01:08:04]
is very useful.
[01:08:05]
Do you also use linters on those kinds of files for instance?
[01:08:10]
No, but I think there's a, there could be, there's an interesting probably question around
[01:08:15]
like unused things, but that's an interesting probably discussion around like doing analysis
[01:08:21]
on the Elm side maybe.
[01:08:23]
And then figuring out like, it would be interesting to explore.
[01:08:27]
We haven't run into that need because usually if the unused stuff is the highest value,
[01:08:34]
just having the query there and where it's like this, I can see it directly and this
[01:08:39]
is exactly what's being requested.
[01:08:40]
It becomes pretty easy to audit a query and to remove stuff just manually.
[01:08:46]
So it's interesting, but not necessarily a high priority is kind of where I would frame
[01:08:53]
it.
[01:08:54]
Yeah.
[01:08:55]
I was mostly wondering like what cool things can you have for the linting on those files?
[01:08:59]
Cause I have trouble finding out what you could figure out.
[01:09:03]
I don't know.
[01:09:04]
I mean, I think some things that are interesting is there's the deprecated directive.
[01:09:09]
So basically you can know if a field is deprecated, that's interesting information.
[01:09:13]
It's not really linting though.
[01:09:14]
It's more to, well, it's applying the schema to your query, right?
[01:09:19]
So a limited version of linting.
[01:09:21]
So that surfacing that information is interesting, but yeah, I don't know.
[01:09:24]
I'd be curious if people can come up with a compelling like benefit or goal in mind,
[01:09:30]
I'd be curious to hear for sure.
[01:09:33]
But yeah.
[01:09:34]
Yeah.
[01:09:35]
And I guarantee you there's some tooling with like regular GraphQL schemas and GraphQL syntax
[01:09:41]
queries to look at all of them and find unused fields and things like that.
[01:09:47]
Like I'm sure it exists.
[01:09:48]
Right.
[01:09:49]
There is another thing that I think about that, but it's still based around directives
[01:09:53]
is on our, in our backend schema, though this data isn't public, but when we're compiling
[01:09:59]
our Elm app, we could make a special version of the schema that had this information.
[01:10:03]
You could have a directive that informs what permissions are needed to run a query.
[01:10:09]
That's already in our backend schema.
[01:10:10]
So basically if there's a query, you annotate it with like this query requires, you know,
[01:10:15]
and there's an enum that has a bunch of permissions listed.
[01:10:20]
So like this query to run it, you require these permissions.
[01:10:23]
I always thought it would be really interesting if there was some way for the front end to
[01:10:28]
know what permissions were needed.
[01:10:30]
So that ultimately the idea we would, if someone can't do an operation, we don't want to show
[01:10:36]
them the UI to do the operation in most cases, but tracking down those permissions thing
[01:10:41]
is it's a very manual task.
[01:10:43]
I'm not sure exactly what we do with the information beyond just making it very obvious to the
[01:10:48]
Elm programmer, but that's sort of a static analysis thing.
[01:10:50]
It's just, again, it's through that mechanism of directives as opposed to full like analysis.
[01:10:56]
Yeah.
[01:10:57]
So I want to make sure we bring up this tool by Harm Boschlo.
[01:11:02]
I hope I'm pronouncing that okay.
[01:11:06]
Called GraphQL to Elm.
[01:11:08]
So this is a...
[01:11:09]
Probably a better name than mine.
[01:11:12]
It's very obvious what it does.
[01:11:14]
Yeah.
[01:11:15]
Yeah.
[01:11:16]
Yeah.
[01:11:17]
So it's a similar query generator tool akin to Elm GQL.
[01:11:20]
So I wanted to just make sure we bring that up, that it's a similar approach.
[01:11:26]
Yeah, I haven't.
[01:11:28]
I only...
[01:11:29]
I think it was on my radar a little bit, but I've never played with it.
[01:11:32]
I think it seems pretty similar, but I personally don't know the ins and outs of the differences
[01:11:40]
of it, but I'd be curious if someone compared the two.
[01:11:43]
Yeah.
[01:11:44]
Yeah.
[01:11:45]
That'd be great to hear a tweet at us or mention it in the Elm Radio Slack channel or...
[01:11:50]
Yeah.
[01:11:51]
Let us know if you've played around with it and take a look at Elm GQL.
[01:11:55]
Let us know what the differences are there.
[01:11:57]
Great.
[01:11:58]
I'm guessing there are probably some subtle differences between the way that you manage
[01:12:04]
input objects.
[01:12:05]
So like in Elm GQL, we mentioned that you can sort of get around needing to build up
[01:12:12]
deeply nested input objects by the way you pass in variables and do most of that in GraphQL
[01:12:18]
syntax, not Elm syntax.
[01:12:20]
Yeah.
[01:12:21]
So if you... for that GraphQL getting all repositories example, if you have your variable
[01:12:30]
be this input object that lets you define all of the options instead of saying the input,
[01:12:39]
the GraphQL variable it's going to take in is a string for the username you want to list
[01:12:45]
all the repositories for.
[01:12:47]
If instead you say it's just the input objects that lets you define all of the custom filters
[01:12:53]
that the GraphQL API takes.
[01:12:56]
Then now you get to use the Elm GQL generated code that lets you build up these input objects.
[01:13:02]
And I think that's like one of the really interesting bits of design work there that...
[01:13:07]
So I'd be interested to compare those two.
[01:13:10]
I'm also really interested to compare that with Elm GraphQL because I think there's a
[01:13:14]
lot I could learn from that approach there.
[01:13:16]
Yeah, it's interesting.
[01:13:17]
I'm curious to see how the two tools kind of square up or the three tools rather.
[01:13:23]
Reenter, only one can leave.
[01:13:27]
Yeah.
[01:13:28]
Yeah.
[01:13:29]
So I feel like Matt, you made a pretty compelling case for your tool.
[01:13:32]
Got anything else you would like to add?
[01:13:35]
I mean, I think...
[01:13:37]
I mean, are you yourself convinced by Matt's approach or are you going to continue using
[01:13:45]
your own tool?
[01:13:47]
Well I think it's really interesting the story of like what do you want the source of truth
[01:13:53]
to be.
[01:13:54]
And like one of my main motivations...
[01:13:56]
Actually at the time that I designed my Elm GraphQL library, there was an Elm GraphQL.
[01:14:01]
It was actually...
[01:14:03]
If you did npm install elmgraphql, this was the tool.
[01:14:06]
Like Jay Haasen or...
[01:14:09]
I'm sorry, I'm botching the username, but something along those lines.
[01:14:13]
I'll drop a link to this deprecated...
[01:14:16]
Now deprecated repo, but it doesn't work for beyond Elm 18, I believe.
[01:14:22]
But that was using the query generator approach.
[01:14:24]
And I was aware of such approaches when I built Elm GraphQL.
[01:14:29]
And I built Elm GraphQL because I thought I would love to just work in Elm.
[01:14:35]
And I wanted to express these things at a high level with Elm.
[01:14:39]
I wanted IDE completions in Elm.
[01:14:42]
I wanted to have fine grained control over the types I build up in Elm and how I map
[01:14:46]
them.
[01:14:47]
So I do personally love having fine grained control over how I build up my types.
[01:14:56]
Even if I have control over my GraphQL schema, I really like that.
[01:15:00]
I do like being able to build up a selection set within an opaque type and expose that
[01:15:07]
so that it's not a type alias that could be constructed anywhere.
[01:15:11]
It is an opaque type where that knowledge is constrained to live in that one place.
[01:15:17]
And the only way you can get that type is through that selection set.
[01:15:22]
I think that's...
[01:15:23]
So the way I like to maintain my code, I really like maintaining it in Elm and being able
[01:15:31]
to use...
[01:15:32]
Elm tooling for it, yeah.
[01:15:35]
That I can craft myself.
[01:15:36]
So that's just my preferred workflow.
[01:15:39]
With that said, I think it's...
[01:15:41]
I mean, even though that's my preferred approach, it definitely gets my interest for things
[01:15:47]
like...
[01:15:48]
I don't know, maybe I just want to fire off a bunch of data to the server and I don't...
[01:15:54]
The data I'm getting back is not all that nuanced or interesting or important to my
[01:15:59]
domain modeling.
[01:16:00]
So yeah, I think it's really cool to have different approaches out there, but I think
[01:16:06]
they both have their uses.
[01:16:07]
Yeah, I would just recommend for people trying it out, probably if you're evaluating tools
[01:16:13]
to give them a go.
[01:16:15]
Like see if you can't take a day if you can.
[01:16:18]
I mean, choosing how you interact with data is probably one of the most foundational decisions
[01:16:22]
you're going to make on the client.
[01:16:23]
So play with it, see what you vibe with.
[01:16:27]
I think the important part...
[01:16:30]
The first important part is both of these are type safe ways of interacting with an
[01:16:33]
API.
[01:16:34]
That's wonderful.
[01:16:35]
And yeah.
[01:16:36]
Yeah, and there's a lot of really cool tooling out there.
[01:16:41]
I can't remember the name of the tool, but a lot of these graphical, like GraphQL...
[01:16:49]
The explorers for a lot of stuff.
[01:16:54]
I love having an API explorer like that.
[01:16:57]
It's really cool.
[01:16:58]
A lot of them these days have little check boxes where you can just say, like, oh yeah,
[01:17:02]
I want this data, I want this data, I want this data.
[01:17:04]
And it builds up your GraphQL query for you.
[01:17:07]
Yeah.
[01:17:08]
Once again, it's like static types, man.
[01:17:11]
When you have that kind of stuff, you can unlock a lot of those sorts of experiences,
[01:17:15]
which are nice.
[01:17:16]
My vision is like, I would love it if people were like, oh yeah, have you tried Elm?
[01:17:23]
It's amazing.
[01:17:24]
It has this like, you can just click this UI where you just click this thing and it
[01:17:28]
builds up all these different types with these little check boxes.
[01:17:31]
I want people to be saying that about using Elm APIs because all the information is there,
[01:17:38]
but we've got more people fiddling with tools in the GraphQL tooling space.
[01:17:42]
We need more people doing that in Elm.
[01:17:45]
You want to be a checkbox developer.
[01:17:48]
I mean, if you know that there's a set of finite possibilities, why not present them
[01:17:54]
in a finite way to me?
[01:17:56]
Yeah, man.
[01:17:59]
I'm right there.
[01:18:02]
Awesome.
[01:18:03]
It was a pleasure having you on to hash this out and to hear your story there.
[01:18:08]
And yeah, thanks so much for coming back on, Matt.
[01:18:11]
This is great.
[01:18:12]
Yeah.
[01:18:13]
It's always exciting.
[01:18:14]
Are there any, if people have questions, where should they go?
[01:18:18]
And do you have any resources to share on this topic if they want to learn more?
[01:18:23]
So the Elm GQL repo will have a guide.
[01:18:27]
I am currently working on a GitHub example repo to show how it asks for queries and stuff.
[01:18:36]
It might be kind of interesting actually to have a shadowing repo for Dillon's library.
[01:18:41]
Shadowing meaning if we had the same stuff so people could be like, oh, that's what that
[01:18:45]
looks like.
[01:18:46]
This is what this looks like.
[01:18:47]
I'm not saying I'm not putting work on Dillon's plate or my plate, but I'm making an example
[01:18:52]
repo.
[01:18:53]
So look for vendorinc.com slash Elm GQL and there should be a number of resources to read
[01:18:58]
more about it or play with it.
[01:19:00]
Just to clarify, Elm dash GQL.
[01:19:02]
Elm dash GQL.
[01:19:03]
Yeah.
[01:19:04]
Amazing.
[01:19:05]
Thank you so much.
[01:19:06]
And you're in.
[01:19:08]
Until next time.
[01:19:09]
Until next time.