 Alright, so our next talk is Robert Myers. He's going to talk to us about GraphQL. Let's give him a round of applause. Thank you. Yeah, so we're going to take back the web. A little bit about me. For the past 13 years I've been doing Python web development. The last six of them have been at Rackspace. And at this point in my career, I can just consider as myself a senior sanitation engineer. And what that means is I don't actually develop software. I mostly maintain other people's software. And I'm including myself in that other people group because I was a different person three years ago than I am now. I know different stuff. I'm using different things. So, I mean, software is moving so fast. It's hard to keep up. And currently I'm working on that website. You probably know it. It's trying to be a single page app. It's using some JavaScript, a little bit of React, a little bit of Redux. It's a hodgepodge of stuff. But it clearly needs to be updated. It's got some glitches. It's buggy. But the problem is that it's millions of lines of code, or hundreds of thousands of whatever, lots of code that was maintained by a number of people. Now the company is pivoting where there's less people working on it. And what happens is it gets harder to maintain. It gets harder to update. You lose knowledge of when people introduce Redux to your product or project. And it's complicated because they leave and the knowledge leaves with them. So what do you do with all of these complicated web projects that are out there? We could just throw them away. Or we could turn to the newest JavaScript single page app stuff and start going. Or we could take a new approach. I've been taking approaches using GraphQL. What this talk is not about, though, is not about replacing REST APIs with GraphQL. Or exposing a GraphQL endpoint for other people that can consume. Nor is it an introduction to GraphQL. I don't have enough time to go deep dive into the technology. But what we are going to talk about is using GraphQL as a thin wrapper around your data sources. The databases, REST APIs, static files, even main frames maybe. This will simplify your existing views. And we can reduce your dependency on UI frameworks. And with a little bit of help, we can all take one of those old websites that are sitting around and haven't been updated for a few years. And turn it into something more elegant using Python. So here we have an example, just a simple list page. For the sake of argument, let's just say this is written with Angular 1.0, which is decidedly out of date now. It does some XHR requests to get some data from an API and renders the list. It works pretty well. But if you have to change it, it gets complicated. Somebody says, why can't you just add this field? You know, like this is simple. Okay. I have servers and they have IP addresses. I look on the details page and I can see that it has a network address. So I could just change the little query and just add that field. Simple, easy. But you dig into it, you look and you see that the server's API actually doesn't have the network info. This is just an example. It could be anything. But really the UI is directly tied to this API. It doesn't have this data. We have to get that data somehow. So we go digging around on the details page to see how we do it. Oh, and apparently this is a separate microservice that does networks. Okay. So we have to pass in the server ID to get back the IP address that is attached to the server. You may run into this problem as well. This is something inherently with REST APIs. If they're tied directly to a database, it has only the fields that are in that database. You need related items that you have to go and fetch from a different API or a different endpoint. But so how can we fix this? Well we can come up with a hacky API solution. That would be to say add just a, let's just add a query arg. It says include network or include other details. And then the API can go and fetch all the details and return it back with a response. And it's great. And this works okay if you own the API. But if you don't own the API, say it's a microservice that you're just consuming, you really can't change it. Or maybe they're two completely separate systems and they just can't do this join at the API level. So this might work for you and it might scale. It might work. Then there's some hacky UI solutions you can come up with. So you want to show this on the list page. Well you can do some lazy loading. You have your components. You can show the server list and then do a little loading pattern for get the network. And that would work. But that makes it complicated. It was nice and simple. Just a list. It did an API call and just iterated over those and displayed them in a table. It's not very intuitive and it's probably not documented. Some of these hacky solutions. You can also do the multiple API calls and aggregate them in the JavaScript. And that gets complicated too because you're doing one-off solutions. And it's usually not documented and fix-mes and to-dos don't count. So how can GraphQL solve this problem? Your data doesn't fit in neat little buckets. Resources or collection of different concepts. You have relations in your data that aren't represented well with restful APIs. GraphQL is kind of meant to break the norm and say like your data is a collection of graphs. They're all connected in different ways. So when you start into GraphQL, you're going to write a schema. And here's a sample schema for what we're going to do to solve our little problem here. We have a couple resources here. We have a network and a server. And you'll see that the server now includes one extra field called the network which is the resource type is the network that we divide here. Now this is what I like to do when I'm designing my schema is to make the resources what I want them to be, not what they are. So try not to map your resources directly to your restful APIs or your database or whatever. Kind of think of it like how you're designing your UI. All the elements you'd want to see on the page you'd want to have make them nice and easily visible. The nice thing about GraphQL too is you can just keep adding attributes here willy-nilly because it doesn't matter how much stuff you shove in the schema because you're only going to return the results that you asked for. So you can freely go wild. But try not to remove fields because removing fields is very bad. It causes problems. But we won't get into that too much. But it's also not magic. We have to tell GraphQL how to resolve these. One of the things I like about the schema here is this is not code so it doesn't have too many bugs. It may have a bug but it doesn't usually introduce bugs in your system. This is a schema sort of like your database schema. As long as you don't start putting in logic in here it shouldn't create more bugs for you, hopefully. So how you resolve data is you create these little functions called resolver functions. These all have a similar signature. Basically they take a source and info object which is a GraphQL resolve info. And they can basically do whatever you want them to. Here I'm doing two API calls. One I'm getting the server's request and I'm returning that JSON response. And then similarly for resolve network. Now resolve network is going to resolve the network field on the server type. I'm being passed in the server here as the first argument. And I'm grabbing the ID in it and using that to fulfill my request. So with this these functions are really easy to read. They're really easy to write and test because they're just little standalone functions. They don't have a lot of setup that you need to do. So you can easily map out your entire schema and all of your APIs and stuff that you're using, all of your data sources in these little functions to your queries. So let's look at how we connect those to your schema. It's not easy to do. It's not very elegant. There are some projects out there that make this better but this is the brute force way. Since our schema is just a flat file, it needs to be told how to resolve those and it needs to tell which fields are resolved by which functions. So we're loading the initial schema that we had before using build schema to build it and then once we have the schema, we can iterate over the fields and replace the servers query with the resolver function for that. And then on that server type, we're going to set the network field resolve to the resolver function that we did. And at this point, we're ready to go. Now we can just query. I don't know how well you're going to be able to see this but this is the GraphQL playground which is one of the reasons why I really like GraphQL is it comes with all these nice little tools to see your data. It has auto-completion and you can see all of the stuff that's in your schema and it tells you when you're making mistakes and you can quickly go through and figure out how you're going to query your data. And it's a little slow here because I'm a very slow typer, sorry. And then you see here we have our results and now we have our server list and we also have our network data embedded into our API which we now and we could also, if you want to, you can look at the documentation. You can see how the different types are defined and what is available for you to make queries on. And this is all done through what GraphQL calls an introspection query where this playground, the first thing it does is it goes and hits your GraphQL endpoint and it asks for all the schema types and it gets back all the metadata for the schema and then it can display it. And you also, maybe you could see up at the top there a list of servers and connection information. Those are strings that are embedded in your schema so you could basically do markdown inside your schema and then this will show up in your documentation. So this is a really nice tool for developers to go in and see your schema, see how to interact with it, and how you're going to use it. So that's great. We know how to query, we've got our data. How are we going to get this into production? Now this is where it's going to get controversial. This is how they want you to use it. This is the authors, or maybe some of the authors, a subset. Here we have React Apollo. What you're doing here is this is a simple little component that is going to make a query, it's going to call our servers, get our name ID. I left out some information here but you would have network on here and everything. What it's going to do is it's going to set up a query object, resolve that query and then return the results and iterate over those and create a table with the results. This looks good. It's kind of simple, it's easy, everything's there. But I've seen this pattern before. Maybe some of you have written it before too. I know where it is. It's PHP. We're going to connect to our MySQL server. We're going to do a select query and then we're going to iterate over the results and print out the table. Simple, right? Well, I think we've learned that that kind of pattern doesn't really work, doesn't scale very well. Maybe it will. The Apollo query team, our Apollo server and they're good developers I'm sure and maybe you can make it scale and make it work for your product. But in my mind you're putting a lot of technical debt into your UI components where there's supposed to be just simple views of your data. That's kind of how I approach it. I have my database or my API that has all my data and I have a view that fetches that data and then a view, I have a controller that fetches that data and then a view that just displays it. Can we do this in a different way? What if we just did the query on the server? This is using Python and we have a nice little route here that's called servers. That looks like an API call but it's going to be a slightly different API than our restful API. It's going to return our query that we have defined and return a JSON response. Now, if you remember, we are dealing with Angular 1.0, a list page. We can just change the URL it was fetching to this new one and all of a sudden we have our network data and we're done. Great. This is a great pattern I can use. We can just start going through all the rest of our little components and we're going to go and we're going to make servers, we're going to make networks, we're going to have queries to get a single item from the database and everything. You can go see we have some reoccurring patterns here. We see repeating ourselves over and over again. We can make this slightly better. Let's just put the queries into a folder. We'll call it queries and now we can have this little function called load query which will read from the file system, parse the query and then return that to the function. Now we can just have two methods, collection and a instance one which instead of being one specific one, we're going to take that query as a path element and grab the correct file from the file system and we're good. Neat, right? But is this any better than rest? What we just did was we kind of just made a different version of rest. We made kind of a collection of resources that only have that if you want to change them we have to go and change those specific ones and we have to manage that. How can we do this slightly better? We need to stop thinking about like a restful API and start thinking about how we're going to build our UI. What your UI is is a set of views and with GraphQL you can bundle multiple queries in one query document. So if you take your approach of like let's get all of the data that we need for a single view. So we're going to look at refactoring a dashboard view. The dashboard has lots of data. This query doesn't even fit on one slide because we're getting, I'm going to get some server quota data, some network data and then I'm going to come up with this new concept called resources which doesn't have a direct API. This is an aggregation of three separate APIs. I'm going to have networks, volumes and servers in this and they're all going to have various fields attached to them. You'll see and I have this dot dot notation. That is fragments and we'll get to those a little bit later. But each one has the various things you can do. Some of the things that I'm also doing here is I'm including app status and app actions. Those are concepts that I'm coming up with and I'm calling them. That's my application logic. That I'm just sprinkling those into the underlying API that comes back. So app status is something where it's like every thing in my world has a status. But they're all kind of defined slightly different and they all have their own little business rules about what's active, what's doing something, what's in a broken state, what's in a recovery type state. There's all these different things. So there's a lot of business logic tied into that status. But with GraphQL you can kind of, well, there's nothing to do with GraphQL, but with programming you can make a concept that's a new concept and with GraphQL you can easily attach those to your queries just like we did with those resolvers. And then we also have some other fields. One of the things here I've also included was navigation. So on the page itself you have your navigation instead of static links. But what I've found in a lot of applications is they're not exactly static. They have rules around them. So certain users in your system might have access to that URL, but maybe they're not, maybe you have a call to action like please upgrade your account. And these are also the fragments that I was mentioning earlier. How do I join it? We're going to move along here quickly. So at this point we have two options. We have this query. We can execute it on our system. And we have two ways of displaying this to the users. We can just use Jinja templates. That is the ultimate taking back of the web because we'll make it just a flat static site. Otherwise we can make it make a mini SPA. So the option for doing templates, you just do your GraphQL query, render your response, get your data and then render your template. Simple, easy. Everybody should know how to do that. Now the next pattern is you make two separate, one handler and then you add in a little statement check that sees if there is an XHR in the query parameter. So we can just add a query parameter for XHR and then the JavaScript can then do lazy loading to get the data. Whereas the template is just loading the structure of the page. So here you see this template view. It just includes, and I'm using web components because I hate NPM and I hate all JavaScript frameworks, sorry. You can do with Chrome and soon to be new browsers, you can do this module import, type equals module and that makes it possible to do import statements in your JavaScript. Just like a normal programming language. That's awesome. This is my little dashboard view, highly simplified obviously but I have this little function to fetch data and it's just going to add in a query response and notice I didn't even encode any URL because I have one URL and this is just going to hit the same URL and every five seconds it's going to refresh the data. So we'll have nice up to date data and this is just passing the data that gets down to these sub components that just renders. So they don't know how to get data, they don't know where it comes from, they're just rendering it. It's nice and easy. So and here's a little view of what I've done. You'll see, are we almost done here? And these are all the tools that I used. Python 3.6, GraphQL Core Next, any A SGI framework, this is different than a whiskey framework. I use Starlit, web components and READ, which is a new framework. GraphQL Core Next, go, it's great. It follows the GraphQL JS port, reference implementation. And this project I like a lot. READ, it's I guess the goddess of the labyrinth, the Greek goddess of the labyrinth. But this kind of follows the Apollo server model of defining your schema files in GraphQL files and then implementing those resolver functions. And it has a nice easy way to connect those resolver functions to your schema. And it has a nice easy way to connect those resolver functions to your schema. That's better than the hard coded way. And I think I am out of time here. So lots of more stuff in here. We didn't get to questions.