GraphQL Doesn't Need To Be Hell with Dmitry Tsepelev - RUBY 665
Different doesn’t need to be worse. Dmitry Tsepelev tells us how to make the most of using GraphQL with Rails, the advantages over REST-based API queries and best practices for security and schemas.
Special Guests:
Dmitry Tsepelev
Show Notes
Different doesn’t need to be worse. Dmitry Tsepelev tells us how to make the most of using GraphQL with Rails, the advantages over REST-based API queries and best practices for security and schemas.
Links
- https://github.com/anycable/anycable
- https://graphql-ruby.org/
- https://evilmartians.com/chronicles/persisted-queries-in-graphql-slim-down-apollo-requests-to-your-ruby-application
- https://evilmartians.com/chronicles/graphql-on-rails-1-from-zero-to-the-first-query
- https://evilmartians.com/chronicles/graphql-on-rails-2-updating-the-data
- https://evilmartians.com/chronicles/graphql-on-rails-3-on-the-way-to-perfectionGraphql-ruby benchmark
- https://gist.github.com/DmitryTsepelev/36e290cf64b4ec0b18294d0a57fb26ff
- Saint P Rubyconf 2019
- https://github.com/DmitryTsepelev/ar_lazy_preload
- https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries
Picks
- Luke - https://blog.phusion.nl/2018/11/28/stopping-slow-client-dos-attacks-with-puma-on-passenger-6/
- Charles - The Black Prism
- John - https://www.stickermule.com/
- Dave - StarTech.com Under Desk CPU Mount – Adjustable – Heavy-Duty Computer Tower Mount – 360° Swivel – Computer Mounting Bracket
- Dave - https://noctua.at/
- Dmitry - https://hacktoberfest.digitalocean.com
Transcript
Hey, everybody, and welcome to another episode of Ruby Robes. This week on our panel, we have John. Hello, everybody. Luke. Hello, Dave.
Hey, everyone. Wow. It feels so much more familiar to not say your last names. I'm Charles Max Wood or Chuck. I'm Chuck.
And this week, we're talking to Dimitri. Dimitri, do you wanna say hi and let us know who you are? Yeah. Sure. Hi, everyone.
My name is Dimitri, and you can call me Dima if it's simpler because I know that Russian names are hard sometimes. I started my software development career in 2012 and decided to focus on Ruby and Rails in 2014. Before that, I did some dot net development, front end development, and iOS. And since 2018, I guess, I worked as a back end developer at evil markets. I spent a lot of time working on open source.
I committed to Ruby Rails, GraphQL, and some smaller gems. And I also maintained some of my own gems. And I started working with GraphQL, I guess, in 2,017. So it's, like, 4 years about 4 years so far. Nice.
So the discerning listener probably heard Graph QL about 4 times in your introduction, and that's what we're gonna be talking about, specifically GraphQL and Rails. We talked about Graffiti a couple months ago, and so this will be interesting to kind of compare the approaches and things like that. I know that some people love GraphQL, and some people love to hate GraphQL. So I'm a little curious as we get going. Can you just kinda give us the elevator pitch for GraphQL?
I know most people are probably at least somewhat familiar with what it is. But if we can start there, then we can start talking about why substitute this for REST or use it in conjunction with REST or what the trade offs are or how to set it up or all that other stuff. But knowing what it is first is a good place to start. Yeah. Sure.
Let's try it out. So if you're using REST, probably could use to a concept of a resource that each kind of data you have is a resource and you have a list of actions you can perform on them. And you have these resting points that allow you to fetch the data you need. But the problem is that sometimes you need a different set of data for each platform, for instance, when you're working with your own website and your mobile application. And in this case, we have 2 problems which come from the same place.
The first one is under fetching, which means that when you fetch some data and you want to get the additional data about the additional, resource, you'd have to make another request. So sometimes you have to make a lot of requests to get the full page. Imagine that you're working on Facebook or something. You have a feed, a list of friends, all that stuff, and you have to make additional requests. Or you can, you know, have a special request that allows you to fetch all things you need, but it's also sounds wrong because when you have the mobile app, you don't need to load all your friends and the pit at the same time.
So you have, you know, separate APIs for the mobile application and your website. The second problem is over fetching. It's almost the same thing when you work on the mobile app and you get all these data for the website. You don't need you don't need, but you have to download it, process it, and, you know, use the network for that. So GraphQL tries to solve this problem.
You can you can get any data you want, but you don't get any additional data that you don't want to get. The special benefit you get from GraphQL is is the documentation because the heart of the GraphQL system is its schema. Schema defines your graph, so you have a list of entities which are called tag. And these types can have connections between each other, so you have all these connections described, and you know what, data can you get from each point. And in this case, you don't need to have the separate documentation because you already have it.
You just need to explain what does it mean in your system. For instance, what is user, what is customer, all that stuff. And that's that's it. You cannot have the outdated documentation because in this case, your GraphQL system just won't work at all. So I guess that's the main selling point for me.
And also one more thing, but not the last one, I guess. There is a special thing called subscriptions. Sometimes you don't want to get the data right now, but you want to get the updates. For instance, new messages in the chat or new notifications, all that stuff. And when you work with the rest, you have to build something from scratch, like, make the Ajax request, make polling, make sockets by yourself, all that stuff.
GraphQL solves this problem by subscriptions. In this case, you can describe the query you want to make and wait until the event happens. In this case, GraphQL would send the data to you, and you don't need to think about how it came to your client application because it doesn't really make any difference between the regular query or subscription call. And this is the part of the technologies, so you do not even need to care about how it works because it's usually a part of the library you think. That's the benefits of GraphQL I wanted to mention to keep it off.
I'm a little curious as we get going, John, Luke, and Dave. What all have you done with GraphQL? You mean other than avoid it? Or complain about it? Yeah.
No. I'm joking. So I think that GraphQL is really cool. From the perspective, like Dimitri was saying, it has a lot of benefits, especially to end users consuming the API where they can only really fetch the data that they need, not everything. Especially when you're talking about really large datasets and really complicated datasets, which maybe have a lot of associations associated with the main record that you were wanting to get back.
So having the ability to just make one API call to this back end application serving GraphQL is really nice opposed to having to make 10 different calls. So not only is that more efficient from the perspective of 1 verse 10 calls, but you also then have more ability to, let's say, pull it often, especially if the back end has some kind of rate limiter. And in order to serve this one page or this one application, you had to make 15, 20 simultaneous requests to get all that data. Well, if you're doing any kind of rack attack or rate limiting, then you were consuming 20 times for just one page view. So, you know, it definitely has some benefits from that perspective.
But now here's my big buts. Despite all of those glorious benefits, I think if I am developing a API back end that's going to be consumed by an internal or an iOS or Android application that I'm publishing to the store or by another in house product or by a third party who is very comfortable with working with REST APIs, I'm gonna go with REST API every day. But if I am going to create a API that I'm expecting all of my customers or users of the application to heavily write their own interfaces to everything, I'm just really providing a data source in a formatted way, then GraphQL might make a bit more sense. I can totally agree with, Dave, and there is no reason to just start rewriting all the application we have with GraphQL. And, also, if you have a client that wants to work with the rest and if it's still comfortable to work with the rest, that's completely fine, I guess.
But sometimes it makes sense to start new projects with the GraphQL even if you don't have any experience with it at all because sometimes you can find benefits. And by the way, there is a special trick in GraphQL, which I also avoid all these different small requests, which is called batching. I guess all modern front and GraphQL frameworks can do that. Batching is a thing that doesn't immediately immediately makes your it just builds a list of requests and send that them once, let's say, once a second or something. It helps a lot when you have to render a lot of things on the same page, at least in the initial lot.
Yeah. I don't disagree with Dave at all. I I think for whatever reason, maybe this has always gone on, but I feel like the last few years, there's been a lot of, hey, sweet new tech comes out. Like, I have this new hammer and everything is a nail. And I feel like GraphQL totally was a thing like that where everyone was using GraphQL for everything even when I couldn't find any of the benefits of GraphQL lining up with their problems.
Right? Like, it was like everyone using Mongo to try and replicate relational databases, which Mongo is not good at. You know? That's my only beef. I think that GraphQL is awesome.
To be frank, I've even said before, and I still think it's probably true. So REST is kind of like a standard. Right? GraphQL is a technology. And I think that distinction to me is important because if we can create a standard on top of GraphQL that looks a little bit more like REST, I think that we'll in my opinion, I think it's likely that we'll see that GraphQL is a lot more powerful than it looks right now.
Because to me, it looks very wild westy. It's like you have this cool new technology, and everyone's all over the place with it. And so it's just a gigantic mess, and everyone's blaming the technology instead of blaming the discipline of the people that are using the technology. That to me appears to be the source of most of the problems. I've only used it on toy apps so far.
I haven't actually had a real problem in my life that made sense to match it up with GraphQL yet, but I still think it's sweet. It changes the way that I think about things at the very least. Luke, have you done anything with GraphQL? No. I interviewed for a position with a company that made white label white label apps, and they were heavily this is in the UK.
They were heavily, heavily into GraphQL. And I I was talking to CTO and I asked him why? Because, again, they were a rail shop. Why they kind of put everything into GraphQL? And they were very mobile focused, and they felt that one of the benefits from using GraphQL was a kind of huge benefit on mobile, especially with more efficient network usage.
So for them, any amount of complexity was worth the trade off to get their apps running more responsive. So the fact it was a kind of a newer technology, they didn't care. They just wanted that improved customer experience. So I'm really interested to hear what Dimitry is saying. What you're saying, this is not just about efficiency.
This is actually a better way of organizing the interface between the client and and the server. And I think you said something like having a schema was one of the big wins, which you don't get with a REST based app. So it was interesting to to hear what why is didn't didn't schemers go away with XML? That was the last time I had to deal with schemas. Are schemas good now?
Yeah. That's a good question, and I totally agree that it sounds like small schema. But, yeah, schemas are better now, I guess, and too young to understand all the pain with small schemes because I didn't work with them a lot. But, yeah, the schema language in GraphQL is very simple. It looks like JSON, just regular JSON.
You just define a type. You just call type user and define a list of fields like title, string, and I don't know. Orders is a list of order which where order is another type, for instance. And that's it. You define all that stuff with text.
And for instance, in Ruby, you don't even have to define this schema by yourself. You just define classes, and it makes all the magic behind the skins. You do you don't need to do anything at all. And then you can use this schema to send to your clients, for instance, some tools use schemas to have nice auto complete and validate the client request that they at least request the fields you have, for instance. And, also, you can use any documentation tool you want.
You just show show the place where you can find the schema, and it will show a beautiful screen with all the fields, connections, types, all that stuff. Yeah. Now speaking of the schema, I mean, this was the painful part, at least, when I've laid with GraphQL in Rails is that I wind up essentially fighting the engine a little bit because I have to set up that schema for every type in the system. It you know, at least and I haven't tried it for a year or so, so the tooling might have gotten better. But yeah.
So essentially, I had to tell it, you know, the user's name is a string and the user's username is a string and the user's, you know, this, that, and the other is a number. And, you know, in Rails, if you're doing REST, it just kind of all works. You know? And I didn't have to do any extra work to get that kind of an endpoint up within GraphQL. So, yeah, that that's my major beef with it.
It's just that it created a whole bunch of work on the back end that I wouldn't have had to do if I was doing REST. I may argue you had to do that on the front end. Right? Because you got all that through JSON. It was all string, and then you had to decide, well, what is this?
Is this a number? Should I be parsing in? You know? Or is this actually a string, or is it something else? If it was objects, you were cool.
But, otherwise, yeah, you had to play with it there. Yes and no. I mean, I agree with you, and I don't. One thing that JavaScript has going for it is coercion, and so it winds up doing a lot of the you know, it it winds up doing a lot of the work for you on that front. Right?
And so unless you need, like, some very specific functionality out of it, you can just count on, you know, JavaScript doing the right thing when you do a course of comparison or things like that. And so, yeah, I don't do a lot of typecasting in JavaScript. So for the most part, that doesn't matter as much to me. Yeah. I I don't wanna pretend like I had to do it all the time, but it was a thing that I did have to care about more often than I wanted to.
Probably at least a few times a year, I was dealing with something where I was doing a comparison or something. And, you know, for whatever reason, something that came from data was still a string, and I had to fix that. And, also, when you work with plain rails and you want to set up some kind of documentation, for instance, swagger, you have to write all these comments near your actions by hand, and there is a chance that you'll forget to change anything. And your swagger will be outdated, and no one will not. And when you have schemas, there is no chance that it will be outdated because it's your schema that's used for executing your code.
So going down the schema route a little bit more, I used to use SOAP back in the day, and, I mean, I don't miss it at all. This is me crying for you. I don't miss it at all, but this isn't my first rodeo with schemas. Sorry. I guess Alexa thinks I'm talking to her because I said soap.
I don't know. Whatever. Anyway, I used to do soap back in the day, and I I mean, there's some benefits that you get with schemas, which I think is kind of what you're talking about here. For me, the main thing that I always felt like with schemas is I could pull information from a completely new source. But I I know that you're not doing this all the time, but I could I could know nothing about what was going on underneath, but I knew everything that I was allowed to do.
That's a lot harder to do with, you know, restful APIs as, you know, we we don't really provide that kind of thing. It's not impossible to do. I guess you could provide a page that does that or something, but nobody it's not a standard by any means. But I guess why for me, I can see benefits to it, and I feel like people are happy with the exchange when they're doing GraphQL. Can you talk more about, like, why the schema in this case is a good thing as opposed to, like, so where I always felt and Charles is actually just Chuck just expressed this a few minutes ago.
He's like, why hate that in rails, I had to, like, do all this setup, like, every time. Right? Like, we really hate writing boilerplate. That's why we write rails. Right?
So why is this exchange good, I guess? Like, what are we buying in exchange for it? Well, again, the problem is that in GraphQL world world, they prefer things to be explicit. So they want you to define the list of fields you want to fetch, the list of fields you allow to fetch, all that stuff. And it could be possible to just generate the list of fields based on your table structure.
That's not impossible. I believe there is even a gem for that. But there is a huge benefit from having a schema when you want to change your data. In GraphQL world, it's called mutations. Mutation is a special query that can change your data, and it looks like a regular query, but it usually expected to change the data on the back end side.
And the thing is that when you define arguments, for instance, you want to change the price of the item for your Internet store and you want this price to be number and you want it to be required, you can be sure that it will be present in the parameters because otherwise, GraphQL execution engine will just send the error to the client telling him that he's wrong. So from day 1 point of view, you add some boilerplate code. But from the other hand, you just remove the part when you validate the data because you can ask your execution engine to make it to make all the checks we want for you. I think that's a fair exchange. So is the big bonus then on the writing side?
Is that what we're saying? Yeah. That's one of the benefits of hearing schema because you can make sure that things that you expect will arrive in a way that you described in your schema. Yeah. It's been a year since I've really touched GraphQL.
But back when I did, one of the biggest issues that I had with it is that my code wasn't pretty. It it seemed like GraphQL complicated it beyond what a REST API would do. And from that perspective, I just found it easier and more maintainable to stick with REST API despite some of the benefits that GraphQL provided. Now I know that with I believe Facebook created the concept of GraphQL or created GraphQL. And what they were dealing with, I'm sure, is a lot worse than what GraphQL provides.
But I think with what Rails provides just out of the box or with just 1 or 2 serializer gems, then you have a much cleaner look without the GraphQL and just stick with the rest. So if I understood correctly, you mean that you don't like the code you write when you are writing in GraphQL, you know, Ruby. Right? Yeah. Basically.
Yeah. I guess it's a much taste, and I can agree that writing a list of fields each time we add in your entity can be not that great as an developer experience. Well, it it wasn't just that for me. It was writing the fields and then writing the resolvers for all the extra stuff. I mean, it felt like it added a ton of work that I wouldn't have to do if I was doing REST.
Yeah. I think the gem that was really popular a year or so ago for GraphQL had a very strange DSL that they use. Or at least it just seemed like it was overcomplicated. But that was probably just due to the necessities of what was required by GraphQL. I'm gonna ask some really dumb questions here, so stand by.
Alright? What is running the GraphQL? I've looked at it, and I don't quite understand. I understand the process. You you you put your schema, Kevin.
You write some supporting code. Yep. Is the GraphQL query hitting it can't hit rails directly, can it? It's going through something. Is it hitting a node server running on the server?
No. GraphQL is basically just a as John mentioned, a technology. So you're not having to parse it through another service per se or external service. It's just you have a standard of what the GraphQL should be structured as as it's consumed and how you are posting back to it for mutable changes and requests and stuff. But it's not actually going through external service or anything.
It could, but your rails server can also be your GraphQL server. Yeah. It just translates it down into calls through your model just like anything else. It's kinda like you could pick Puma or you could run Apache or Nginx. Whatever you want can be your web server.
You just have to adhere to certain things in order to be that. Oh, that this is my my weird bit, one of my weird bits for this week. So I've been working on I noticed that GraphQL has got a kind of subscription service you mentioned, which is looks like a kind of WebSockets based live updates. I've been trying to make my own without using WebSockets using a long polling. And I was using Fin because it's quite easy to use Fin to do asynchronous stuff using event machine.
But, Fin appears to be missing, presumed dead, and everyone's using Puma now. Right? They're getting nods here. So event machine Yeah. I guess people can't hear my nods.
Yes. Yeah. Yeah. It is an absolute agreement. So I've been trying to get it you working using, the rack hijack, yeah, which is a kind of way of keeping a connection open with PUMA.
My word. That is a total nightmare. I can't tell you how long. I mean, it was took me to about 2 or 2 AM to 6 AM to get a hijack working. Now my web server stack is NGINX into passenger, into Puma, into my app.
Is is this is this excessive, do you think, to run to run all of those for one web request? So this is not GraphQL, but, yeah, I a 100% agree with Dave. I actually reverse proxy to Puma in almost all of my setups, but I don't use NGINX plus passenger and then also add Puma on top. You wouldn't believe how long it took me to get it working. But now that I have got it working, I quite like it.
And it kind of it feels like I've got a bit of a gang on the server instead of kind of lonely process serving web pages. You like it until there is a problem in production. Then you'll rip all that out. Why I like passenger. If I'm in production, passenger tells me, like, help, you know, I just run the passenger status, and it tells me what's going on.
And you don't you don't get that with the with the Puma. There's no kind of happy here's how what I'm doing Puma command. Yeah. So NGINX is gonna be your web server. That's gonna serve the HTTP content.
And then passenger, Puma, Unicorn are going to be your application service, which is essentially going to talk to the rails application, convert all that ERB slim or Hamill code over into HTML, and then give that to the web server to then serve to the client. I know it's off topic, but, you just need Passover and Puma. The reason I'm diverting here is because I've got my happy long polling set up, and that that works really well now apart from the huge huge stack of process that goes through. But now I've got that. I'm kind of looking at what I want to achieve is a site that sends state simultaneously to lots of different clients live.
So it's a production system. Maybe you've got 60 terminals. I and I want state changes to propagate automatically so so that with somebody at one terminal hits a button, the others can see that, yeah, in real time. So this is this is my motivation. So that would be if there was a slightly less arcane way of doing that using GraphQL, that would interest me, see, because my choices at the moment are roll my own WebSocket system, which I've done, but it feels a bit homebrew, or look at something which has already solved this problem, which is a bit more standard.
So in GraphQL, there is a subscription, special subscription type, which looks like query, and it can be run on different transports. As far as I remember, along with Action Cable supports some other paid services. So you set up your transport engine, and after that, your client, client application will just start using subscriptions as a regular request because in this case, it doesn't really matter where the data came from because the data has the same type. So for instance, if you have a list of notifications and you have a query to get all the all the, let's say, unmute notification for the current user, you get the list from the query. And then as soon as the new notification arrives, you get the new, notification from the subscription.
So it can be done with when actionable setup. So is this a thing that I can get out of the box really easily, or is this, thing that I have to set up? Right? So I have to go set up some action cable stuff, tie it in to whichever GraphQL gem I'm using, or maybe I'm using Graffiti, which we talked about recently, whatever, but I haven't tried yet. Is this a thing that's, like, easy to set up with some out of the box Rails gems that are easy to find?
Or is this a thing that I'm gonna have to go read 3 tutorials and kind of fumble my way through it? Let's say it's not super hard to set it up. Fortunately, I have a tutorial how to set up subscriptions and all the stuff you need to start your GraphQL application. And, yes, that's a part of the standard jam. The only thing you have to change if you're using any cable have you heard about any cable, by the way?
So in this case, you'll have to set up one more additional jam and it will work. Okay. Sweet. So one thing that I'm wondering about is yeah. You know, we we've talked a bit about the boiler plate that has to be written.
So is there a generator or something that I can run that will take care of a lot of that stuff for me? There are dashboard generator in the GraphQL will be a gem that will create all the stuff you need to start, all the base types, controller, add a new role. So, yeah, after that, you'll have very simple schema with one type, I guess. Just trying to track, what is the gem that's kind of been around for, like, I don't know, I wanna say, like, 3 or 4 years for Ruby stuff? Is it GraphQL Ruby, or is it a different one?
It's a GraphQL Ruby. Some you guys mentioned that there was a strange syntax. I guess you worked with the previous version with blocks. Look like JavaScript. Right?
A lot of braces. Yeah. That's very possible. So some time ago, they computer rewritten the API and just use classes as all other Ruby gems do. Yeah.
As long as I can write clean, maintainable code, then I think GraphQL, you know, is viable in a Rails application. But as John said at the beginning, it's not a hammer that will fit every nail. You have to use it when it's appropriate, not just because it's what you're familiar with or because it's the latest and greatest. If it's the right tool for the job, then absolutely use it. Yeah.
I think for me, like, the issue is trying to understand a sort of nuance view of when is the right time to use it. I think my understanding thus far from a very simple standpoint is is very similar to what you said earlier, Dave. If I have control of the client, right, so I can write it myself, and I have resources that very easily fit sort of the rest kind of framework, then I don't really have a lot of motivation right now to diverge from that and go to GraphQL. But if if I start to leave that, if I start to look like Facebook where I need to know about, you know, person x and a whole bunch of stuff about person x's friends. That's where I feel like I start to go down the road, where GraphQL is good.
And so I don't know if any of you guys or Dimitry, if you guys have, like, a more nuanced view of of where you're, like, oh, here's the line in the sand when you might wanna consider that. But I I don't have a very good line at all. Well, as I mentioned before, when you have more than one client or there is a chance that you'll have more than one client in the near future, that might be it, the baseline. You can start using GraphQL because in this case, you won't worry about what data would be needed on each platform. Yeah.
Yeah. That makes sense. I mean, the way that I'm kind of envisioning it is, say, I build a Dragon Ruby or a React Native or something, you know, build an app with those. And I'm actually looking at some of this stuff for some of my personal things. Right?
So I could build a front end off of the GraphQL, you know, in React or Vue or Angular or, you you know, have some kind of tie ins with stimulus or something depending on how I wanted to structure the front end of the web app. But then the mobile app, I'm finding more and more people want to interact with apps on their phones. Right? And so, you know, I may have slightly different interface or slightly different needs on a mobile interface on the web, or I may offer an app, you know, like we said before written in GraphQL or something and or sorry, in React Native. And so if I'm doing that, then having having that option available as well also works.
One thing that I'm wondering about though is the authentication flow and, like, permissions and security and things like that. Right? So one thing that I'm working on right now is I'm trying to pull together, like, basically a dashboard for the podcasts that essentially, you know, I can say, okay. You guys are all hosts on Ruby Rogues. And so, you know, here are all the upcoming episodes.
Here's all the prep information. Right? So instead of it going through Zapier and Google Docs, which is what we're doing right now, you know, it just pops up a notification on your device and says, hey. You've got you've got this new thing. You know, come check it out, come prep, whatever, you know, and stuff like that.
But I'd like to be able to manage all that stuff on my phone. And so I'm not sure how to set things up so the the device can actually, you know, authenticate. So they go to the login screen in React Native, and it sends the login information over the wire to GraphQL. Do I do my authentication through GraphQL, or do I do it through a device rest endpoint and then just kind of pass around a JavaScript web token? Or how how do you manage all that stuff?
The fun thing is that when you try to find this out in the documentation, they say that we don't care about the authentication. Just do it as you do it usual. In this case, yes, you'll have to set up something, token or device endpoint or something else. And in this case, when you do some old stuff, you don't have any shows. You have to use rest because when you get the combo from, let's say, Facebook, you'll have to set up this REST in point.
But then when you have the token, you just put it somewhere into header, into cookies as usual, and perform the authentication on the rails level, on the REST level because GraphQL claims that it's transport diagnostic, and they don't care about the protocol they use. They do care about the protocol they use. So I would put my token, say, in the header or something like that, and then is there some level of checking that I can do before it executes a query? Yeah. So let's briefly talk about how GraphQL request is processed in Rails.
So there will be after you run that generator we discussed before, there will be a special road called GraphQL. It will be post because sometimes queries big enough to not fit into get requests. So there will be a post into a special controller, which is called GraphQL control with a single action called execute, and these internal action contains a single call to GraphQL schema. There is an object called GraphQL schema with the execute method. You pass your query, your variables that came from the client, and then you can pass a context.
And context is just an object, a hash, which can contain anything you want. And in our case, it will contain current user object. So you can authenticate user, make decision about his permissions, and put it into the context. And this current user in the context will be available everywhere inside your GraphQL tabs, resolvers, all that stuff. So it's pretty similar to just regular application control.
We we all write every day. You also mentioned some optimization questions. Is this the n plus one for the optimization? I'm sorry. I forgot.
Did you freeze? Yeah. I guess. People do that a lot when I ask them questions. I think it might be me.
Yeah. So the question was about m plus 1 optimization. There is a big problem in GraphQL with m plus 1 because sometimes you get a request to fetch some entity and a list of entities inside of this entity. And if you miss something, there is a chance that you won't make a join in your database, and you will have a lot of small database calls. Just a classical m plus one problem, but it's a little bit different in GraphQL work because, there is a chance that you will make a ton of small requests during the one graphical request.
And there are, a lot of solutions to this problem. So the most simple and naive approach is to just log everything you need. When your application is small enough, you can just, you know, list all the possible associations on the top level in your query type, and they will be loaded. Sometimes it works because some applications are small enough. And also there is no alternative solution.
I have a gem called active record lazy rollout. It works in exact same way, but it doesn't really, load everything you listed right now. It loads it as soon as someone tries to access the association. In this case, you can list everything you need, but it won't make a lot of requests on the request that you need to make. But, of course, it doesn't really work on the huge applications, so there is a different solution.
The solution is called lookahead, and it's a part of GraphQL Ruby gem. The idea is that you always can ask the execution engine if it wants to fetch a specific field on anywhere we want. So for instance, when you're resolving a user who can have orders, you can ask, hey. Are we going to load orders right now? And if it says that you are going to load orders, it, you can make a special request to database to avoid and respond.
And the last, the most complex solution, but it works in huge applications, is called GraphQL batch. It's a gem by Shopify. The idea is that they use laser resolving. They stop resolving your field as soon as it understands that you're going to have a possible n plus one. It collects all the IDs that it wants to load and then makes a single request for all the entities you want to load and then just puts the data into the slots, let's say.
So I think n plus one problem is solvable in this case. So another thing we have on our list of discussion points is caching. So does I guess, where does that caching occur? Because if you can kind of request anything with GraphQL, then I'm assuming that it happens at a lower level where it caches the fields or the result that it gets somehow and then builds the response from there? Yeah.
There are a lot of problem with caching. So first of all, as I mentioned, GraphQL requests are usually post requests, and it's impossible to use HP cache with bots. And there is a solution for that. There is a special technique called GraphQL persisted queries. The idea is that when you send a request to the server from the client, sometimes you know that you are going to send this request more and more, the same one.
And in this case, you can just send a fingerprint of this request. There is a special way to calculate this fingerprint that is known by server and client. In this case, you can send the fingerprint and server knows what it wants to return. And if it doesn't know what query you want to make it or respond that it doesn't know about the query and does the full version. When you use this technique, you can use get requests because there is no chance that you will send this huge query using using get.
In this case, you can use if you if you want. As far as I remember, it's possible to do it using GraphQL Ruby, but only in pro version. So I've written my own gem for that. That's interesting. So, essentially, what you're saying is that, yeah, you can create a fingerprint for the query that you made, and then you can make a get request and take advantage of the HTTP caching anyway as long as you're making the exact same query.
Yeah. Because of the variables, you usually make the same request from not only a single client, but from all the clients for the same version. So most of the time, you have cache hit. Then does it invalidate the cached responses if some data changes? Like, does it keep track of it the same way that Rails does for other caching?
So in this case, we don't really care about the invalidation because we cache only query itself, so the text of the query. And HTTP caching has to be invalidated by Rails. So manually, there is no solution. I tried to implement something but stopped and figured out that we need to use a different solution. There is an idea that we can cache GraphQL responses.
From the first perspective, it seems like it's impossible because each time client makes a request, it can ask for any data we want, but it's possible to cache the part of the query that you don't want to resolve each time. For instance, when you have the ecommerce set and you have a list of popular items, you probably want to show the same list of popular items to to everyone, and you don't want to go to the database to fetch them. That's why we created a special gem for that called GraphQL fragmentation. It was extracted from one of Ilya Martians projects, initially implemented by Vladimir Dimantev and Nikolai Swytkov. The idea was that we want to remember the part of the response.
And when a client wants to get the same thing, we just take the part of JSON from the cache, from Redis, or somewhere else and just send it to the client without resolving it. Unfortunately, it wasn't possible to do it in GraphQL Ruby because there were no mechanism to stop execution, so I had to make a pull request to add this mechanism. So right now, it's possible to use this thing even if if you are not using the gem. But when you use the gem, you can specify the cache key. It will be built by the gem.
And, of course, you can always invalidate this cache if you want, and also can also specify time to it. That seems super useful. Alright. So is there anything else, Dimitry, that that you feel like maybe we should be doing with GraphQL that's sort of not common practice? Like, is there a best practice that we've sort of missed or anything along those lines that we just haven't gotten to today?
Yeah. I think we could talk about some best practices. Some of them, sound similar to things we do in REST, but a little bit different because it's a different technology. So there are some possible security issues that can happen with you when you are using GraphQL. So as we mentioned before, it's possible to ask everything you want, but there is a chance that your client will make a request that will just blow up your database because it will be a huge select with a lot of giants.
And there is a solution for that. As far as I remember, it's not a part of the specification, but most of the libraries have this built in. The idea is that they calculate the depth of the query, and the complexity depth is amount of entities you touch when you go down the graph. And complexity is a complex metric that includes amount of fields, your request, dev, and so on. And you can limit these to variables, on your execution engine.
In this case, when someone tries to make a huge request that you know that won't be made by your by your real clients, it will just ask the client to make a simpler one. I guess we didn't face such problems with the rest. And, also, there is one more interesting thing. As we mentioned before, it's possible to expose your schema to have, let's say, public documentation. But, also, in this case, it's possible to see your to see your schema using GraphQL because there is a special thing called introspection.
You can make queries to see the schema. I'm not sure why it's dangerous, but some security specialists think that it's security problem, that we should hide introspection from public users because they don't really need to see it and use it only in development and maybe staging environments. So sometimes it makes sense to turn off introspection in intro their production environment. There is a special setting for that in graph. You can just turn it off, and it disappears forever.
It'll be impossible to ask for this data. I'm gonna change the topic unless there's more to the best practices. There is one small thing to mention. There are some best practices related to code, which will be hard to discuss without looking at code. Like, we shouldn't expose data from other entities, all that stuff.
So I have a small extension for that, which will help you to check your code. Of course, these rules have been added because it was created by me, but sometimes it might be helpful. Sounds good. How do you test your GraphQL? You just make a bunch of queries?
Is there a better way to do it? So it depends. There are two ways that I'm aware of. The first one is making queries. So you can just make a test for, like, GraphQL controller.
So you define your query, then call the controller and I mean, may make the request to to call your controller, and then you'll check the response if it matched to the data you expect or not. But when you write a lot of such tests, it sounds repetitive. So there are 2 ways that you can avoid it. The first one is to write a shared context in our spec. In this case, you'll have some kind of DSL that will handle things for you, or there is a different approach that I heard of.
There is a gem called Pixorama. The idea is that you put all the data you want to check to YAML files, define a single test, and just have a lot of folders with these YAML files, like what you ask for, what to expect, and it will just compare the result with the kind of data you expected to get. It sounds like it would be cool to test types directly, but but right now, it's impossible because of the GraphQL Ruby architecture. It's impossible to just create type object from scratch and ask it to serialize something for you because it's heavily relies on the execution engine. So right now, it's not possible, but maybe it will change in the future.
Did you what Chuck did or, Dave, you guys were complaining a little bit about it earlier. Did you guys do any testing with GraphQL when you did your implementation? It is this testing that you speak of. Test is a 4 letter word. Right?
Alright. Alright. No. I did tinker around with it, but I didn't dive into it too much. And it was really just simple mini tests.
Just make a request, expect this back. I got it back. I mean, it's really not too too different than doing other tests on a REST API. Yeah. Most of my testing was manual because I was more playing with it than actually trying to get something out of it.
But having spent time on some of the front end systems, I mean, that's where GraphQL is really, really nice, especially if you're using something like Apollo that just gives you a whole bunch of powerful features out of the box. Anything else? Any other, thoughts or advice? Nothing on the top of my head. The only thing I wanted to mention is that I'm surprised that no one asks about the performance because sometimes people think that it's so hard to parse these huge GraphQL requests and then respond to them and that GraphQL adds some overhead to your processing.
I tried to prove it and figured out that it's not that big problem. I have a benchmark that tests the, memory consumption by GraphQL. It will be compared with JSON API, which I mean, JSON API, standard that makes the similar thing that GraphQL does, and there is no significant difference between them. And, also, I tried to process really big query. Like, there were 8 fields, and each field had a nested an a nested entity with 8 fields and so on 4 times.
So this that was a really future request, and it took, like, one second to process, which is a big amount of time, but we usually don't make such requests. And that's why I do not recommend to you batching that I was mentioning before. And, also, after I published this benchmark, things became better because right now there is a new execution engine in inside GraphQL Ruby, so things are even faster now. So I can say that it doesn't really add any overhead to your system. Yeah.
We didn't bring up performance because Rails can't scale. So Yeah. It's cool. People that don't know how to use the tool can't make it work. I think that's normal.
Yeah. So instead, they reach for stuff like React. Oh, oh, I didn't I was just definitely not trying to react kinda worms. No. No.
It's fine. We we can all pity the Django devs. Anyway, any other thoughts or things that we wanna bring up before we go to pics? Yeah. Why can't we just send SQL over WebSockets?
I I think people do this probably somewhere. No. We're supposed to put everything in a c data tag. Right? Yeah.
There we go. Sweet. Yep. Alright. Let's do some pics.
Dave, why don't you start us with pics? Alright. So I recently got a Startek under desk computer mount to free up some desk space, and this thing is really cool. I mean, granted, I now hit the computer with my knee a bit, but having it off the desk is really nice. So that's my first pick.
And, surprisingly, my computer weighs, like, 35, almost £40, and it supports the weight nicely. Wow. And then the 2nd pick is Noctua Fence. So with the age of digital learning and 2 of my 3, soon to be 4 kids, we're expecting if you didn't know. Congratulations.
Thank you. Yeah. I I think after 3 kids, it's supposed to be condolences, but thank you anyways. I have 5. You're gonna name the next one Pearl?
No. I've been x nayed on any more developer programmer kid names. I already got Ruby, so that's that's a win. But with these computers that ended up building for them, I just went to my local microcenter and bought a whole bunch of parts. One thing I forgot to get was case fans.
It came with one case fan on the back for exhaust, but I didn't have any intakes. And so I had some spare RX 580 graphics cards and did some load testing and let the kids play some games, and that case got super hot. So I went out and, on Amazon ordered a couple of Noctua case fans, and those things are amazing. Not only are they quiet even when they ramp up, but it made a huge difference in the cooling of the PC case. So Noctua fans is my 2nd pick as well as just, like, case fans in general, having enough of them.
Congrats on your kid, by the way. And I'll also thumb up Noctua. I think they make pretty reasonably good fans. They're up to be really into of fans. Good.
I was gonna say something dumb, but I didn't. John, what are your picks? I feel like I should recommend, like, some Gentle Tai fans, which you can't, like, buy anymore or something like that. But they used to make these really cool fans that were, like, super silent, but they're, like, impossible to get and super expensive now. So this week, I just, like, want to to give some pretty much a shout out to let because I think that a lot of people are familiar with Sticker Mule?
Yes. Thank you. Just had the name, like, 5 minutes ago, and I just forgot it. Whatever. Anyway, best experience ever getting stickers every time.
I have gotten stickers from multiple places in the past. And then a few years ago, I switched and started using Sticker Mule. And I just got stickers again recently, and they're just so, like, flipping amazing to work with. And they let you freaking cut out your stickers in the shape of your sticker, which is exactly what I want. So they're awesome.
Just saying They're cool. They're cool. Doing icons or something. Yeah. Yeah.
They're great. I put them out in the sun. Rather, I do the bumper test. So I put a sticker on my bumper and see how it fares to the weather. I've had a bunch of stickers, which just faded over a course of 2 months.
Any sticker mule sticker I put on the back of my car has always lasted years years. Yeah. They're Nice. They're pretty awesome. And as far as pricing goes, like, I don't know.
I feel like they end up somehow man managing to be cheaper too than, like, if I were to get them from, like, Moo or something. So, yep. Also Mu doesn't do the weird shapes that I want. That's it. That's my pick.
Awesome. Yeah. I like sticker mule. They're awesome. Luke, what are your picks?
I've got one for fans. This is a, an, an ESC it's speed controller for a drone motor. You can get them for about 20, $30 an up. And this is controlled by a, the same PWM signal that your computer fans run off. And the voltage going in on this particular one will run off a 12 volt rail.
If you want to put it in your PC case, you can hook up the minus 12 and a 12 and run really quite insane ones of these. So if you want to make a really ridiculous computer fan, you can hook one of these up with a cheap drone motor and get them for again about $20 and put a carbon fiber propeller on it. And that will move the most amazing amount of air your PC has ever seen. It's really unsafe, obviously, because it's designed to lift it's designed to lift things, not to provide a gentle airflow. But if you want if you if you miss truly silent fans, that is a great way to get a totally silent fan.
I've I've I've used one in the past. It's really hot here. So I've used one for, as a like a desk fan. Obviously, cats, you know, is not safe around cats. How many of those does it take to lift up your computer case?
Oh, sure. So this particular model, you can get about 3 kilos of frost out of it if you really push it and, you get everything matched up. So if you Way too many to run off your power supply. Okay. If you, as long as you got a big enough panel, you can lift anything.
Right? It's kind of yeah. I don't know. So my pick for the week is not very dangerous computer fans. It is my server request stack, my much maligned NGINX passenger Puma stack, which I'm using.
And they that is my pick. You might not like it, but I picked it. And part of motivation for this was a post by the passenger blog, which talks about combating slow loris DDoS attacks by stacking up NGINX for faster impuger. And they they explain part of the motivation behind it. So that's my pic blog post by Fusion from tweeting like it's 2018.
Awesome. I'm gonna jump in here with a couple of picks myself. The first pick is I've been reading these books by Brent Weeks. The first book is called The Black Prism, and it's high fantasy. Really, really been enjoying these books.
I'm on book 4 right now. I can't remember what the name of the book is, so don't ask. But anyway, The Black Prism is the first book and I guess the the series is called the Lightbringer series. And anyway, I've been listening to it on Amazon. It's narrated by Simon Vance who's an awesome narrator.
So I'll put links in for the book, and I'll I'll drop my affiliate link for Audible because that's where I'm consuming it and really, really enjoying it. And, yeah, that's gonna be my pick for today. Dimitri, do you have some picks for us? Yeah. I just thought about the email I've got yesterday that this year, as usual, we'll have a Oktoberfest in October.
So that will be my pick, I guess. Awesome. And if people wanna connect with you online, do you have a blog or, GitHub or Twitter or whatever? Yeah. I will, send you a links to my GitHub and Twitter profile.
And also, I sometimes write articles in the eul Marshall blog, mostly about GraphQL and database stuff. Cool. Alright, folks. We'll wrap this one up. And until next time, Max out.
GraphQL Doesn't Need To Be Hell with Dmitry Tsepelev - RUBY 665
0:00
Playback Speed: