JavaScript Air

023

Wed, May 18, 2016

May

12:00 pm CT

We've heard about GraphQL quite a bit. We know that there are problems with REST and GraphQL solves many of those problems. But now we have a new problem: Transitioning from REST to GraphQL. Let's talk about what it takes to do that well and how services need to adapt to this new way of thinking about data access.


Audio


Video



Links, Tips, and Picks

Steven Luscher Profile Picture

Steven Luscher

Tips
  • When you arrive at an n-way stop at the same time as one or more vehicles, who should go first? Take your right hand, and point it to the right of you. If you’re pointing at nobody, it’s your turn to go!


Kent C. Dodds Profile Picture

Kent C. Dodds

Tips
  • Colocate AMAR (as much as reasonable)


Transcript

KENT: And we're live with JavaScript Air. Hello, everyone! My name is Kent C. Dodds and I am your host for this JavaScript broadcast podcast, all about JavaScript and the web platform. Today, we are going to be talking about transitioning from REST to GraphQL. And maybe not just REST, but SOAP. We might be talking about SOAP. That'd be interesting, maybe not (laughs). But, yeah, we have a couple of subject matter experts with us today, so I'm super-excited to be chatting with them.

Before I introduce everyone, I'd like to give a shout-out to our sponsors. So first our premier sponsor is Egghead.io. They have a huge library of bite-sized, web development training videos. Check them out for content on JavaScript, Angular, React, Node and more. Hopefully, GraphQL coming soon, actually. I think somebody's working on that.

And then Front End Masters is a recorded, expert-led workshop with courses on Advanced JavaScript, Asynchronous and Functional JS, as well as lots of other great courses on front-end topics. Check them out at frontendmasters.com.

TrackJS reports bugs in your JavaScript before customers notice them and with their telemetry timeline, you'll have the context you need to actually fix them. Check them out and start tracking JavaScript errors today, at trackjs.com.

And SparkPost is email delivery built for developers. Build something awesome with their Node.js library or SMTP relay. Start sending a hundred thousand emails per month, free with SparkPost at sparkpost.com/jsair.

And finally, WebStorm. WebStorm is a powerful JavaScript IDE. It makes developers more productive with its super-intelligent code assistance for JavaScript, Node, Angular and React, and integration of lots of different tools. Learn more at jetbrains.com/webstorm.

Great, so as a reminder this a live show, and so with that, we have the nice benefit of being able to engage you, the live viewers, and so if you have any questions, go ahead and ask those on Twitter, with the hashtag #jsAirQuestion. I'll have my TweetDeck up here, watching that. And we'll answer those questions at the end of the show.

