Kevin is joined by Ramón to learn about the characteristics and strengths of GraphQL, although it may not make that much difference to him...
Speaker 0: Hello, and welcome to learning things I love to hate. In this show, I invite my friends and guests on to teach me about something that I've been avoiding for some reason or another. And today, I'm inviting my dear friend, Ramon, to talk to us about GraphQL. So could you introduce yourself, please?
Speaker 1: Yeah. Thank you so much for having me, Kevin. Yeah. My name's Ramon. I'm based in Vienna in Austria.
I'm a developer educator and developer relations consultant, and I do the odd job in some software development, which has given me the joy of it being introduced to lots of different tools and strategies for building software. And, Kevin, when you intro you know, came up to me to talk about GraphQL, it was something actually that I've taught in the past. So I'm just super excited to hop into it today. I hope you're having a good day.
Speaker 0: I'm having a lovely day. The weather's terrible, but I'm having a nice day. All the better for speaking to you. But, yeah, the fact you've taught this before is just fantastic. So let me just open with why I have avoided GraphQL so far.
Speaker 1: Please.
Speaker 0: So in theory, and maybe the the basis of my current understanding. So in order to serve up a Graph QL API, I know there are 2 portions. There's something that happens on the server side, and then there is a specific way of calling GraphQL or making GraphQL queries perhaps is the right terminology. I'm sure you can correct me later on the client side in your actual application. On the server side, I think, honestly, it just looks like there's a lot to set up.
There are a lot of parts of fetching and preparing data when, when compared with something perhaps a little a little more restful, I suppose, a little a little more standard where, you know, I can make very simple database queries and then just, you know, pipe the response back to the user. So I I understand that there's there's this. I understand there's some tooling, something called Apollo. Don't really know what that is. I understand that every time anyone ever uses GraphQL, they seem to install some additional dependency to make it more tolerable.
Maybe that's my negativity creeping in. Now one thing I know about GraphQL is you can also be very, very, very specific about the data you want to receive back. You can ask for specific fields only, which means that, you know, the response is smaller. You're sending less data back over the pipe. I think you can also go get, like, relational data.
So if there are some related items and but there's some preparation needed there. But, honestly, it just looks really complex. Whatever way you cut it, making them using graph using GraphQL APIs, it just looks like perhaps that complexity doesn't always trade off. So I'd be interested in knowing perhaps why this came about or why people might reach for building or using a GraphQL API over a REST API given the given the option. And then the only other note here is, you know, I work for directors, and we provide for your database both a REST and a GraphQL API.
But we also have a really powerful query syntax that allows you to be really specific about the data that comes back, including relational data without using GraphQL as well. So perhaps some of the trade offs, you know, some of the benefits of using GraphQL to a direct us user may not be as notable because you can just use whatever and gain very similar functionality. So that's a little bit of my basis for understanding. Please correct me if I'm wrong with anything. But maybe if we roll on back, talk a little bit about why, how, when, and Yeah.
I'll have a ton of questions, I'm sure.
Speaker 1: And please do hit me with them. And to be super upfront, Kevin, I'm a as as you know, I'm a very strong generalist. I love to, you know, weigh the pros and cons of different technologies, and I'm not gonna try and convince you today that GraphQL is the only way forward because You
Speaker 0: probably wouldn't win.
Speaker 1: Even if I wanted to. But, you know, I I I think that I think that when it comes to, you know, any kind of tool we use, we need to pick the right tool for the job. And GraphQL came about as a necessity for giving the client, that is the person developing against an API, the ability to be as specific and as, efficient in their data retrieval as needed. And as the name suggests, the QL in GraphQL comes from query language, which we might know from SQL, which is structured, I believe. Yeah.
Speaker 0: Structured. That sounds right. Yeah.
Speaker 1: I walked him I walked myself into a trap there. But yeah. No. So Graph 2o came about
Speaker 0: structured. I Googled it.
Speaker 1: Okay. Good. Okay. Cool. I'm already see seeming, like I know what I'm talking about.
I'm kidding. You can remove that if you like. Yeah. So RafQL came about as a necessity to it it came about from from meta. And as the name suggests, it came from a necessity from having large, complex graphs of data, you know, interconnected pieces of information between and the in terms of Facebook's use, you know, friends, comments, posts, and all of these, like, interconnected pieces of data to make retrieving them as specific as needed for a given application.
Right? When dealing with when what we know as RESTful APIs comes stems from this need to conform to the conform to the structure dictated by that API. Mhmm. I find myself often missing GraphQL when having very complex data retrieval needs. For example, one piece of client work that I work on has the gives you the ability to work with energy appliances at home, such as solar panels, power meters, and batteries so that you can interact with these and look up your data and all of this.
Speaker 0: Sure. Sure.
Speaker 1: When loading my dashboard and and looking at what what the data of the day is, I need to make 3 requests as a developer. 1 is for the solar power data, one is for the battery data, and one is for the, battery. So, I'm sorry, Kevin. I don't know.
Speaker 0: The 3rd appliance. The 3rd kind of appliance. Sure.
Speaker 1: Right. Right. And so and so what happens is when I need to load this, I need to make 3 requests to an API, one to each endpoint. And each of these, especially when working this is for a mobile application, mind you. Each of these becomes a single point of failure.
And having to chain these, I don't know, as a developer, as a consumer always makes me feel a little bit wary. Sure. Ideally ideally, I would be able to just make one request to a back end and get all the data that I need. Because, of course, I don't need all of the data. I just need specific data.
This is where GraphQL becomes really useful because I can link a user to their solar power data, their battery data, and their power oh, gosh. The 3rd appliance. I don't know what's with them today. Yeah. Thank you for the, thank you for bearing with me.
But for for retrieving these three pieces of data, being able to do so in one request, it is something is that I have found extremely compelling as a client side developer. Now as you correctly said, as a server side developer, it becomes a little bit more complex because unlike a RESTful API, we need to add a layer of complexity that is not only dealing with a, several, several endpoints in the REST API. We're now dealing with several kind of resolvers on the GraphQL side. And a resolver is one of 3 possible things. 1, we might know just from the get go, is a query.
If I wanna retrieve some data, I need to declare what kind of query that would be. For example, if I were, say, looking up that user, I would need to say, cool. This is what you can look up in a user, and these are the data types available to querying that user.
Speaker 0: Okay.
Speaker 1: The second type is a mutation, and this is where things become even more complex. Because, of course, not only do you wanna be able to query data, but you wanna be able to mutate it, that is change it. Be it, for example, push new data to the server, create new, data points for your solar power, or be able to delete stuff. So what we're gonna
Speaker 0: do so sorry. So a query is just like a read operation, create update, or delete would happen in a mutation. That's fine. That's That
Speaker 1: is absolutely correct.
Speaker 0: Data manipulation happens or mutation. I get that. That's cool.
Speaker 1: Yeah. And you would, as you would in a REST API, you'd need to declare what type of mutation this is and what data is available to it. The 3rd type, which is perhaps not as commonly used, is a subscription. What this allows you to do is, as the name implies, subscribe to a query. That is when that data changes, your client will be notified of that change, which operates mostly via WebSockets.
Speaker 0: Yeah. Yeah. And we offer those to Direct us real time. You can subscribe using what we call, like, the standard WebSockets interface, or you can subscribe to it using GraphQL
Speaker 1: API. But what about using it? Why is it that so many people love it so much as an alternative to restfulness? The first, perhaps perhaps pretty standard, because you are declaring exactly what type of data you want, it makes your data retrieval pretty efficient. You're only getting what you need.
That is minimizing the over fetching as you as from my previous example, instead of doing 3 requests, you're doing just 1. It's a single endpoint. The second is that because you are only getting the data you need, the size of the payload that you retrieve is significantly smaller because you're only getting what you need. The other advantages include this flexibility. Right?
If you need to get different data in different places, you all you need to do is expand your query just a little bit to add a field, and then you've got it. I actually can show an example of this. Shall we look at my screen real quick?
Speaker 0: Yeah. That'd be good.
Speaker 1: Yeah. And at the at the risk of being overly overly, what's the term? Overly standardized, we're going to use one of the favorites from Apollo GraphQL, which is the Star Wars GraphQL API.
Speaker 0: I don't know what that is yet. I'm sure we'll move on to that in due course.
Speaker 1: Absolutely. Apollo for context is a is a provider of a GraphQL API for JavaScript and TypeScript apps. But, the example they love to fall back on is Star Wars, so I thought I'd, you know, provide a little bit of that context there. So what we see here on my screen is a playground for interacting with a GraphQL API called GraphiQL, which the I here is for interactive.
Speaker 0: Interactive. Yeah.
Speaker 1: On the left here, we've got an a query that I've written, and on the right here would be the data retrieved, the result from that data retrieval. So let's take a look real quick at what I've got here. So I'm querying the all films resource. Inside that film all films resource, I'm querying the films resource. And from that films resource, I'm getting the title of each film.
Speaker 0: What's a resource in this context?
Speaker 1: Great question. So you know how we had those those, resolvers that I talked about? Yeah. Each of these, all films, is a resolver.
Speaker 0: Okay.
Speaker 1: So it's a query that is available to me to be able to query all of the films in the Star War well, most of them. It's not fully up to date, but you know what I mean.
Speaker 0: Sure. Sure. Sure. Everything in the database.
Speaker 1: Exactly. Everything everything in the database that you want to make available. Then that all films resource has available to it a films connection. So this all films query lets you query the films in that all films resource. I know it sounds a little bit wonky, and this is where we get into one of the disadvantages of GraphQL.
Syntax wise, it can be a little bit cumbersome to get used to. And then inside that, we can query all kinds of data related to a film.
Speaker 0: The films in the title make sense. There's a film's table or equivalent, and inside of that are a bunch of, sorry, a film's table or equivalent. And inside of that are a bunch of fields, and we're specifying that. I'm still not entirely sure what the old films is, but we don't have to answer that in this moment if you think it can become clearer later. I'm still not quite sure what all films is, where it came from.
Is it always named that way?
Speaker 1: What if I wanted
Speaker 0: to take for multiple tables Yeah. So on.
Speaker 1: Totally. And then to do that, what we can do is look at here on the left. We've got our documentation explorer. Again, this is built into GraphiQL, which is great for me to be able as a client user to be able to explore what is available in this, GraphQL API. So we can see all of our schema types, and let's talk about schemas real quick.
Because in GraphQL, you've got, just like in any other query language, access to a schema. When writing a GraphQL API, you need to declare this schema, and this is something that GraphQL is extremely opinionated on. You need to declare all of your types and how they relate to one another. So when building this all films resource, what we've done is declare all of what is available inside this film's connection. And, actually, what we can do when writing queries is, in graph in GraphiQL is if I press command space, I can see what is available here, kind of like an autocomplete.
So I can see, for example, the total count of films. So it's think of it as like a layer on top of the film's resource themselves.
Speaker 0: It's it's a set of metadata. That's cool. That makes sense. Is it maybe I'm jumping ahead. I'm pleased to tell me if I am.
But, like, these pieces of metadata are standardized for GraphQL APIs. I'll always have Not necessarily. Not necessarily. Okay.
Speaker 1: So this this API does it. But that's a great question. Yes. So and this consistency can also be a little bit strange to work around, but what I find really useful
Speaker 0: is API.
Speaker 1: Right. Right. At the end at the end of the day, we're what we're doing here is, navigating what somebody has already built. Sure. So by running this query, which I already have, you'll see that I've only retrieved the films and their titles.
Speaker 0: So so where does all films come from? Is that something you've named? You can name that whatever you want, or is that something that's provided by this API, This resource
Speaker 1: This is a resource provided by the API. This is a query resolver created by the API.
Speaker 0: Okay. Fine. Got it.
Speaker 1: Yeah. Cool. So yeah. And and inside this data, we're able when when working with, queries and this sort of thing, what we're able to do is tweak these to our needs. So, for example, if I wanna look up some more information about a Star Wars film, I can press, again, command space and see what data is available to me.
So let's look at, for example, the opening crawl of a Star Wars film. You know, that text that appears at
Speaker 0: the beginning. This one.
Speaker 1: Yeah. Exactly. If I want
Speaker 0: pains me. I know I know this is a GraphQL query, but it looks just enough like a JavaScript object that I'm like, where's the comma? Where's the comma? Oh,
Speaker 1: yeah. That is a that is a syntactical hurdle to jump over. I feel you.
Speaker 0: I know that there'll be white space, white space sensitive, which as a JavaScript developer is not something that I really have to think about very often.
Speaker 1: But, yeah, if I execute it, now I can see more data come in.
Speaker 0: Cool. Yeah. I mean, selecting specific and I assume sorry. Not to jump the gun. This bit feels quite comfortable.
This is just saying, hey. Look. I only want back specific field. And I imagine, that and I'd love to see if there's an interface for the relational data. I imagine that will be there too.
I think that's one of GraphQL's strong points. It's everything else. That's kinda where my knowledge and I don't know how to do that. I still wanna see the relational data grabbing. But it's everything else.
We've used some words. We've used words resolvers. We spoke about queries and mutations and subscriptions we don't need to cover today. In theory, I understand what they are. Yeah.
I'm still these concepts are still a little fuzzy to me, but this level of, like, just being very, very specific to avoid over fetching, which I'm not sure if I if I'm using that word right. Over fetching is the way you used it was making too many fetch making an excessive number of requests. I wonder if over fetching can also be used to refer to fetching too much data. But
Speaker 1: Which is in and of yeah. And that is absolutely in and of itself a danger that you're running with GraphQL as well because you need to be very specific about what you need. Otherwise, you are going to, you know, run into a situation where you're getting too much data. And this is where, some APIs will protect themselves by being very specific about, for example, the number of items.
Speaker 0: Data. That's where it just gets well out of hand, which it can do with directors as well. You can run on resources if especially if you're self hosting and you have to care about that. You know? You yeah.
Yeah. Because we allow you to do wildcards. We we can be like, hey. Give me every every related item and give me every configuration. And then, yeah, you're you're making very expensive requests.
Speaker 1: Absolutely. Absolutely. I mean, we can we can give that a try here with with seeing what's available. The way I love to use GraphiQL is to just sort of, like, just sort of take a look at what's available to me through this through this resource. So, for example, when we start seeing the word connection in this API, we're referring to this relational data that you've referred to before.
So, for example, we can see what species, I'm assuming, of alien live here, what starships are in these films, vehicles, characters. I'll just go ahead and try out planet. Why not? Yeah? When querying a planet, I then need to go a level deeper.
So this is where you're gonna see these nested curly brackets come in. And we've already used a connection here with all films and films. Remember, all films is the metadata, and films is the data of those specific films. So then when I want to query a planet's connection, again, just by hopping into this whoops, into that specific connection, I can take a look at what's available to me.
Speaker 0: So your planet collection is a resolver on the same level as all films?
Speaker 1: Correct.
Speaker 0: Fine. So resolvers typically only resolve 1 data type, one one table. Like, here we have all films, The only item inside of that that wasn't metadata was was films. And here in Planet Connection, the only property we have here that isn't metadata is Planet. Is that quite typical?
Speaker 1: I would say so. Yes.
Speaker 0: Okay. Cool.
Speaker 1: So we can go 2 ways about it. This Planet Connection again provides metadata. So if I go for example on total count, which again is the metadata for that planet connection, if I run it now, I can see how many planets are in each film. That's a lot of planets. And then from there, we can go into querying that connection itself and seeing what data is in there.
So I'll go here to planets. Again, I find GraphiQL so handy because it allows me to not only see what the schema of that relation is
Speaker 0: The
Speaker 1: that is a list of plan.
Speaker 0: An array of planets. Yeah. Cool.
Speaker 1: So we can go into that, for example. And then again, using this this data, I can look up its name.
Speaker 0: Do do as someone who builds a GraphQL API, do I need to set it up for something like GraphQL, or is it or is it does it do some form of introspection for free? And then I can use this in lieu I mean, I'm not saying you should, but you can use this in lieu of writing some level of documentation. Like, this this feels really good. This feels quite robust. Like, I could do the exploration I need.
Speaker 1: Yeah. And I think you can do a little bit of both, really. I mean, I would I would encourage folks to to have these sort of complement each other.
Speaker 0: Sure. But So what I mean is, did did you have to set this up with the Star Wars API, or did they do it, or could you pop in a different API here?
Speaker 1: Would this
Speaker 0: tool work?
Speaker 1: Yeah. That's a fantastic question. So out of the box, I believe, don't quote me on this, most GraphQL, server API, providers bring this GraphQL GraphiQL with them out of the box.
Speaker 0: Got it.
Speaker 1: So a lot of this will be generated from your from the schema that you declare when writing this.
Speaker 0: Hosted alongside your API. Exactly. Right? This is not like Graph iQL. Like, I have a code editor on my machine that can to everything.
No. This is a graph I q l instance for this Star Wars API. Got it. Exactly. Sorry for derailing.
I'm just trying to under
Speaker 1: No. No. This is how it works. Understand it. No.
This is this and and, frankly, Kevin, this is why I like developing with graph GraphQL because I don't need to, like, you know, make test requests and have it fail. I can just sort of try it all here. And as we'll see shortly, take this as is and just plop it into my into my application. Sure. So when running that, for example, I can then see, cool.
I can see that in in A New Hope, these planets show up.
Speaker 0: Yeah. Very similar to what a director's output would look like for, requesting relational data. This is this feels good. This feels grabbing data if this is more or less the extent of it. We're still a little bit fuzzy on what a result.
I know. I think I've got what a resolver is. A resolver is a provided interface for grabbing data, for fetching, for reading data. All films is a resolver provided by this API, which does exactly that. Connections are often you the word connection, the, the convention will be to use that for relational data.
Speaker 1: And there
Speaker 0: may be other kinds of resolvers. This feels this feels good. I would love to see just how you plop it into a front end, but it's the Totally. Where I'm starting to go a bit. I don't Yeah.
This feels good, but I don't know how I would set this. And we may not get to this in a demo. We did speak a little bit about focusing our demos on consumption, but I'd love to talk a bit about how you how you might set up and all the parts involved there.
Speaker 1: Totally. I mean, one one thing that I feel is missing from looking at this is, cool. We're looking at a sort of, like, list of data, but what if we wanna focus on one specific piece of data? Say, for example, and I'm spoiling my demo from later, what if I wanna look up my own data from GitHub? Right?
GitHub does provide both a REST API and a GraphQL API similar to Directus. So what I can do here is look up for example, what if I look wanna look up the planets for one specific planet? And I will have to use a different resolver for that, but we can look into that in just a second. The first thing I wanna do is look up an ID the IDs of all of the films so I can grab the ID of a specific film.
Speaker 0: Sure.
Speaker 1: So what I've done here is run that, and now I've got the ID for A New Hope. Now this is a specific, you know, data ID attributed to each film, so I can go ahead and grab that. And now what I'm gonna do is I'm going to I've I've copied that now. Now what I'm gonna do is I'm gonna start over and look at one specific film. So in order to do that, again, I I just love this this autocomplete so much.
It's so helpful for me to explore. So I can go to a specific film, and this one will have a requirement. You'll see how I probably will have an, an error. Let me just try and, say, look it up. Let's go with title just for the sake of argument.
If I try and run this now, I should get an error. So what we can do in GraphQL is provide validations for required, fields for doing a query. And fields work and fields work very much like in rest in rest in other kinds of APIs, we need to specify a specific thing. So, for example, we've got an error here saying must provide ID or film ID. We can show how to do that in, when looking at mutations.
So cool. The data I've passed in is film with null, and the errors is must provide ID or film ID. So with brackets, what I'm gonna do here and, again, autocomplete super super handy. I can specify an ID, which I already know in advance is this one here. So if I try and run that
Speaker 0: basically how you just have one endpoint handle, what would create what would need multiple endpoints with the rest API. This would be slash films and then slash film slash ID. It's 1 I'm mad. I believe GraphQL just uses a single endpoint. But this or can use a single endpoint, but this is how you tell it exactly what you want out of it.
Speaker 1: Exactly. And and, actually, there's there's an analogy I really like, which is, like, when when building, for example, resolvers. Right? Queries, mutations, and subscriptions. I like to think of these as equivalent of writing endpoints.
I've got an all films endpoint. I've got a film endpoint. These are all resolvers, which by nature of it being a little bit more condensed in terms of, like, what data I'm retrieving, lets me write fewer of them as a server developer.
Speaker 0: Could I ask one other question? Oh, do you want a hindsight? Because I'm pretty sure Oh, yeah.
Speaker 1: Let let let's try that.
Speaker 0: Works. Right? Cool. Yeah. Can I, inside of this this outermost object, use multiple resolvers?
I've noticed we've only used one. We used all films. All films, I think it was called. And we have Yeah. Film.
If I break line here and then you go all films, is that legit?
Speaker 1: Absolutely. Let's let's give that a try.
Speaker 0: Don't specify if you don't specify anything inside the films, you get nothing back, just an empty array.
Speaker 1: Let's give it a try. So, where did I do something wrong? Found closing brackets. So I assume that it was expecting me to put something in here.
Speaker 0: Which makes sense.
Speaker 1: I could try this and see what happens. It's a weird error.
Speaker 0: There you go. It defaulted to It That's fine. That makes sense.
Speaker 1: Yeah. So, yes, I can absolutely chain, queries. This is a great point. And, again, reduce that to be just 1.
Speaker 0: Yeah. Right. And so this this is going back to your initial example of your your 3, you know, appliance types in your home. You could just Yep. Ask for all 3, ask for just the data you need, run one request, get the data back.
In my mind, it's still boggling how that how you resolve that. Resolve might not be the right word because it means something in North Korea, but how you handle that. But yeah. Okay. I'm I'm seeing it.
I'm seeing the value here.
Speaker 1: Yeah. The let let's go back to this one real quick. Let let's, let's bring up that planet connection again. Actually, let's do something different. Let's do characters.
Characters, and we'll do the name. So now we've got all of the characters that show up in A New Hope. Right? This is all well and good. And when we want to do something like, you know, looking up specific films, say if I were opening a page in my Next JS app for each individual film Sure.
This would limit me in that I'm only limited to a new hope. So if I wanna use variables, that's something we can absolutely do here as well. And GraphiQL, once again, makes this super super straightforward to me to you'll see here at the bottom, I've got access to both variables and headers, which is gonna go into the whole authentication question.
Speaker 0: Mhmm.
Speaker 1: So if we look at variables, for example, we can pass in this is gonna be a JavaScript object here. Oops. That is not what I wanted to do. We'll set the ID to be this one here. And when going up here, I now have access to this variable via dollar sign notation.
Speaker 0: But this this what you're showing me now is do you need to add, like, a dollar sign? In any case, I understand I understand what we're trying to do here. But just so I just so I get it. This is GraphiQL specific. Because in the real, I would just do this with JavaScript.
I would like interpolate a string into a query.
Speaker 1: Yes. You know what? I think what I'm doing here wrong is I need to declare the variable. My bad. Cool.
And we need to say what data type it is. So film ID. I'm probably doing this completely wrong, mind you.
Speaker 0: We'll find out in a moment when it doesn't work.
Speaker 1: So I think that's how I wanna do it. Expect a dollar sign. There we go. So So when writing a
Speaker 0: Sorry. So this is no longer a resolver. Resolvers are basically prebaked queries. They are endpoints. But you can also make more free form queries using by forming a query.
Speaker 1: Kinda. What I'm doing here is making a query. I'm declaring a query a query that is going to run against the resolver on the server that is going to pass to it, that is going to be using inside of it this variable. Okay. Does that make sense?
Speaker 0: Yeah. I'm a little bit fuzzy on why we're bothering when, again, we're in this web environment. But in the real, I would be writing code, and I can just I could just add a dynamic value straight within the the film?
Speaker 1: You could right. Yes. We'll see how we'll see how to do that. But and you could absolutely interpolate that using, like, string vary variables because at the end of the day, these queries are strings.
Speaker 0: Yeah. Exactly. But maybe that just isn't the done thing. So this is a this is the first query I've seen. I I get it.
I mean, it kind of just looks like a a function that fetches, and there's there's the parameter, and I use the parameter inside. Sure.
Speaker 1: Totally. Yeah. So we can and we can use those for going into, for example, looking up specific films. And that I would say is sort of like the extent of how you would most of the time use GraphQL on the client side. When developing on the server side, what I can do is bring up the would would you be cool with, like, going through the documentation together and, like, looking at how mutations look?
Speaker 0: Absolutely. This this is all just a learning exercise. So if it isn't working for me, I will let you know. But, yeah, let's let's do that. I'm cool with reading docs.
Speaker 1: Cool. Let me bring them up then. GraphQL. I know and now I'm gonna step into GraphQL, sorry, into Apollo GraphQL.
Speaker 0: So let's start with what is you described it, but I didn't quite understand the description. What is Apollo GraphQL, and why does everyone who use GraphQL seem to reach on the server side seem to reach for it?
Speaker 1: Yeah. So, Apollo GraphQL is a provider of GraphQL frame not framework. Pardon me. Package for JavaScript and TypeScript apps that lets you both interact on the client side and on the server side with GraphQL. Now when you're working with GraphQL in a different programming language, you're not most likely not gonna have Apollo GraphQL available to you.
For example, I wrote a, a GraphQL server in Rust, and there's no Apollo GraphQL for that, but there is a third party package that makes it available for you.
Speaker 0: Okay.
Speaker 1: So when, when declaring a back end for
Speaker 0: Just so you know, I I still only see GraphiQL.
Speaker 1: Yep. No. Don't worry. I haven't not worried. I haven't gone there yet.
I'm just looking for a really good example, and I don't have one on hand, and I'm very sorry. We might have to cut this out. I just want to see if I can find a really nice example of 1. To clear schema. Here we go.
Perfect. Yes. Cool. Oh, and this uses Star Wars as well, so worth being consistent here. Cool.
I'm gonna go ahead and share my screen again. So as said before, GraphQL highly dependent on being really, really tight tightly typed. Right? So when we're declaring types, we know when we're declaring data in GraphQL, a schema, it involves being very specific about not only what resources are available, but what data are available to them to be exposed to the client side. And this can be done in several ways, such as using provided data types that are built in like strings, for example, or, data types that you have declared.
So when you're building a schema, you want to be very specific. For example, a character has a name which is a string and which episodes or which films they appear in. You might see this, exclamation mark as well. This means that this is a required field.
Speaker 0: Fine. Yeah.
Speaker 1: Right? So you might see here, for example, an episode cannot be null inside this list, which cannot be null. Yeah. Again, this is when declaring a schema. So you can also have things like arguments.
You can have default values for specific fields when querying, but also have them be enumerables. You know, a list of specific values.
Speaker 0: So
Speaker 1: our schema will then evolve into being part 1 of 3 things, one of these 3 resolvers. These can be queries, mutations, and subscriptions. So when we're querying against this this API, for example, we can preface this with query to fetch that data. But if we also wanna do a mutation, we would just preface this with mutation.
Speaker 0: Can we see what one of those looks like? Sorry. It might mean scrolling around. Sorry. I I understand that, but there's also gonna need to be data being passed in.
Right? I'm kinda curious how that would look.
Speaker 1: Let's see if we can find 1. Interfaces. Yeah. We can have a lot of, a lot of, syntactic sugar to make things simpler for us, but we're looking for a mutation specifically. And this can get really complex as you can see.
Here we go. So we've declared a mutation, resolver called create review.
Speaker 0: Okay. Yeah.
Speaker 1: Yeah. This takes in a few fields as parameters. Episode and review. Yeah. We can see those being declared in this in its use up here, and we're passing in that data through this query.
Down here, we can see the variables being declared and then the response here on the right.
Speaker 0: The the stars and commentary is the data that comes back. Sorry. So how do I use a mutation?
Speaker 1: Sorry. I was unclear.
Speaker 0: No. There's nothing we're missing here.
Speaker 1: No. Totally. So this is an example of using a an already declared mutation resolver. Right? So we're using that we're saying, hey.
I wanna do I wanna perform this mutation, which whose resolver has this name, create review for episode. We're going to be passing to that mutation this data. So these two variables
Speaker 0: like calling a function.
Speaker 1: Essentially, like, calling a function.
Speaker 0: Has that name. It already has that signature.
Speaker 1: Correct.
Speaker 0: Okay.
Speaker 1: Correct. And then we call that mutation itself, passing to it the according data.
Speaker 0: Sorry. Terminology thing. So what's the Totally. First and last line? If if create review is the resolver, which performs a mutation, I think I'm using the terms right, what is this first line, mutation create review for episode?
And how much of that is determined by the server versus determined by the consumer?
Speaker 1: Great question. And I'm sorry. That was on me for being unclear. So why I'm asking. We're declaring that
Speaker 0: That's why I'm asking. That's okay.
Speaker 1: Great. Yeah. So we we're declaring that we want to use a mutation. We're giving it a name that we're gonna be using on our side and declaring the variables that we're gonna be using in this mutation.
Speaker 0: This is like this is like, writing a function where the function is going to perform a mutation. That's why it has mutation at the front. And then create review is the name of the mutation that already exists. It expects an episode. It expects a review, stars commentary.
So this is us defining it and then using it is what? No. This is how you use it. No. And then you use it.
This is where I'm getting a little bit I'm not entirely sure.
Speaker 1: Totally fine. I was
Speaker 0: down below. That's the data that's within it. It has an episode name of Jedi and a review, which includes stars and commentary.
Speaker 1: Exactly.
Speaker 0: So that is the review. The shape of a review is determined above. It has a stars and commentary in that box, up up above the cursor now. And then what it will return is the stars and commentary. That's why they're nested in there.
Speaker 1: Exactly. And in here, we're also seeing that this is the data we get back in our response.
Speaker 0: Yeah. Yeah. I got it. So the reason you
Speaker 1: have to
Speaker 0: pass it in below is because that's the shape of the review input above.
Speaker 1: Exactly.
Speaker 0: Exactly. Quite verbose. It looks like I'm doing a lot of steps here. Like, what feels like it could be very concise because it isn't overly complex, Feels like it's being dragged out over lots of parts.
Speaker 1: So and you're absolutely right. And this is this is one part that I feel that if if you're gonna be doing a lot of mutations, I find that GraphQL actually tends to be a little bit overkill, because most of the time when you're creating data, you are creating records in a database, you don't really need to go beyond a certain amount of specificity for it, in my opinion, especially in a narrow use case, such as, for example, creating a review.
Speaker 0: Seated example for education, of course. You know, in reality, the complexity brought about by real world applications might demand separation of concerns, which is effectively what this is. I just feel it's being separated a lot. The benefits that I'm seeing are, about making codes dry, but also Yep. There's a lot of abstraction in here and a lot of data fetching.
But in this, yes, mutation side, this feels clunky as heck. I'm not sure I like it.
Speaker 1: That is entirely fair. And I have to admit, it's not something I've used a whole lot. And and I think, like, for me, primarily, my my my benefit my favorite use case of GraphQL is more on the retrieval side. Yeah. So that's how we would go about using a mutation.
To declare 1 would require, on the server side, having a definition of a schema and each of these mutations, which can then, not sorry. Each of these resolvers, which you can then bring into your application and use, you know, use however you wanna use. And different types of GraphQL providers are gonna give you different amounts of flexibility. On the server side, you're gonna find yourself more often than not relying on your own data source. So because GraphQL is pretty source agnostic, you can use everything from, like, an in memory array in your server to, you know, even interacting with an existing REST API if that's something you want to do.
Yeah. And, of course, database providers. So that's how we let me just hop back real quick to our, Star Wars API. So that's how you would go about using, using GraphiQL to figure out the query you wanna do. But to then use it is something that I wanna bring in now for our demo purposes of, for example, looking up my data on GitHub.
So what I'm gonna do right now is hop over to this explorer on GitHub docs, and I'm gonna try my best to make this look nice because it does have a little bit of, like I really wish I could, you know, just have this
Speaker 0: Page page in a page in a page. Page in
Speaker 1: a page kind of thing. I think this looks okay. Does this look okay?
Speaker 0: Yeah. Yeah. Yeah.
Speaker 1: Yeah. Fantastic. So, like I said before, GitHub provides a REST API and a GraphQL API, which when you wanna work with it, you can also interact with using GraphiQL in their documentation, which is super handy. So what I've done here and we can go already look at it going by what we've already covered so far. I've got a query called that's gonna look up in the users going with a login, which comes from a username as a variable that I've provided.
Mhmm. My and the name of the user, the avatar URL of that user, and look up against its repository's connection with some provided things here, which we'll look up in a second, which ID and name of those repositories are there?
Speaker 0: What's an edge? What's a node? I noticed the terms over in Star Wars land as well.
Speaker 1: Yeah. So these are these are provided by GraphQL to describe the connection between the connection between these, relational objects. Right? So if you think of a graph as you would what are those called? A graph?
That's computer science graph? You know what I mean? Like, a a set of edges and nodes. So a node is a data point that is connected to a different data point via a node.
Speaker 0: If I it feels weird to have to expose that to someone consuming an API. But yeah. Okay. I'm with you.
Speaker 1: So most of the time, you won't have that. You and you probably if I were to go through that here. So most of the time, you're gonna have that sort of shortcut, resource. I'm just gonna hop back to the Star Wars API real quick because I wanna showcase this. You see, for example, in our query film title character connection, we go straight into characters.
Another way convenience. That's a convenience. Exactly.
Speaker 0: That isn't typically like, out of the box, that isn't what it would be.
Speaker 1: No. So another way to make the same query would be by going by its edges and then its its node of the each of those edges and then getting the name of that character. This works the exact same way.
Speaker 0: Interesting.
Speaker 1: The data is just a little bit chunkier.
Speaker 0: Fine. Alright. That makes sense.
Speaker 1: But I'm really glad you caught me on this. So, yeah, edges oh, oh, right. I already wrote that. So back here, right, I've looked up the edges of that connection and the node the node for each of those connected repositories and then the ID and name. Let's look at the fields being used here in repositories real quick.
So because it's a little bit clunky, but we're looking up the first 50 repositories that I own. This is actually a required field by GitHub. And, actually, why not just remove those so I can show so I can illustrate that? So if I wanted to look up all of my repositories, right, running into that danger of, if I have, like, thousands
Speaker 0: of where it could be, yeah, exactly, thousands of of
Speaker 1: Exactly. We would be getting several several several several results. And the way that the GitHub GraphQL API is designed, it requires you to specify pagination boundaries. It says here in the error message, you must provide a first or last value to properly pad paginate the repository's connection. Yeah.
So that's why we want to have our first value set to 50. And just because I'm embarrassed to show, like, my first 50 repositories, we're gonna actually order reverse the order of these so I can specify this order by, and then we need to specify, I believe, the field
Speaker 0: Being white being white space sensitive, could you break line inside of this object? It's not really an object at all.
Speaker 1: I don't know. Let's find out.
Speaker 0: Yeah.
Speaker 1: Field would be created at and be, I think it
Speaker 0: would be Or or not there, but before the word field, I think. Just because it's getting long, isn't it? It's becoming not very visible.
Speaker 1: That's a great point. Let's do that. So like this, right?
Speaker 0: Yeah. Sure. I'm just curious.
Speaker 1: We'll go and again, because these are enumerables provided by the GitHub API, we can be specific about which order we wanna do that without having to, like, write strings or anything like this. So we would have that. Right?
Speaker 0: Break line. Break line.
Speaker 1: Thank you. So I'll go ahead and try and run this.
Speaker 0: That works. Yeah.
Speaker 1: Yeah. It'd be good to know. So we'll execute that query.
Speaker 0: Not kicked up a fuss, so I'm guessing fine. Yeah. There was no red squiggles.
Speaker 1: Exactly. So it looks good, and we can see there my latest fifty repositories.
Speaker 0: The data structure that comes back is quite, any Is there any way to make that more palatable in the request, or is that just something you have to handle?
Speaker 1: I think this comes down to a graph to the server API design.
Speaker 0: And you as the consumer actually then going on to handle it. Yeah.
Speaker 1: Exactly.
Speaker 0: Alright.
Speaker 1: But yeah. So this is how I would use it. Yeah. Sorry.
Speaker 0: No. No. No. I answered my own question. I was gonna say, where's the username coming from?
But, yes, it is right there in
Speaker 1: line 7.
Speaker 0: It's provided by the variable at the bottom and then injected on line 7. Exactly. BS
Speaker 1: code because I've got an example React app that's already running. BS code because I've got an example React app that's already running, and show you how to how I would use it on a day to day basis.
Speaker 0: That'd be good.
Speaker 1: Mind you, this is not gonna win a design award, but I think it'll it'll do the trick. So the first place we're gonna start is here at our React app. Is it cool if I hop through the dependencies real quick just to set the stage? Yeah. Yeah.
Fantastic. So this is a bit of an older create React app using amongst other things, Apollo client, which is that Apollo GraphQL provider I was talking about before if I were to actually there we go.
Speaker 0: Not strictly required to call web, to call GraphQL endpoints, but we'll get some nice convenience out of using it.
Speaker 1: Exactly. Exactly. We also have the GraphQL dependency here as well.
Speaker 0: Okay.
Speaker 1: This is gonna allow us to build queries.
Speaker 0: Okay.
Speaker 1: So, going by React, we're gonna hop into our index JS, which is sort of like the top level of our React app. And what I wanna what I wanna showcase here is where we set up our Apollo client. Right? We set up this new Apollo client, which we've imported from Apollo client itself. The URL is at GitHub API GraphQL.
We do caching. We can set up caching here as well. This is a question with GraphQL that we can go into a bit later if if that's cool.
Speaker 0: Yeah. I can do. Yeah. It's it looks like an Apollo specific, thing. Yes.
Yeah. That's cool. It makes sense. I don't even think we need to go into it. You it can handle caching for you.
Speaker 1: It can. Yes. Yeah. And this is the the reason I the only reason I wanted to bring it up was because this can be a contention of using GraphQL in that because your data is so dynamically constructed, caching does become a little bit more overbearing to do.
Speaker 0: Mhmm. Okay.
Speaker 1: And when setting up an Apollo client, I can also set up my headers, which for the GitHub API, I'm gonna need to, know, I've set up an end file with
Speaker 0: my GitHub API
Speaker 1: And variables.
Speaker 0: Token. Not necessary not here?
Speaker 1: Not here yet.
Speaker 0: Fine. But because it was headers and variables in GraphiQL, but fine. But you would set up headers here. I imagine you can overwrite those on a per request basis as well. We're just setting up Total.
Defaults.
Speaker 1: Sure. Exactly. Sure. My React app will be surround will be included inside this Apollo provider component, which will do all of that Apollo GraphQL magic for us, do all of the authentication so that when I go into my app, which is this component here and I made I said, not gonna win a design award here just to show you what I'm doing here.
Speaker 0: You're really setting the stage here.
Speaker 1: I mean I mean, I just wanna I I'm going for for function over form. Is that the term? Yeah. We're gonna you'll see what I mean. But yeah.
So what I'm doing here in my app is essentially grabbing a a username from my window location. If there is none, it'll default to my GitHub username.
Speaker 0: Sure.
Speaker 1: Pass that to a profile to a profile component where I specify that username. And here in the profile is where we're going to be building and utilizing our GraphQL request. So I've copy pasted this, but I wanna I wanna expand on it when we do some modifications to it, which I would like to showcase as well. So cool. We've got a we've got this GQL function that comes from using Apollo client that lets us build our GraphQL query string.
So we declare our query called profile lookup. It takes a required username variable as a string
Speaker 0: Mhmm.
Speaker 1: And then does the query that we've seen before.
Speaker 0: Sure. Yeah.
Speaker 1: Apollo also provides a use query hook that allows us to run that query, And here Oh,
Speaker 0: I'm providing
Speaker 1: pass any variables.
Speaker 0: At the time of running it.
Speaker 1: Exactly.
Speaker 0: So and and I see loading error data being, deconstructed from it. I imagine I think error and data are GraphQL specific because we've seen those. But loading feels like a an Apollo, perhaps, convenience. Yes. Yeah.
This is a convenience. This is coming together.
Speaker 1: Exactly. So, yeah, if we're loading, we show it. If we have an error, we show that. And, otherwise, we and, again, we can see that that data object is provided to us as the in the response so that we can dive into it. So, for example, get the user's name.
Yeah. Get the avatar URL, and you can see here user repository edges, and then look into that node to get the ID and the view
Speaker 0: of that. Just working with data on the front end. Interesting.
Speaker 1: Exactly.
Speaker 0: Okay.
Speaker 1: So if I go so if I go back to my browser, I've actually got it running here.
Speaker 0: Nice.
Speaker 1: Grabbed all of our data and made a set then this is what I meant by not winning a design award. Got a list of the latest 50 repositories. Cool. If I wanna modify that, and that's this is what I would like to work with a little bit just to showcase how I use it on a day to day basis. Say if I wanted to get the, turn these into links, I would hop over here, and for those repository edges, I would then look into my very handy list, see if there's any kind of, like, a URL kind of thing, which I can
Speaker 0: see there is. This so like I said earlier, this can be in lieu of just, you know, descriptive documentation that just lists all of the properties that come. You're you've you've not touched the GitHub API reference here. You've just come straight here to see what's available. But there has to be some intuition, I suppose, as to what things are called.
So we're taking for granted your your, what I call, developer sent, your ability to sniff out the answer just based on your experience. But, yeah, completely viable.
Speaker 1: Totally. And and if you wanted to, I said, because of the way the schema is declared, you can actually go and look at now GitHub is gonna have a lot more of, schema types than Star Wars is, and provides mutations as well for you to do things like, I don't know, update your profile picture or something, or your name. You can see a bunch of data types available. So I can for example, let me just go quickly over to repository. R is for repository.
Then I'll have to scroll back up because it's not the most convenient way to use this. And we can see what field fields are available to us.
Speaker 0: Fine. Fine. That makes sense. This might feel a bit risky, and you can say, no, Kevin. I'm not gonna do that.
But, like, so how would you do a mutation in this context of your actual application?
Speaker 1: I mean, I I probably wouldn't do that in a video. Sure. But, like, I think the way you'd wanna do it is so declare a mutation. Yeah. Actually, let's go back because I've actually never done a mutation here before.
I wonder if there what is available to us. So I would see what mutations are available to us.
Speaker 0: This is actually probably where my previous statement about not needing, like, you know, a handwritten API reference goes out the window because there are so many mutations and resolvers that we just saw that really so solve no purpose apart from being internals that are exposed in a edge case. That was not a very nice experience.
Speaker 1: I I it was it's it's a bit cumbersome to get into, but once you sort of, like, get used to knowing what to expect from navigating a set of documentation here Sure. The good thing is and this is one of the I see this as a double edged sword for for GraphQL in general. There is, as with most most tooling, a hurdle of of of learning.
Speaker 0: Mhmm.
Speaker 1: But what I like compared to a REST API is that once you get the hang for, like, the syntax, working with it becomes mostly consistent across different APIs. So Yeah. When bringing it in to be used in a in a team, for example, if you've got a team that is used to GraphQL and the scope necessitates its use, I find it pretty handy to work with. Interesting. So for example, if I want to create a repository, I can declare a mutation, which takes a set of fields here.
I see it'll need a name, It's visibility. And is that it? I guess that's it. So I could declare a repository using this mutation resolver or endpoint depending on the your code.
Speaker 0: Can we see, like, how you might do that? I don't expect you to hit go. I'm just kinda curious.
Speaker 1: Yeah. Totally. I would probably start here and then bring it over to the code.
Speaker 0: Is that and that would be your workflow?
Speaker 1: It would be mine. Yeah.
Speaker 0: Interesting.
Speaker 1: So we we would take, 2 variables and create
Speaker 0: Oh, no. Because create repo is your name for it.
Speaker 1: My mutation.
Speaker 0: Your function. Your mutation. Exactly.
Speaker 1: Oh, I
Speaker 0: got it. And terminology wise, you're creating a mutation now, which uses a resolver, which mutates the data. It's kinda like this cascading set of terms.
Speaker 1: Exactly. So that would be a string And
Speaker 0: there's a visibility Yeah.
Speaker 1: Ability, which is of type I have no idea what type this is.
Speaker 0: Is it not repository visibility? Yeah.
Speaker 1: Yeah. Visibility.
Speaker 0: Which I suppose we can dig into in a moment.
Speaker 1: Yep. So let's take a look at what it is.
Speaker 0: Squiggly there, by the way, if you go further to the right.
Speaker 1: Yeah. Forgot my password. Fine. Yeah. Thank you.
Cool. So it's it's an. So, and here I would say, use the create repository mutation resolver, which remember takes 2 fields. So that's going to be the name which comes from the name and the visibility. This is getting a little bit cumbersome.
I'm going to hide the documentation real quick Just so we have a little bit more screen real estate. Ability will be the visibility itself.
Speaker 0: Sure. Getting some squeeze. Feels very, what word am I using? It feels very verbose. It is probably very verbose.
Speaker 1: And I'm probably doing it in a more cumbersome way. Do I mean create repository?
Speaker 0: Honestly, don't worry about it. I think I got
Speaker 1: the gist. Yeah. But, I mean, that is essentially how I would use it.
Speaker 0: So and this this would basically just so I understand. The only other thing you would do, right, we resolve the red squigglies, is you do one more set of brackets, and you would just say, okay, what data am I gonna return? And then that's the whole mutation. Then you would take that into your code and and
Speaker 1: Essentially, copy paste it in here.
Speaker 0: Copy and paste it.
Speaker 1: Let me let me take this as is. It's not gonna be
Speaker 0: the previous. We will recognize that that won't work verbatim. That's fine.
Speaker 1: So it'd probably be make I know that this is not going in in line with what we were talking about, before in terms of, like, chaining lots of queries and short No. I'm not
Speaker 0: bothered. Let's do it standalone. Yeah.
Speaker 1: Request. And I'd set that to be GQL.
Speaker 0: GQL is provided by Apollo. Yeah. See at the top. That's correct.
Speaker 1: And that is essentially how I would do it.
Speaker 0: Interesting.
Speaker 1: Interesting. Go and use it as needed.
Speaker 0: But you would yeah. Okay. No. That makes sense.
Speaker 1: And then
Speaker 0: And you would do a use query. Is it is it use query, or would it be like a use mutation?
Speaker 1: I'm not actually sure because I've never done a mutation in in in Sure. But it's But I would assume that
Speaker 0: there's idea.
Speaker 1: So we have here Use mutation. Use a mutation. Exactly. Okay. So And that's essentially how it work.
Speaker 0: I got it. Was there anything else you wanna share about this? I think I've kind of got it. I'm gonna sum up what we've learned in a moment or what I've taken away. But is there anything key that you think is missing?
Speaker 1: I can't think of anything off the top of my head beyond, if I wanted to, and we were kind of elaborating on that before. If I wanted to have lots of queries in here that I wanted to do in one go, I would just, you know, put in a separate query here.
Speaker 0: Yeah. Yeah.
Speaker 1: But I think that about sums up, like, illustrating what it is that I wanna do with GraphQL.
Speaker 0: No. And I think I've learned a lot. So thank you. But so just to sum up Fantastic. You make API requests using GraphQL to an API that exposes a GraphQL interface.
Subscriptions. Subscriptions are like real time WebSocket stuff. We didn't talk about that beyond just that description. Queries are used for fetching data and mutations for any anything else. The create, the update, and the delete.
They're all mutations. You can in creating so resolvers are created by the API authors, and they they denote what you are able to what you're actually at once. So you can you can Correct. Get more data. You can specify what fields to bring, what connect what connected data, what relational data to grab.
It definitely honestly, at the end of this, I still think it looks rather clunky. I think the the fetching of data, the reading of data, I think it looks really nifty. I think that's super handy. In the world of directors where we effectively give you that there isn't that parallel, I totally get that. But in terms of there isn't that parallel, I totally get that.
But in terms of creating data, we didn't obviously on the on the code side, we looked just at the consumption, the client. Yeah. But I imagine actually setting up those resolvers, touching your database in the right way, bringing back the right data feels like a level of complexity that I'm not sure I'm ready for yet, but I now appreciate, which I think was my real goal with this series.
Speaker 1: Yeah. Yeah. No. I I I can I can tell you from a consumption side, and and it's kind of a weird parallel because I find that on the consumption side, declaring mute like, using mutations as as we both saw feels a little bit clunky? I think on the server implementation side, providing a single, let's say, endpoint for not just creating, but you could also swing it in a way so that you're for example, when providing an ID, updating a resource instead of having 2 endpoints for that, you've got one resolver for it.
Can be really handy. The thing to watch out for there, as with most of these types of tools, is that remember that this is a query language. So when setting up resolvers, this when implemented poorly as would any kind of endpoint for this, gets you in line of danger with, say, malicious code running against it.
Speaker 0: Sure. Okay. That makes sense. Although that whole thing of yeah. You can you can, build one resolver that serves multiple purposes.
It's exactly the same in the rest API. It's all down to the design of your API at that point. And the design doesn't need to be consistent, across all APIs. You just need to remain consistent within yours. Yeah.
Excellent. Well, thank you so much for coming and teaching me about GraphQL. I have learned a
Speaker 1: lot about
Speaker 0: how it works. Not sure I'm entirely sold on it still, but, again, the context of my work allows me to be not be sold and still gain most of the benefits of it. So I'm quite lucky in that.
Speaker 1: Totally.
Speaker 0: But, yeah, thank you ever so much, and thank you to everyone who tuned in. Until next time. This has been learning things I love to hate.