How to write a GraphQL server

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
how to write abroad kill server well first of all let's start from a little bit of history in 1999 we had rest were fielding a PhD thesis invented came up with an architectural style that was a big improvement over whatever we had before like soap and that kind of stuff so big improvement a lot of people liked it we use it for a number of years so we still use it and we're still going to be using it for a long time in 2005 well you know stuff started to happen around the fact that people started realized that the rest had some limitations so in particular I found that interesting that Microsoft invented something that's called OData something I didn't know myself but I just learned it was an attempt to try and solve what the limitations of rest and it was nice in its own way it's kind of weird if you look at it today compared to what's available out there but it's a it's nice to put it in context that people started to to look for better ways to do stuff and then Facebook invented internally what later on became graph QL and it's been invented between 2010 2012 depending on the class too but they started using it internally heavily and then eventually in September 2015 16 it was publicly released this is not even two years ago in already we have a huge adopt on which we see a huge adoption there have been two conferences about graph QL 1 in the US and one in Berlin which I attended and it was a really really nice conference so the graphical conference about 300 people all excited about this new technology many many people using it in production already so it was all about discussing best practices and stuff like that so it was really interesting and uh so basically we use rest for a long time then we realized that the could have been better I started looking for a solution somebody finally had a good idea started to build it and now it's spreading spreading really fast so let me show you who's using graph QL well Facebook obviously but also github so they used to have a public rest api and I don't now they don't have a rest api anymore they have a public graph QL API so that's a big that's a big one I think Pinterest Airbnb Tesco talking about big companies Walmart the New York Times Coursera into it so you name it if you go to graph kanakam you will see a huge list of other companies that use it and this is just to download the monthly download rate of a pull-up line which is a graphical client library and so the the area of this graph is the actual number of people using it and it is growing really really fast so let's start from rest in order to understand brafilius let's see what rest looks like and we know that we're had has this URLs to represent some resource some some resource and and the rail means something according to some the communication of our prior agreement and then we have we fire this request to the server we have an implementation that somehow calculates a JSON response value and so this is how it works and implementation is kind of opaque in the sense that rest doesn't mandate anything about how you doesn't dictate anything about how you were supposed to implement the server so it's only a contract between the shape of the URLs and the stuff you're going to get back as a rep as a JSON representation in a complete system or an API is made of many entry points made with different URLs and so the ID you know the whole set of these URLs make up for your API rest has some disadvantages though because first of all one specific entity is conceptually represented by one specific URL and so if you have a user you have one URL for that user and that doesn't that doesn't change if your requirements as a client are different so if you're if you're a web if your web application then you need a lot of information probably but if you're on a mobile or mobile device maybe you need less information and in that case you're going to overfit meaning that you're still going to hit the same entry point and what you're going to get a lot of information that you don't care this you don't care about so that's one problem one way to mitigate that problem is maybe split those entry points maybe you have user and user brief or something like that user short you know something that that contains less information but then you have a proliferation of entry points and so this is not this is not nice because of duplication logic duplication and also maybe a implementation duplication so it's not nice also if you go by the book and implement restful architectures then you may end up having a too much network traffic because first maybe you fetch the user and then you fed the sites for that user and then the projects for the user just to show up one page maybe not know your why so these are limitations of rest that Brasel solves very briefly because then i'm going to want to show you what graphically it looks like but graffia offers a way to to formally describe your your system with the pipe system so you have actual type system to describe your data and building on that you can every request can be different because you can ask exactly for what you want in the request and so you get exactly that and so you get predictable results so these are the advantages so as I mentioned before github is a new public rough ql api and so let's see what this looks like so if we go to this their site we're going to see we're going to see you know that this is another their website and and bigger and so they have in the central in the center part of the screen we see this tool is called graphical this is a tool that's common to most a certain graphical implementations and it's just a is a simple wrapper around the fact that the brass QL request is just a plain HTTP request but it's just a nice dress around it that provides some extra features so you start with a query and the graph QL schema is totally respectable so you know you know what you can query by just using the client like graphical and we're going to ask for a viewer again viewer is something that's really common to every graphical implementation so I just that's the only thing I know pretty much the rest I'm you know coming up as I go because I don't I don't quite know the github API but I see that there's an email here so if I fire this request now let's see what I get well I see I get my email address so this is this is this is me and just logged in and set myself so this makes sense they probably have ways to query the repository exactly oh there you go so I want to see the first 10 repositories but it's like this slightly smaller it's gonna be ok industry and then yeah for each repository well first of all before going into each report let's see what we can find oil total count yeah that's interesting so let's see how many repositories I have oh I have 36 repositories and actually I found it interesting that they show the total disk usage so now I know that I'm occupying 75 Meg's of get up space that's interesting so let's filter by privacy public so I have 25 public projects in my account now I can I can iterate over them forget about edges in node for a minute this is just a way to iterate over a collection Raphael and they're probably going to have a name yeah there you go I have an so yeah these are the first ten public repositories in my account and so if I want to see the next ten what I can do is show on the edge show the cursor and it gives me an opaque string that I can simply copy doesn't mean anything to me but it means something to deserve it and so I can say give me the first time repositories after this one so this is how I do pagination because now I have the next end and so yeah this is how you do pagination and this is a this is what graph here looks like you see it's a very it's very simple you specify something that looks like a days without the values and then you get back adjacent with the value with the value so and then you have embedded the documentation so if you go if you go here you'll see you will see you will see a documentation of what we just did so this is all stuff that comes for free in a way because it's embedded in the way you describe the system to begin with so it's a I think this beats the hell out of old tools that are available out there for rest for documentation because it's still separated I think implementation is separate from the documentation graphical it's it's the same it's in the same place so it's much easier to maintain so let's go back to the slides let me tell you why it's called graph QL so we have as an example we're clearing a user and then the size for that user and then the projects that belong to those sites and then maybe in our example maybe we have the concept of users that collaborate on that projects no so why not ask for them so yeah if we do that we see that there's not a tree anymore these boxes over here to the left they look more like a graph in fact because I'm getting a user it's the same type as the user is a user so I can always ask for the size of those users so why not even complicated and further the query so you see basically what I have on the left is a just a graph of my model the model of my API the the conceptual objects that I want to expose through my API and the graph fuel is simply a query language for that graph so on its you know it's like SQL for the web in a way so you have a model that represents your API entities and then graph UL is a way to query it and because it's a graph in the most generic sense then when you query a graphing visit a graph you get a tree out of it and that's your JSON so that's why it's called graph QL and actually that explains why that explains that edges in node terminology because the edges are the arrows and the nodes are the boxes and so that's a generic way to it's not part of the graphical specification but most implementations decide to to use it because it's compatible with relay anyway let's see how graph QL works and how you implement it internally so if that is on the left is our query the way we implement a server is by using a concept of resolvers a resolver is a function that basically returns information that can be they can be intersected so for example in this case I must have a user resultant because that's the function that ultimately returns something that contains the first name and last name email whatever have you so I've got to have a function that's being called for the user and then because this user has several sites I'm going to have to have a cypress over as well which is going to be called once for each site and because we also have projects belonging to the site then we also need to have project resolvers which are going to be called once for each project and then in this example we also have a user result being called again so this is how it works and if you compare this n each one of these results the resolver said it returns something that is ultimately used to create a JSON response so if you compare this with the black box of rest you see already that the graphical specification is much more rest was an architectural style so it wasn't it was definitely not telling you how the implementer server it was just telling you what the server should behave from the external point of view graph QL is still specification it's not a library on its own there are there are several libraries in several languages that implement graph fuel but it's ultimately a specification but it's a specification it goes into much more details about how to implement your server specifically it mandates the existence of these resolvers with all the functions and so this is how it works and when you see this you may think oh my god I have the n plus 1 problem that is I am calling these functions way too often like like a bed or M right you end up hitting the database it's one of those resolvers needs to hit the database for example I'm going to hit the database every time for every entity my my model and so this is going to be too inefficient the complexity is basically a linear in the size of the response which is not very nice so just to assure you this is the very first concern that everyone approaching the broad feel for the first time and raises and there is a solution to that we'll see that in a minute so but first let me show you how to write actual code for for graph QL we're going to be using this launchpad tool which is really cool it was announced in Berlin at the graphical conference and we're going to be working on an exercise that makes use of words we're going to represent a simple dictionary with the key text and then a words are made of characters and we're going to represent the character with the dictionary with a key value and so let me click over here and show you what a launch pad looks like first of all you have a screen that split in half on the right hand side you will recognize graphical and it's a it's working so you can you can that you can query your server and on the left hand side you have the server implementation so this is beautiful tool because it runs in your browser but what you're writing here is node.js code actually running on an obvious instance in the cloud so nn executing in real time for change this ello world it's going to update the right hand side in real time and allowed me to theory again and see the updated result see so this is really cool so when you first when start for the first time you're going to have like I just did you're going to have a lot of comments over here that explain you how to get started and then you're going to have a bunch of boilerplate down here like make executable schema you don't need to understand this right now what you need to understand is this so basically up here we have the type definitions this is a string and it's it's language defined by the graphical specification and now here you have the resolve of the functions we just talked about so let's make our available so my query is something that you need to have that's you know a rule type you have to have it in our example we're going to have we can make something that code word that returns a word and but to make our example simpler let's just pass the content of the word is a mandatory strain so strain with an exclamation mark means that it's mandatory then we need to define the type word so word is something in a type that has a property that's called text let's returns the string that's my name string so this this is already a good start so let's implement the result this so if you look at it resolver this is how we should look like so if you think about Java this but is the funk is a functional prototype so it's it's you're telling the system that there's going to be a function called it's going to be a function in the class query this is the class this is the method these are the parameters to the method and then this is the type of return value so this is what it looks like and this is the implementation so this is the method again and these are the parameters this is self this depending on the language you're used to you know it's the instance a reference to the to the actual instance and context is so args are the arguments up here is collected in dictionary and context is something you can provide down here at the bottom something that's available to every resolver so you can put like your database pool there for example if you want to access the database or anything else you need so this is what how it works so let's make the resolver forward and we said this is the return value is supposed to be Ward and we just decided that the format is going to be another dictionary with with text in it and which groin which is going to contain rx content so this is how we return out a word from this resolver and then we need to implement the resolvers for the type word and we're going to have one resolver text which is going to take a word and it's going to return a string so word that text so this is ours over and it should be already working so we see that the skin is already introspect about we have word here and so it's it already knows that it takes a parameter content and then I will be in full and then we can ask for the text and if you run this there we go we have our word so now with the word we can do for example ask for the characters vectors which is going to be a list of character so a list the type lista is defined by the square brackets and so now we need to define the type character and the type character is going to have a game text of type string and so there we go let's implement the characters resolver it takes a word and it's going to return a list word of text that's split we're going to make a list of of characters we're going to create a new list bathing on the old one where it's element is going to be a dictionary with value it will talk this is what we defined was the we decided whether it was the representation of for a character and then we need to define the resolvers for the type character we're only going to have one takes a character and returns we said we returns a string that is the value after that value so this is how it works and let's see so we can have characters yes and for each one of those characters we're going to ask for the text and there we go now we have our food and this is and then we can play with this you know like for example for it with a character for a character we can ask like a sample word why not a word that starts with that character and then we can implement this resolver over here in the character type that given a character returns a word so it's going to be something like this and let's say if character dot value equals F then for example we can return a word like fantastic otherwise well Buddhists return null which is perfectly fine because we don't know other words so this and if we run this sample word and we're going to ask for the text yeah we get fantastic now let's let let's imagine that for example instead of returning aside we have an error so we throw a new error oh now this is going you see this is not going to break we're still going to get our response nice and clear but with the sample word that's the one that breaks that we're going to get a null instead but also in addition to that we're going to get another level result another information is called errors it's list of all the errors they happen and so this is a nice way to gracefully degrade in the case of errors of course you don't want to have this in production you know in the end but it's nice for development it's not going to totally break your code if you have exceptions so this is how it works and you can see how this is really flexible the nice thing about this tool Launchpad is that you can actually download what we just did and it was going to bundle it up as a zip file that you can unzip in your system and then it's going to be an obvious application just npm install and you can run it already so what I what a nice way to get started let's go back to the to the slide so let's see what we just did this is what we on the left-hand side you see what we did so basically we type the definitions with this language of type definition language and then we implement the resolvers if you've noticed in the boilerplate there was a function a call that was called make executable schema that was basically taking the type definitions adding them to the resolvers and then making up something that looks like the stuff on the right so you can still programmatically implement a define your schema and you can actually choose which would style you want to use you can you can generate you can generate the other side so it's really a choice that's up to you if you're working in JavaScript if you work in other languages you may your choice may be reduced but maybe one of these two style so only but it really are equivalent it's just different way to specify and maybe you you will find one nicer than the other depending on your situation so let's now talk about the n plus one problem how to solve it you ultimately solve it in different ways depending on your language and depending on the actual implementation of your rest of your graph QL server but I think the the way that's being solved in JavaScript is pretty interesting and it's worth discussing a little bit so you know first of all what is the n plus one problem well we said you know you have a user and you need to select the site for that user and so that's a query to the database that comes back with the say three sites then for each one of these sites you have the fire I request another who gets to the database to find the the projects and so you get a bunch of projects for site one another request a bunch of projects for site to another query and so on and so forth so you see that this is one query and these are n queries so that's quite this why it's called n plus one problem it's a problem because you don't want to go to the database so often so many times so how do you solve it well let's let's go to the code now for a minute to see to see how it's been solved in that in in JavaScript so let's say we have a calculation that takes a value and returns on computed value and we have a function that calls that calculation given a parameter and then we have we call a couple of times and we print out the result this you know the output would be two and four of course now let's say that we want to make now the F function asynchronous by introducing a promise so this is how we need to do to do it so we're going to create a new promise and then we're going to call the complex calculation and then resolve the promise and of course the way we do the console.log is different because we have to use then the outputs are still going to be the same two and four now the bigger step is the following so let's say we want to add a way to so a promise is a way to defer the calculation of something at an arbitrary point in the future so this is nice because it allows us if we want to to collect the parameters to those functions and call them at a later time and call it complex calculation at a later time so let's say we want to do that and let's introduce at line 1 an array of collected calls and then in line 17 instead of calling calculation right away we just push to that away the parameter together with the result function and then we're going to call it 19 a process hold pending function we find at 7 that's simply printing the number of values that have been collected and then going through each one of them call the complex calculation and there is all the the the promise and of course clear out the the array so if we do that we're still going to have a complex calculation called twice and also process or pending called twice right but every time we call it we're only going to find one value in the array because we're pushing a value processing the array calling calculation on that value and then clearing your a and then do it again for the second time so so far so good and not very useful to be honest but now there's the last step which is the critical one we're going to introduce this little code is called the process next stick so this is a way in nosiest say that this function is going to be needs to be called later on when the event loop comes back after after it's done with whatever is doing right now so if we do this we're basically going to have the those two parameters pushed into the collected closer way before both of them pushed before the actual first process or pending call happens we're still going to call process or pending twice but we're going to call them after we've collected all the D parameters so the output is going to look like this so the first time we call process or pending we're going to find two values and a second time of course is going to be NT because with amplitude and nothing that no one else has added more values the output result is still going to be two four so we haven't changed the semantics of this code but we have introduced a some delay well some logical delay it this is not going to be slower in executing it's only going to be processing things in a slightly different order so that we now have the opportunity to know all the collected parameters when we are about to calculate the call the complex calculation so in this case the complex calculation is you know not very complex but in real life but in real life you know we probably want to go to the database or some somewhere as expensive if not more so if we need to go and fetch the site for site and when the feticide to one now I mean 93 and then fetch Saida it and then set side ID 24 this is bad because we go to the database three times wouldn't it be better to to go to the database only one only once and leverage the in operator that's much more efficient because we can leverage an index and scan the table only once and this is exactly what this trick it allows us to do it allows us to know all of the accumulator parameters and allows us to fire a request to the database in a much more in a much smarter way so this is called back Singha and the library that implements this trick is called data loader and in real life you don't have to write code just like I showed you before but the library takes care of this for you but you have to understand what's going on under the hood otherwise it seems like too much magic in really in reality is not magic at all it's just uh it's just leveraging the fact that the nodes es is asynchronous and there's an event loop that allows you to do passing day in a smart way so now if we look at the n plus one problem it's solved because we you know we get the sites from the user with one request that's like before but now we know all the ideas of those sites and so we can go to the database only once to get all the projects we need with all the IDs to the other side and of course we have to do it this in a smart way so that out of those out of that big list of projects we know which ones belong to site one which one belongs to sites two and and so forth but now this is one query and this is one query and basically we've reduced the complexity of the of the implementation from roughly speaking very roughly speaking from an order of n to an order of log and so basically instead of going to the database once for each entity in our response we'll go to the database once for each level of the tree which is much better order complexity so this is it and I basically talked about how to write roughly well on the server how temple and graph field on the server a totally different talk would be to how how do you use what field on the client because on the client you might as well as I said rough field query is just a regular HTTP request so you might as well just go ahead and do however you do with Ajax with with the rest by using an ethics call and you know fire an HTTP request that way and that's actually a nice way to get started and migrate maybe an existing legacy system from rest or to grass trail but after a while you should realize that it's nice to use what's called a client library so Apollo and relay are two graphical client libraries and those are JavaScript libraries that take care of stuff like a bath stuff like caching on the client side you know build building the query for you in such a way that you can describe the data requirements in a very nice and compact way really close to the UI components so it's really cool eventually you want to look into that definitely data loader is the library that we just I just explained it internals to solve the n plus one problem so here's a little extra information bathing on the questions that I normally get after this talk one important chapter that I was about to forget to talk about is authentication and authorization here's how it works so you have your HTTP request that comes into your system you're still going to need a regular entry point controller in your in your framework in your server to deal with the slash graphical entry point you're not going to have as many entry points as a regular REST API but you're still going to need at least graph QL entry point and so in this control you review a lot of things most importantly you do authentication so you know your user profile and based on that you can take important decisions like for example global authorization for example you can decide at a given a user profile a given type of user doesn't have access to slash graph you at all and and so you can you can already deny that with a for for something like that and then you can also do a schema choice for example this is a nice way to differentiate regular users from administrator users they can be serve different schemas all together so that regular users don't even see what other administrators can do because they have a different schema and and then most importantly this entry point controller is responsible for creating the context of the actual and resolvers so the context is then passed to the schema resolvers and the context really is just a you know a box where you can put everything that's relevant to the or resolvers but definitely you want to have your user profile so that resolvers know how to take decisions bathing on that and then you can put definitely your connection pool to your database so you're observers can query data from the database or handles to your external services so again for resolvers to do their job and then finally the resolver is finally kicking in and in each resolver you can take advantage of the information you have in the context and so for example you can do fine granular fine-grained authorization so you can decide that a keeping user doesn't have access to a specific attribute and and so you're still going to see that that attribute is available there but it's going to get a no and then if the user instead is authorized then you can actually perform the situation of that attribute resolver and so this is how you deal with the authentication and authorization you have two different levels more granular you know fine-grain and more course in granular Grandon Ivan so the other topic is the other thing is that you know a slide I should have shown earlier on so basically what I've talked about in this in this topic is is how to query your data how to read it but I didn't say I didn't tell you how to write your data to the server and that's mutations intentions are basically they're not really complicated think of it as just a remote procedure call so you just have a remote method that's given a name and a set of parameters and that's it you basically fire that method remotely but when you do you have the choice of you have the opportunity to specify a query using the same formalism that I just showed you that basically so that basically you can ask the server to send you updated information as soon as that mutation is happened so in an atomic way you can perform a data changing operation something that has side effect and at the same time receive that the updated information that that action now has affected so that's that's how mutations work and then finally the most exciting piece because it's last addition to this pack is gras is subscriptions so by leveraging a push mechanism like WebSockets you can have your server emit events and so your client can subscribe to these events events are just things to have a name in your client that just subscribes to those events to get notifications that those event happen but when you do subscribe but you have again the choice of specifying a query so that not only the server tells you that that event happened but it also tells you gives you updated information that you know that event might have impact so that how it works so thanks
Info
Channel: Stefano Masini
Views: 18,615
Rating: undefined out of 5
Keywords: GraphQL, node.js, javascript
Id: Tpf9kVE2AY8
Channel Id: undefined
Length: 37min 35sec (2255 seconds)
Published: Wed Jun 28 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.