And as a reminder, we are a weekly show, and so we have another show next week, same time, same place, and it is Progressive Web Apps. I'm super-excited about the show because I think progressive web apps are the future and awesome and exciting. And so, yeah, we'll have a couple of guests on there. Henrik Joreteg, (I'm not sure how to say his last name. I should probably find out), Ada Rose Edwards, Nolan Lawson and Ben Kelly. So a bunch of different perspectives. It's gonna be a great show.

And, yeah, that's it for my announcements. So, oh yeah, and then always, follow us on social media, Google Plus, Facebook, Twitter, all that good stuff to keep up with the latest. Oh, and I should probably also announce there is a React Native app for JavaScript Air, which is super cool. So on iOS and Android, check out the JavaScript Air app. So it's JSAir.

So, yeah, great, let's go ahead and introduce everybody, so we have for our panelist, Dan Abramov!

DAN: Hi, everyone!

KENT: And I will be hosting. And then for our guests, our subject matter experts, we have Lee Byron.

LEE: Howdy!

KENT: And Steven, oh shoot Steven, I didn't ask you how to say your last name. Luscher?

STEVEN: Hey you nailed it!

KENT: Sweet!

STEVEN: Hi everyone!

KENT: So awesome, yeah, so Lee and Steven, why don't you give us a quick intro to yourselves, who you are, where you work, what you care about and why GraphQL life matters to you. We'll go ahead and start out with Lee.

LEE: Sure. So, hi, I'm Lee. I work at Facebook and started the GraphQL project four years ago, actually. And also led the effort to redesign GraphQL, and open-source it, last year, this time last year. So GraphQL is important to me because it's my baby, but I've also seen it do some pretty awesome things at Facebook and help us build stuff that we never would have been able to build before without it.

KENT: Super awesome! Now that we're talking more about transitioning from REST, but I would really love a back-story on how you created GraphQL, or like where the idea came from. So we'll chat about that in a sec. Steven, why don't you go?

STEVEN: Sure. Yeah, my name is Steve Luscher. I work at Facebook. I started for a year working on the Instagram Web Team and now I work on the Relay Team. And GraphQL to me, I've landed on the Relay Team, and I think it's sort of, it's sort of fortuitous because in the early days of React, people were really excited about building user interfaces, and they were like, "Oh yeah, declarativity. This makes so much sense." But then there's always, always this missing piece, you know, "Okay, well fine, I can build this beautiful declarative UI, but how do I get data into it? How do I ferry data back and forth from my server? How do I perform mutations," you know?

And, in my last company, we were sort of grappling with this and sort of like circling the solution. And when I joined Facebook, you know, Pete Hunt, pulled me aside and he was like, "Hey, have you seen, have you seen this thing? This thing, Delay?" That was the code name of Relay, before Relay became Relay. And he showed it to me, you know, colocated queries in the form of GraphQL, that sort of looked like, you know, what your response format would be without all the values and you know, married together with React components. And to me, it all started to make sense. So that's why I was super-excited to join Relay and work together closely with the GraphQL Team.

KENT: So yeah, I love the co-location idea, like colocate all the things. It makes things so much easier. Well, that's great! Cool, thanks for coming on the show, each of you. So to kick off our show, I think it would be great to get a baseline. I think most people who are really interested in this show, probably know what GraphQL is or at least have heard of it. But It would be great to get a baseline, so could we talk really quickly about what is GraphQL? And then maybe Lee, you can go into the background of how GraphQL came to be.

LEE: Sure, GraphQL is, it's a query language, it's a QL. But it's a query language, not for a database, it's a query language for your application. And another way to think of it is, I've heard it described as nested RPC. So if you're familiar with RPC, then nested RPC is where you can do an RPC call, and then based on the output of that RPC call, do another RPC call, and then get all of the results sent back to you. It started at Facebook as trying to figure, just the same problem that we've been trying to solve for a long time, like how do you get data that lives on the server to the client and then solve all the myriad of problems that inevitably come out of that, right? The problem of how do you only get the data that you want, so you're not just over-sending data, which is especially important when you're on crappy network connections which is basically the default now that mobile has taken over web. How do you handle, multiple related resources?

So this was a huge problem for us before when we had a more RESTful kind of API, where we needed to load newsfeed, and then we needed to load the users for the authors of every story. And then newsfeeds' stories often contain other pieces of information within them, and you just, you either get all this duplication and with like a super-custom endpoint, or you get these URLs, (oh my gosh, my lights just turned off) ...you get all these URLs that you have to go load and in a second run. And that's super annoying either way, right?

So GraphQL is an attempt to solve those kinds of problems. And the origin of it was actually, Nick Schrock. So Nick Schrock's given some talks at ReactEurope before. He keynoted the last React Conference, so you can go learn about Nick. And he had this idea to take our existing server code and kind of expose it in as a raw a way as possible. Our server has this framework called ENT, which is short for entities. And it's a really simple ORM. And what he wanted was a way to basically write, like condensed PHP code, that you could then send to the server, which would run and it would be limited to only like getter functions, and it would run all those getter functions, and then it would send the data back.

And so he showed me a prototype of this, and, you know, it was really, it was a super-early prototype, it was kind of janky, you know, regular expressions to parse the stuff, and like a pretty crazy executor. But it totally worked, and the idea kind of blew my mind. It was like, "Yes, like this is, this is so much better than what we were doing before. Let's figure out like why, how it's gonna break, like let's figure out how to make this thing work at scale."

And so Nick Schrock, Dan Schafer, who was on the Newsfeed Team at the time and myself, got together to figure out how, how GraphQL should look, and then how it should actually point at our service data. And Dan Schafer, in particular, was pretty instrumental in that. On the Feed Team, he was the mastermind of how a newsfeed would integrate with GraphQL. And that was like actually a pretty, pretty fast project. It went from crazy idea in the sky, to like a working server in about a month. And then a lot of the work after that was just getting our iOS up in a much better shape. And we launched the first version of our iOS app that hit a GraphQL-based newsfeed API, in the late Summer of 2012, so about four years ago.

KENT: That's quite a history (laughs).

STEVEN: I really love how... oh it happened to me too. I really love how Lee described, you know, straight off, it's a query language, not for your database, but it's a query language for your application. I like to think of like, you know, at Facebook we use one monolithic GraphQL schema, that describes everything you could possibly ever want to fetch. And it doesn't really matter if it's backed by, you know, a database or some, you know, microphone hanging on a window, that's like generating entropy, like it could be anything, right? It sort of describes your data universe, rather than any one particular storage back-end. And in this way, you can write a GraphQL schema (and I'm sure we're gonna talk about this later), that fronts pretty much anything. Like you can have some fields in a GraphQL query being resolved by (mumbles), you can have some being resolved by, you know, live video stream, or anything you can possibly imagine, that you can, that you can express in code. But fundamentally, what falls out of that, the response format is something that looks, you know, very familiar. It's a record, basically. It looks like JSON, behaves like JSON and it matches, very, very closely to the query that you just made. I like to describe GraphQL. Lee described it as a query language for your application. I like to sort of flippantly describe it as slick JSON, just without all the values.

KENT: (laughs) Nice. So as in like the query language, itself, like you look at the query and it's like JSON without values.

STEVEN: Exactly.

KENT: Cool, cool. So on like, what we talked a little bit about the, you know, some of the problems that it solves, what are some of the things that, like, is there a point where GraphQL makes sense? Or like does GraphQL apply to all applications? Should everybody use this or is it a little bit more complex? Or does it add too much complexity to like a basic smaller application?

LEE: So, I don't know if complexity would be the thing that I think you'd (mumbles) to use GraphQL. Actually, when we shifted from... so our iOS app used to hit a RESTful API server at Facebook, and it was a lot of code. In transitioning to GraphQL, we deleted tons of code. So it actually ended up being dramatically simpler from the client's point of view. Now that's kind of where we started. Since then, you know, it's been four years, we've built lots of really complicated tools on top of GraphQL because it gives us the stable base to build those tools on. So we've built up a lot of complicated things to do stuff that was impossible before, but none of that was required to use GraphQL. It was made possible by GraphQL. So, complexity, I don't know is the thing.

We also, in talking to server engineers, found that GraphQL helps them organize their code, and shrink the amount of code that they had to write in order to surface an API. I've had to write like REST framework integration code before and it kind of sucks. It was like, it's really not too dissimilar from if you're writing an HTML-based website, where every endpoint needs to load, all the HTML for that page. Sounds simple, until you realize, oh you got to hit these databases in this order and then fill out this template and then do this and that. And, you know, it's enough work that you end up with at least a couple hundred lines of code. And those probably call out to functions, which are other lines of code that's all kind of manual stuff that you maintain. With GraphQL, the mapping tends to be pretty small. And if you think about, you know, each endpoint in your REST API, might be dozens, hundreds, thousands of lines of code, depending on how complicated that thing is, the corresponding GraphQL-type that it maps to, that you define those types, tend to be really, really small in comparison. So it's actually a simple find for us on the server as well.

But to get back to your question about like where are the boundaries? Like where's a good idea and not a good idea? I think that depends a lot on the architecture of your application, the purposes of your API, etc. There's a lot of greatness about REST, right? One of REST's super-powers is that everything that one resource points to is a URL, which means any one resource can point to anything else on the internet. You can have two APIs hosted by totally different companies that know how to talk to each other via URLs. That's nothing that GraphQL tries to solve for you. In fact, doing something like that in GraphQL would be very hard, but it's because it's outside of the scope of the problem that are trying to tackle. But if your application is bend with constrains, if it's constrained on how many network operations it's trying to do, if it's constrained on the amount of code that's being written, to take the output of that no-network call when the REST API finally dumps you data and then parse that into model files or whatever. Like, if that's the focus, then GraphQL can actually be a great simplifier.

STEVEN: On the topic of complexity, I wanna go two places with this. Number one, because you can introspect a GraphQL schema, for those who haven't used it, once you've built up a GraphQL schema, that describes your data universe in a nested way with fields inside fields, inside fields, like, for instance, users, posts, authors, right, sort of cyclic relationship. We have tooling that lets you inspect at every level. "Okay, I'm in an author. What's its type? It's a user. What fields are available on it?" And any client from, you know, someone who built the schema themselves, to a new intern who just joined your team, can use the introspection tools to understand, at a glance, immediately, what fields are available on user, what fields are available on posts. And this literally is available through and auto-complete interface.

And I think these sorts of features lend themselves to, you know, increased developer velocity. You can move a lot faster when you, when you don't have to go, you know, swimming through server code to figure out, "Okay, well I'm hitting, you know, I'm hitting myapp.com/home. That's my mega REST endpoint. What does it return? Like what data's available on there?" You can introspect the query just at a glance using tooling.

And another thing about complexity that I wanted to say was that because GraphQL queries are sort of composable, they're also fragmentizable, right? You can pull them apart...

KENT: I love that word!

STEVEN: ...into fragments of queries. And you know what, this is a lot has to do with relay, is push a lot of the complexity of data fetching, abstracting that away up into a framework level, so that you can do, you can do incredible things, like you can say, "This tiny little avatar widget needs to know this subset of this larger universe of data," like maybe the profile picture at 50 pixels and the link to the user's profile, right? And that's all it needs to know about. But because GraphQL queries are sort of intimately composable at the framework level, we can put an avatar into a post, into a list of posts, into a blog application, and compose that tiny fragment of a query all the way down into a larger query that we eventually send off to the server resolved however we resolved it. So these sorts of features have let us sort of abstract away a lot of complexity of data fetching, pushed them up into the framework level, so that you can move really, really, really fast and be able to jump into a small section of an application and have an impact without having to understand the entire system.

KENT: Yeah, I think that it's really cool to see like more and more things moving to a more composable and like composability design pattern, where React's really pushed forward the idea of the composability of your different components. And then, you know, bringing that into, into our data queries, having composable data queries, it makes it a lot easier for us to like, I totally love, like keeping, colocating as much of our stuff as possible and so that when you, when you're a new developer coming onto to a team, you say, "Okay, I need to update the avatar widget or whatever." I just go to that avatar widget file and I see everything that I need to know about what makes that avatar widget work. And with, you know, the CSS and JS kind of movement thing as well, like, being able to have even the CSS, the HTML or JSX and the data stuff, everything that you need, just right there in that one file or in that one folder, all together, and the tests even, makes it so much easier to come in and make a quick impact. So it's really cool to see GraphQL all kind of enabling that.

LEE: We've been using GraphQL at Facebook for four years, but this idea of colocated fragments is actually a relatively new one. This is an idea that Relay introduced and we're actually now taking that idea and bringing it back to all of our other platforms that use GraphQL. And it's been huge because one of the serious problems that we've had in our apps, that is a serious problem that lots of people have in their apps is just over-fetching, just like getting more data than you end up actually using.

And as we've been going through components and writing fragments that describe exactly what those components need, and then ultimately replacing like master query files that say like, "Here's all the data you need for this whole view or this whole part of the app," we find that all of that over-fetching completely goes away, because we can write tools that say, "You wrote in your query here that you wanted this field. But then in the same file, you never asked for it." It's like the same kind of lint rule that ESLint can do. It's like, "Hey, you defined this variable and never used it."

And the inverse is also possible, right? Under-fetching, where you end up asking for something on a model, but you never actually got from the server and then it just shows up invisible and you have a bug in your product. You can do the same trick. That's like using a variable without defining it first. Same lint rule. It's like, "Hey, you're using this thing from the model that you never defined in the query. Did you mean to put it in the query?" And it's been super-powerful to just completely curb over-fetching and under-fetching in our existing apps. It's something that, you know, really introduced that idea. Pretty cool.

STEVEN: And another thing that co-location, sort of does, I love Greg Hurrell who works on, who works on the Relay Team with me, he gave another talk at Relay Deep Dive, Technical Talk. It's available on YouTube. I'll put the link in later. And he talks about, he talks about coupling. You know, is coupling bad? Is Coupling something we want to avoid? But, you know, fundamentally the model of your data, that author is coupled in a way that you can't, you can't avoid to the user interface. User interface demands that certain data is present. The data will hydrate the user interface. And what co-location lets us do is it lets us, it lets us sort of embrace that coupling, but makes sure that, that coupling occurs over a shorter distance, right? Literally within the same component, you know, component file or that boundary. So an avatar can now say, "Okay, I'm going to admit," you know, a therapy session for a component, (laughter) "I admit that I'm coupled to my data. But, you know, it's all right here and I'm declaring just the parts that I need."

You know, before, you'd have to say like, "Okay, I need to render a profile picture," and then the front-end dev would have to go all the way back into the back-end, the REST API and be like, you know, "Is this the 50 pixel version being vended through /users, /id? If not you need to put it there, or put it behind a flag, that's like, you know, user/one with a little query param that's like include profile picture at size equals 50,100 or something like this." And that's coupling over a very, very large distance. I mean that's spans the network, that spans different technologies. If we're able to colocate the query and abstract all of that complexity up to the framework level, they embrace this coupling over a much smaller distance, which I think is huge!

LEE: Yeah, and usually when we talk about coupling, we're talking about like separating technology concerns or separating functionality concerns, right? And one of the nice things that GraphQL lets us do is separate the concepts of actually like going to the network, and doing network activity from the data that we ultimately want from the network. So when you colocate, your GraphQL with your component, you're not like, it's code that's calling the network, it doesn't make it any less unit testable, right? It doesn't do any of the things that tight coupling costs you. And so maybe coupling isn't even the right word to talk about those two things next to each other, because it's not influencing how you end up actually talking to the network. As Steven mentioned, it lets us pull all that stuff away and do it somewhere else. So it actually allows us to more loosely couple those two things to each other.

KENT: You know, that's a really interesting, interesting idea. And I think that, like maybe what we're kind of talking about here is dependencies and I guess that's why it's so, like in our minds, it's all about coupling. But like in the way that common applications are built now, you have kind of these implicit dependencies like this avatar which is implicitly dependent on the data it receives. And, yeah, maybe like it accepts all that data as props, and so you can make it explicit in that way, but it, it like, it doesn't really do a whole lot for you. I feel like GraphQL makes that just even a little bit more explicit. And then like, you know, in the same vein having like, we're really used to having CSS, like these giant CSS files that style everything in our application, but it's like totally implicit. And there's no like, it's you know, then we build all these tools to find out, okay what styles am I not using because it's implicit, like you have no way of knowing, for sure. So, yeah, I think it's really cool that GraphQL has brought that to our data.

So we've kind of alluded to a couple of the strengths of GraphQL, or we talked about some of the strengths of GraphQL and that kind of has alluded to some of the weaknesses with REST. What are some of the other things about REST that make developing applications a little harder that GraphQL solves?

LEE: I think it's actually pretty, pretty simple. I don't there's a lot of them. I mean REST does a lot of stuff really great, but the one thing that it tends to not do great is allow you to get all the data that you need, nothing more or less, in a single round trip. Many REST frameworks have like extensions that let you do variations of this where, you know, maybe if you ask for, maybe I have like an endpoint that gives me a list of my friends. And rather than just like simply giving me an array of URLs, which might be the like most straightforward REST-ty thing to do, I can ask it to like expand. I'm like, "Oh, actually expand, because I actually want to know the names of all my friends." There are a lot of REST frameworks that can do that, but what many REST frameworks don't let you do is say, "Okay, I don't want to just know the names of my friends, I also want to know the last group that they posted in." And by the way, for each of those groups, "I want to know which of my friends are in those groups. And by the way for each of those friends that are in those groups, I wanna know their name, and I wanna know who their best friend is. And I want profile pictures all the way." And you know you ask for all these dependent resources. I've never seen a REST framework that can do more than one level of inclusion of a URL resource without kind of cascading into over-fetching. GraphQL is designed explicitly to handle exactly that problem, where you have a mobile connection that's crappy, you have latency that's very long. And I just like the idea that you would have to do two network round trips, where the first one has to come back before you know enough information to do the second one, is just like completely insane.

KENT: Yeah. That's what leads us to kind of breaking out of REST and making these one off endpoints, like, "Oh, I'll just make this one, so that I don't have to like do multiple fetches." I'll just say, "Okay, this is the data endpoint for this page and I'll get everything that I need for that page." And then, "No I'll just, like make that one exception." But then you wind up making a million of those.

LEE: I've gotten in that exact same trap. It's like, "Okay, what we really need here is you know, we're trying to build the feed for our app, so we're just gonna have our API slash feed. And then that's just gonna give super-custom stuff that's specific to that view." But even that is kind of painful because what you've really done then is created a tight coupling between your client code and your server code. And then when your client needs to change because, you know, products evolve all the time, and you're like, "Whoops, it doesn't need to work that way. It needs to work this other way!" and you have to change the server, and you have to change this in lockstep. And if we're talking about a web app that's deployed as JavaScript, maybe that's okay. You might have to worry about, like a little bit of safety or someone has cached JavaScript and they're at your server but that might get by. But you have iOS or Android apps or any kind of deployed binary, once it's out there, you can't take it back, right? So you send that out and people are going to continually hit that endpoint expecting data to come in a certain way.

And, you know, the last time that I had to build apps that way and I had to build API endpoints that just give custom stuff, we broke stuff all the time. It was just really hard and we ended up with these insane test plans before we could deploy where we had to look at every "supported" version of our client which just only grew over time. Even if you're like, "Oh, as soon as somebody has more than six-month old version of the app, then we won't support it," which is conservative, if you would launch your app every month, you're still talking about like six versions of your app that you have to go test on every view, to make sure that nothing broke when you changed an endpoint, which basically cripples the server team. And so that's why I like, when you talk to your API engineers, that's why they're so upset all the time, it's 'cause they're like every time something breaks, it's their fault. They have to fix it. So GraphQL also like helps us get past that problem where the client was responsible for describing what it needed, rather than the server implicitly having already having written that stuff out.

The other thing that it ends up doing that's nice is because you have a semantic understanding of what that stuff actually is. As Steven mentioned before, GraphQL has a type system there and every point in that GraphQL query is talking about a particular type, a user, a post, etc. And so when you get that data back, you know what type it is, which makes it way easier to build a caching mechanism. You can say like, "Okay, here's this thing that claims to be a user, and here's this other thing that claims to be a user. I can store them in the same spot. I can do lots of interesting things depending on how complicated I want my caching system to be. I can start to make sure when I get a query in one place that has new information, that I make sure that it's updated in all the other parts of my view, etc." It's much harder to do that kind of thing when the server's contract is, "I will give you newsfeed and that will be JSON. Good luck to you." Right, like it's much harder to build a shared caching strategy around that.

STEVEN: And it's paralyzing for developers as you've mentioned, you know, API developers, 'cause they jump into this endpoint like slash feed, and they look at it and there's all the history of everything that's ever happened to feed there. And they terrified to remove a field because they don't know what client's using it, who's depending on it. It's very difficult to find out who's depending on it because unless, you know, unless a graph of your code base turns it up, you might not even know what PC's interface is using that, whether it's being hit anymore or whether it even exists. Even the non-presence of--

LEE: It's a recipe for--

STEVEN: Yeah, even the non-presence of that in your code base, you're like, "Uh, is it really, has it really been deleted? I'm just gonna leave it here in this endpoint." And so you end up with these incredibly bloated endpoints, that contain, you know, they read like a history text of like every experiment that your company has ever tried and like failed and abandoned. And you know, these weird things like, at exp underscore one, underscore user, like, you know, some long abandoned experiment. As an exercise for the reader, I honestly encourage you, like fire up Charles, fire up an HTTP proxy, and put in front of your favorite, you know, app that you use daily and you'll find incredible things in there. You know, it reads like a storybook.

LEE: Oh my gosh, one of favorite things of all time was, so one of our engineers, Adam Ernst, he is occasionally asked to visit other companies and gives talks about the kinds of things he's building at Facebook. And I think he, I think it was Etsy that he went to, and, you know, they didn't give a prompt. They were just like, "Hey, a friend of his worked there. Can you come talk to us and tell us about some of the cooler stuff that you're building?" And he decided that he was gonna tell them about GraphQL. So he set up Charles which is a proxying service, you can look at APIs. And he had his Etsy app on his phone hit Charles and then he just watched the traffic, and he basically reverse-engineered their API and then stepped through their API and then told them everything that we're doing wrong. It's like, "You're doing this. That's gonna be bad for these reasons."

And then after he had like explained all this, then he like showed them GraphQL and he's like, "Okay, let's go back through all of those and show you how we would do that with GraphQL." And he like wrote GraphQL queries. He basically came up with like the whole GraphQL interface for them and then wrote it all out. And during the presentation, as he was like showing, you know, the folks in the room, they were like, "Yep, we do have that problem. Yep, what you said is correct. That did bite us."

And so, yeah, he was just looking at it from the experience of, you know, he's an iOS engineer at Facebook, so he's watched the app go through this many phases of life. And he was a pivotal member of the team that helped integrate GraphQL four years ago, so he's watched the kinds of problems that you suffer from and been first-hand at replacing them with the appropriate GraphQL queries. But I loved it! It was one of my favorite presentations ever. I wish it was something that we could share more broadly, despite it being company specific.

But Steven as you were saying, I think you can replicate this experiment for yourself, so whether it's your app or whether it's from your company or some other favorite app you have, hook it up to your proxy, just like watch what happens! You'll be surprised how chatty it is, how weird those endpoints look. Like, the insaneness of the API responses that are coming back. It truly is, yeah, like a history lesson of what that app has been through over the time that it's been released.

STEVEN: And to your point, there are REST frameworks that try and eliminate these problems, or like make it easier. But in practice, time and time again, plugin that proxy and look. And that's what I see in practice. People are terrified to remove things, constantly adding things. And, you know, custom the entropy is this universe of custom endpoints, rather than, you know, rather than one unified one. That's the sort of entropy that we've tried to reverse with GraphQL, one unified endpoint that knows how to respond to every possible query, since time immemorial. It's amazing. If you have like an iPhone 3GS or something, sitting in a drawer, you know, go find one of those power adaptors and charge it up and see if you have the Facebook app on it. It's amazing that it'll still, you know, the GraphQL queries that are present in that, you know, three year-old version of the Facebook app, they'll still resolve today. And that's something that's really amazing.

And on this flip-side, someone who's doing some cutting edge experiment, right now, in whatever product at Facebook, they're putting in all of these fields to do their experiment, and if the experiment fails, they can sort of just sweep away that client code with impunity and that query is now completely flushed from the system. It's not going over anyone's wires anymore.

KENT: It's so amazing. I'm seeing, like I keep coming back to CSS, but I just see so many parallels to the problems that we have with CSS. That's just really interesting to me. So, let's talk about the actual transition period. I think we've probably talked enough about trying to convince people that GraphQL is a good idea and could really save people from a lot of problems with REST. So how complicated is it for... and I guess there's kind of two parts to a transition from REST, right? You have this server-side part and you have the client side, whether that client's written in React or Angular or Backbone or whatever. So let's talk about the server side first. How difficult is it for somebody to take their server and turn it into a GraphQL server?

LEE: It's not hard at all. And here's the strategy that I usually suggest people do. And actually, Steven did a super-awesome talk about exactly this idea. Start on the client. So basically pretend that you're hitting a GraphQL endpoint, but all you're really doing is just running GraphQL, locally. And what that lets you do, is just play with it, right? 'Cause often what makes changing a client-server relationship very hard is that unless you're a very tiny company, it probably involves at least two people, if not more, right? You got to convince everyone that this is a good idea, and then you got to plan it, and then you got to like figure out how to deploy it. And there can be a lot of steps that need to happen, until you can make your first GraphQL query and be like, "Oh look, is it valuable for us now?" Like you really want a much earlier point at which you can say, "Here's a prototype. Check it out. This is what we can do with this." And you wanna be able to do that as like a one-man army so you can actually convince people, this is what it looks like for our data at our company.

So, usually what I suggest is, take a look at GraphQL.js. We made our reference implementation of GraphQL in JavaScript, for the very reason that it can be run in so many environments. Run it in the browser. What you do then is because GraphQL is a query language for your application, what that actually means is every kind of field that you see in a GraphQL query, maps to a literal JavaScript function. There's a JavaScript function that will be called and it will return either a value or it will return a promise for a value, and that's it, that's the whole contract. So, that's great because it turns out that talking to networks is really easy, if you can talk about it as a promise for a value. You hit a REST endpoint, you get a backup promise for ultimately the like JSON payload that it will return to you, and then you can keep going. So you can write a REST wrapper in GraphQL with a fairly small amount of code. Everyone should watch Steven's talk, we'll get a link up to that talk where he does that exact thing, for three different programming languages in about 25 minutes, which is pretty awesome, for like a reasonably complicated thing. So it's not hard to do. Like you can do it, in an afternoon to try it out for like a portion of your app. Now, that doesn't win you the like network chattiness problem. All that lets you do is say, "Okay, now I can kind of see what it would look like. I can write queries. I can get responses. I can start to visualize GraphQL for my own data." But it's still being chatty over the network, right? It's still actually sending all those REST requests.

The next step is to actually put that code on your server. And you could do that in a lot of different ways. If you have the ability to run Node somewhere, anywhere, you can just take the exact same code that you just wrote for GraphQL.js and run it on a Node server, still hitting the REST endpoints. You could even put that on Heroku or something, if your REST endpoints can be hit live, which I assume they can, if you're using them for your web app or iOS app or whatever. And that way, you can just kind of like spool it up on your own, just to kind of prove the point, and then show how the iOS app can now look, one round trip and I get all this data. And even better if you can do that in a way where you're colocating with data center. So if you use AWS, deploy it to the same cluster. If you use Heroku, deploy it to the same like Heroku cluster. That way, the calls to your REST endpoint are happening within the same facility and they're gonna be like extremely fast.

And then the final step is to actually write, like remove REST from the equation and re-implement GraphQL. And at that point you can kind of do it kind of incrementally. You can go through kind of one type at a time. And basically the same kind of code that you would write to implement a REST framework is roughly the same kind of code you end up writing to implement GraphQL. And you can do that kind of one type at a time and then eventually you get to the point where there's no more REST anymore and you either keep that REST server alive if you have clients that depend on it, and you can have a brand new GraphQL server or you can remove it if you're no longer using it and then you're just on GraphQL all the time. But that kind of progression of try it yourself, you know, be a one-man army to test it out, test it totally on the client, just so you can kind of get a feel for it, then host it up somewhere, but still point it at your REST endpoints is kind of like a good one-two punch, for testing it out without requiring like agreement from lots of people all at the same time. And that will give you a basis from which to start to then convince co-workers that what you're doing is actually good.

STEVEN: I love that progression. That's, you just laid it out so well. I wanna try and say exactly what you just said, like, just like, I wanna get super-tactical for people 'cause I did give a really, really, tactical talk. It's called "Zero to GraphQL," and you can search on it, where I sort of live-coded up one of these schemas. But this is basically how you can start, just as Lee said. There's a library. It's called GraphQL.js. There's a method, probably called GraphQL. It takes two arguments. It takes a string that represents the query, and a schema that you wanna execute against. So basically the string might look like, you know, in curly braces, me, curly braces, first name, email. Maybe you won't wanna get your first name and email. So that's the string. Second argument is the schema. The schema is where you locate all of these resolver functions that know, given a user-type, how to go get the first name and the email. And this is where you write JavaScript.

In Lee's first example where you're just purely operating on the client, those resolver functions are probably gonna like make XHR requests to the server and hit your REST endpoints to get that user, you know, and pull out the first name and email fields and stuff like that. And that's like, that's the whole thing. If you can pull that in, write a query, that's just a JS string, write a schema using our schema creation libraries, that know given these types, where to go get the data for them, then you can go get started. So your, and the return value of this function is just an object. Basically, you can think of it as the JSON response that comes from the server. So you put in GraphQL query, a schema that you've crafted that knows where to go get that data, and it will return you a JavaScript object with the response.

DAN: Do we have any Twitter questions that we want to answer?

LEE: I think we do. I can see a couple Twitter questions coming in.

DAN: Yeah.

LEE: One of them is, one is asking what are the best learning resources for GraphQL? That's a great question. And to be honest there, it's actually relatively sparse right now. I think there's a lot of appetite for more resources to learn about GraphQL, which is on us to some degree. But the community is actually stepping up in a pretty big way there. So there's this GitHub account called awesome-GraphQL which lists out links to tons of different things, blog posts, conference talks, libraries, tools, that are all about GraphQL and they try to surface the best content. Also the Meteor Apollo Team, it's a Meteor company. They're building a new client and server that speak GraphQL and they've been pretty regularly writing about GraphQL and I found those to actually be really good, like introductions to GraphQL and the concepts. And then once you're familiar with GraphQL and you're like, alright, I wanna get into the weeds, GraphQL.org has a lot of, GraphQL.org has a lot of resources there as well. There's kind of like full articles, there's blog posts, there's just like API documentation. That's what we have now. It still, I got to say though, it's a little sparse. We need more, we need more stuff.

DAN: I have a small question. Can you tell me, what is the difference between Relay and this Apollo thing? Are they both libraries on top of GraphQL? How are they different?

STEVEN: Yeah, that's a question for me. Super-embarrassing 'cause I have not played with Apollo yet, even though we've been in close conversation with the Apollo Team and sharing ideas, sharing ideas about Relay, sharing ideas about Apollo and sharing ideas about GraphQL, itself. But, unfortunately, I can't speak to the differences between Relay and Apollo, and their approaches. Yeah, because I've been in the weeds, working on, working on some stuff. But I very much look forward to being able to come up for air and check out what they're doing and seeing what we can learn there, learn from them.

LEE: Yeah, I would add that, you know, there are a lot of trade-offs that you make when designing clients or when designing frameworks for data on clients. You can choose to be as simple as possible. You can choose to have really complicated caching mechanisms that do smart things for you. You can be very pluggable and have a lot of user-provided functionality. You can be very opinionated. There's all kinds of trade-offs that you can make. And even within Facebook, a lot of our frameworks make different trade-offs based on the kinds of stuff that people are building.

So, our iOS and our Android apps, for example, are actually simpler than Relay. Relay does a lot of smarter things with the cache than our iOS and our Android apps were doing, and we're now kind of like learning from each other. So our iOS app is taking advantage of some of the caching techniques that Relay introduced. Also Relay introduced that idea of colocating fragments with the components that use the data. And that was a new idea, so we've been stealing that one in our iOS and Android.

iOS and Android, themselves, have come up with cool ideas that Relay doesn't do. One of them is the ability to look at all the possible queries that your app could ever run before you ever run the app and then upload them all to your server ahead of time. So you can think of this like stored procedures for some, you know, some SQL databases have this concept. You get back, just like these really small keys, that represent those queries. And then at run-time, rather than sending up a big string that describes the whole query you wanna run, you can send up a key that represents that query which is gonna be much smaller bytes. And if you're talking about, you know, if you're optimizing down to like how many TCP packets are we sending in order to do this request, you can get a query that would have been many TCP packets 'cause it's a string down to one TCP packet for that outgoing request. And so now Relay is actually investigating what doing that would look like, within Relay.

So there's a lot of these trade-offs. We're learning stuff, and we're seeing new GraphQL clients pop up in the community, mainly to take a different point on that continuum of trade-offs. So one of my favorites that's community-driven is called Lokka, L-O-K-K-A. And the drive on that one was to be as simple as possible. So basically what it does is it helps you construct your GraphQL query, and then that's it. It sends the query to the network. It comes back and you get JSON, and that's it. And one step simpler than that is cURL or XHR, right? It's like kind of the same that a REST endpoint would be, like you don't have to have a client framework to hit a REST endpoint. You just XHR it and then you get back JSON. GraphQL is very much the same way. Like if you point your GraphQL query as a parameter string and like send it, you'll get back a JSON payload, and that can be your whole client framework if you want it to be. It's just all kind of different points on the continuum of how sophisticated you want your clients to be or how simple do you want your client to be.

STEVEN: Yeah, you reminded me, I think in conversation with the folks from the Apollo Team, they were definitely trying to find some different trade-offs than we found on the current Relay. And I think one of the things they're trying to do, is they're trying to make the simple things really simple.

LEE: And one of the key differences between Apollo and Relay in particular, is the integration with other view frameworks. So Relay is unapologetically about React. Its purpose in being, is to tie together React and GraphQL. So the whole idea that Relay would do some other kind of view framework is just against its reason for existence. With Apollo, it's different. Apollo's reason for existence is not to tie React together, it's to create a common library for GraphQL. And so they wanna build integrations with Relay, sorry with React, integrations with Angular, integrations with Ember, to be more flexible.

There are trade-offs with that, right? Like if you know that you're doing React, you can do really cool specific things that have a much tighter integration with React. If you know you wanna be more flexible and target other view platforms, then you have to curb that back and be a little bit more generic. That gives you that flexibility, but it also means there might be, you know, additional plugins you have to use or some other thing that has to happen in order to make that happen.

So, you know, these are all just trade-offs that you can make, so I imagine that, I can't envision a future where there's only one GraphQL client. That seems like a failed future in my mind. I think we will see a handful of, you know, of the peaks and valleys of value along this continuum, that people just find all the spots where, where there's value. It's like, "Here's one that's really simple. Here's one that's really flexible. It can be lots of things. Here's one that's great for React. Here's one that's great for iOS," right? And we're just gonna see a bunch. I think that'll be awesome!

STEVEN: This is why I'm really glad that these two projects exist, because, yes, Relay grew up unapologetically as a, you know, way to bind queries to React components. But I think what we're finding, you can take a look at some of our recent meeting notes for Relay or the Relay future repo, we're starting to think about how the concepts of like the client store and all of the other like abstractions that Relay offers. You know, whether we could whittle that down to a core and if React Relay could be a wrapper around that. So we're starting to explore these things. I think the existence of the Apollo project, the Apollo project (whooshes) (laughter) can only help, as we share ideas and like explore different decisions and different trade-offs.

KENT: Great. , am I back?

LEE: Yeah.

KENT: Okay.

STEVEN: Yes, you are.

KENT: That was really weird. Yeah, that was great discussion. Thanks for carrying the stuff on while I had some weird things going on. So we do still have two more questions that I think are both relevant and interesting. S Daniel asks, "What is a good starting point for people with SQL background, only?"

STEVEN: Yeah, this one's really great. There's nothing that we can particularly point to, except I wanted to point to this project called PostGraphQL. It's actually an automatic schema generation library for PostgreSQL. So it'll inspect a post-graph schema and try and generate a GraphQL schema from it. And I think if you're starting from SQL background, if you did that and started to see what the output of the schema generator was, then that's a good way to sort of slipstream into writing your own schema or customizing that schema further.

LEE: Yeah. Also one of the things that we tried pretty hard to do with GraphQL is keep it very simple. So there are extension points to let us do more complicated things, but it's actually much simpler than SQL. And in doing so, it explicitly doesn't do some things that SQL does. And so if you come to it from a SQL background, probably the most important thing to know is that it's solving a very different problem than what SQL is solving. SQL lets you ask arbitrary questions about a series of tabulated data. And GraphQL does not do that. What GraphQL lets you do is ask, kind of going back to my metaphor from before, nested RPC. You can call a function on your server and get back the values, and then call more functions on the result of that, and get back the values, and ultimately come out with kind of a JSON payload of the results of all those operations. So the query language, itself, is simpler than SQL. And it's targeted to let you do only the things that, whoever built the schema, wants you to be able to do. So no, kind of arbitrary order-by's on an unindexed field that cause super-slow queries, which is actually another boon for server engineers and DBAs in particular, that you're not constantly hunting down, like bad queries and trying to go fix them, yourself. That's something that we haven't had to solve with GraphQL.

KENT: That's great, awesome. Check that out Daniel! For Mike Williamson, our last Twitter question, "Why the split between GraphQL regular types and input types? Why are both needed?" This seems pretty specific. If you could give us a little bit of background.

LEE: Yeah, so, we mentioned before that GraphQL has a type system. So GraphQL has a type system, both for the kinds of things that you can ask about. And, we didn't really talk that much about this, but there's this other concept of being able to provide inputs to some of these things. So a good example is, there might be a field on User called Avatar, a profile picture. And you might actually want different sizes of that thing, right? So I'd say, "Hey give me the avatar for Steven Luscher." And it's like, "Alright, here you go." And I get this 50 by 50 pixel image. I'm like, "Well that sucks, 'cause I'm on a quad retinal display, and I wanna like display this thing at, you know, 300 by 300 pixels."

So what I really wanna do is be able to provide an argument, so if you literally think about that thing as like a function, where the function is get profile picture and the implicit first argument is Steven, the user object, and then the next argument needs to be "what resolution do you want?" And so for that you need input types. So input types, there's all like the scalers are the same, so, you know, strings, Booleans, whatever. But there are handful of cases where you wanna provide a complex and protects. You wanna provide and object with fields, as an input, or something like that. And this is relatively common when you're doing GraphQL mutations. And so these two type systems are different. The output types are your users, your newsfeed posts, whatever, all the things you can ask questions about and get answers for and your input types are all the input that you need to provide in order to get the right data back out. So these two things are different because they have subtly different characteristics.

So one good example is those arguments. So a field has arguments in an output type, but in an input type, it does not make sense to have those fields have arguments. If you think about what the corollary is in a programming language, like JavaScript, a output type is an object that contains only methods, right? It's a class with like getter functions. That's an output type, and an input type is like a plain old JavaScript object that has some properties on it, with some values there, right, with no functions anywhere in it. That's kind of the mental model that I use to distinguish the two from one another.

One of the other discrepancies is default values. So output types don't have a concept of a default value. Where input types, you can say, "Okay, here's, like a point in the world that has longitude, latitude and altitude. And altitude I don't always care about, so if I don't provide it, what I mean is sea-level." That's a default value. So now I can say, "Here's my point on the world, longitude, latitude, and that's it." And now we just, we know you're talking about sea-level. Output types aren't the same. You either ask for the field or you don't. There's no default value. So because there's all these discrepancies, we actually tried to figure out if we could make them the same. Are there cases where an input type, and an output type are just gonna be the same. And every time we tried to do it, there was just too many weird quirks and like bad-edge cases and just decided it was best to keep them separate.

KENT: Cool, great thanks for that answer. So there was one more question, but we don't have time for it, so if you wanna check out that through the Twitter hashtag after, I'm sure Apollo would be very grateful. So let's go ahead and get into our, just wrapping up with our tips and picks. And we'll have Dan go first, then me and then Lee and then Steven. So go ahead, Dan.

DAN: Sure, so let me open the doc (laughs). So for today's tip is something that is, I'm working on a new series about Redux, like more real-world patterns, it doesn't get as sophisticated as Relay. It's just talking to REST endpoint (laughs). But so as I was working on tutorial, I noticed the pattern I started following which is related to what we've been talking about, the co-location. So in Redux, what you often do, is when you often want to change, especially in the beginning as you iterate on the application files, you want to change the state shape of your application. Like, you want to introduce something new into the state shape. You want to store it in different way for, as an optimization or something. So this gets painful, if you have to hunt for all the components and all the other parts of code that rely on this specific state shape. So what I suggest doing is together with the reducer, right in the reducer files, you can put the selector functions that... they act as a public API for the state managed by this reducer. And just like you compose the reducers into separate files, and then combine them, you can also compose selectors and have selectors call other selectors, thereby ensuring that if you change the state structure this change is localized in a single file and you don't have to change any other components. So this is my tip for today. I linked to a comment, sorry, a place in the Redux examples where we used this pattern.

And I have a bunch of picks for today. So my first pick is a new interface to OCaml language which Facebook released just like yesterday. It is a creation by Jordan Walke, who's the author, the original author of React. And it's like super-cool. I'm very excited about functional languages. And this is a way to write in a functional language with a mature tool chain, but in a syntax that kind of resembles JavaScript a lot, especially ES6. So it's a great way to introduce yourself to functional programming, in a comfortable way.

Another of my pick is React Tiny Renderer. So it's a project that implements the minimal interface for a React renderer. You probably never need to do it in your projects, but it's a great learning exercise into like how React works internally and how the difference between ReactDOM and React Native is actually implemented in the code. And so this is a tiny renderer that just renders everything into JSON.

So my next pick is a new course by Wes Bos, called Learn Redux, which is free. It's sponsored by Sentry. Big thanks to Sentry for doing it. So check it out. People say it's really great, so it must be great!

And I have another pick with Mark Erikson's link collections. So with Mark Erikson is the person who came up with Redux Fact, where they ask questions and he has a really good collection of links in his GitHub profile. So check those out.

And I wanted to highlight Apollo Client again, because people have been talking to me about it and asking have I looked at it. It integrates Redux with GraphQL and I haven't had a chance to look at it yet. So check it out as well. That's it!

KENT: Great, a ton of awesome resources there. And I think, I don't know if you mentioned the actual name of that OCaml interface, it's called Reason. So good luck Googling that (laughs). Yeah, I had a hard time finding that one. Okay, great so for my tips, I'm actually gonna piggy-back on Dan's tip about colocating selectors. I'm gonna make it more broad, as colocate A-M-A-R, that's as much as reasonable. So try to get like your CSS and your GraphQL queries and your HTML if you're doing it, if you're not doing React like put your HTML right there. And like, yeah, just as much like your test files and everything, put it where it's being used. And so like even if you have multiple components, if it's only being used by one other component, you just like extract out, put them where they're being used. It just makes it a lot easier to think about this like structure of your application. So yeah, colocating is great!

And then I want to pick, LGTM, Looks Good To Me. This a service, or it's a GitHub status bot, that will allow you to say, like, "This pull request can't be merged until two maintainers say, 'It looks good to me' or 'Ship it,'" or something. It's great. It's enabling some really cool things for open-source projects in the way of like automatic releasing and doing all kinds of really cool things, so I like it.

Code Cartoons is really applicable for this episode, specifically our cartoon guide to Facebook's Relay. And if you're interested in more of the inner workings, how everything works this is a fantastic blog post from Lin Clark and so I recommend you check that out.

And then Aphrodite. This is CSS and JS done right. I totally love Aphrodite. It is amazing. And so there are a lot of problems with doing in-line styles in CSS and JS, but Aphrodite gets around all of those by actually generating actual CSS styles and sticking those into the DOM. And so you can use media queries and pseudo-elements and all kinds of that stuff without doing some magic JavaScript stuff. So, yeah, it's fantastic. I recommend you check it out! Great, Lee why don't we have you go next?

LEE: Just got to unmute myself. Alright, so I have one pick for the day and it's a book, and it's a new book that isn't out yet but you can pre-order it. And I've had the ability to read some of it before it's come out. And it's super-awesome and so I like super-can't wait for the whole thing to come out. It's called "Suspension." You find it at readsuspension.com to get a pre-order. It's super-cool. It's a sci-fi, political thriller book, that deals with zombies and reality TV and the presidential race. And it takes place in the United States in 2018. So it's like sci-fi, but it's like sci-fi that happens very soon from now, which is cool. Like I don't think we see that kind of writing that often. So I'm super-excited for that. Check that out!

KENT: Cool, I'm looking forward to 2018. (laughs) Cool, Steven.

STEVEN: Hey, I'm gonna do my picks first. My first pick is music. I want you all to take a look at an album, Hope by The Strumbellas. It's an old friend of mine, that I used to play in garages with back in Oshawa, Ontario. And now, that band's gone to Number One on the US alternative charts, for good reasons. Let's take a listen to that! It's gonna melt your face.

Second thing is a book. It's called the "The Lost Chord," by Conrad Amenta. This is an incredible science fiction book about a world in which algorithms have completely replaced performers in the musical, it's for music. Nobody produces music anymore, only algorithms produce music. And it's an absolutely chilling view of the future, possibly the near future.

And my tip is, my tip is about resource contention. Particularly, about America's highways and roadways. I'd bike to work every day. I live in Menlo Park, right near Facebook's office. Takes me 16 minutes to bike to work each way. It's a hundred percent flat because it's Silicon Valley. But there are a lot of four-way stops along the way and this message goes out to pretty much everybody that bikes, specifically Californians. And I wanna give you a little tip for negotiating a four-way, three-way or an end-way stop. Here's the rule, basically. If you arrive at an end-way stop at the same time as one or more people, what do you do? Who goes first? Do you sort of like look at each other and, you know, do this and like, "No, you." "No, you." "No, you."

Well here's what the Highway Traffic Act has to say, and here's my tip. If you arrive at an end-way stop the same time as other people, take your right hand and point it out to the right of you. If you are pointing at nobody, it's your turn to go. That's the whole thing! You can think of it as right-of-way. If you are the right-most vehicle, be that a car, a bus or a truck, you've got the right-of-way. Go for it! If there's one thing that we don't need on American highways, it's diversity. We should all understand the rules and just, just run 'em on a daily basis!

KENT: I love that tip! We need to get more of those kinds of tips (laughs). Thanks for that! Cool, well let's wrap this up! So I'd just like to give a quick shout-out to our Silver sponsor, Trading Technologies. They are hiring and so check them out. And then if you have suggestions for the show, we love getting suggestions of guests or topics, so go to suggest.javascriptair.com. If you have feedback for this show or the show in general or a previous show, go to feedback.javascriptair.com and submit your feedback. And then we have a weekly newsletter that goes out about highlighting, like highlights of the shows and with the show notes and everything. Go to jsair.io/email to sign up for that and see previous ones. And then remember, next week our show is Progressive Web Apps, and it's going to be the bomb. We're going to have a good time and follow us on Twitter, Google Plus and Facebook to keep up with the latest and download the JSAir app on your iOS or Android phone. And with that I think we can say goodbye. I thank you so, so much Lee and Steven! It has been a blast!

STEVEN: Cool, thanks for having us!

KENT: We'll see you all next week!