Modern frontend applications want to efficiently query data on page load and navigate, format the data with TypeScript, and cache data between repeat requests. Setting that all up on your own is a chore... but with Apollo and Next.js, you can set up your client to auto-generate TypeScript types, cache query results intelligently, and generally be a breeze to work with.
GraphQL + Apollo + Next.js: A Lovely Trio
GraphQL Galaxy 2021
Hello and welcome to graphql apollo next.js, a lovely trio with me, Josh Goldberg. This is going to be a quick talk, so I'd like to think of this one as an overview. The goal of it is to get you hyped. This is really cool technology. We're going to be auto-generating types and looking at introspection and cool stuff. The target audience for all these nifty things are folks who are new to next.js, maybe know graphql and want a primer of how to use next.js with graphql. A little bit about me, this stuff is near and dear to my heart because I do it for work. I'm on the web platform team as a front-end developer at Codecademy, a great place to learn how to code. I work on our shared tooling across all of our front-end apps, such as our recent and ongoing move from our custom react Rails webpack architecture to next.js, which does a lot more for us and helps us use things like apollo and graphql. On the side, I'm also working on an O'Reilly Typekit book, so hit me up if you're interested about that. The way you can hit me up is on my Twitter at JoshuaKGoldberg or my website, JoshuaKGoldberg.com. Let's dive in. next.js, delightful react scaffolding. In a nutshell, next.js scaffolds data loading and routing for react website pages. It does a lot of other cool stuff for us like really great builds and optimization, but for the purposes of this overview talk, it's really just the data loading and routing that we care about. There's a great tool, createNextApp, that the Next folks made similar to createReactApp. I've gone ahead and done that for us at github.com slash JoshuaKGoldberg slash graphql, a Galaxy A Lovely Trio. Again, shout out to my website, JoshuaKGoldberg.com. If you want to get these things, I'm going to be going through these slides quickly. To start, I have already Git cloned and yarned. If we do yarn dev, next.js starts with a marker really quickly, and then when we first visit a URL, it starts loading the page, which might take a little bit first. So I'll just go ahead and look at the page. Pages slash index. Every file under the pages directory, which can be in your root or under source, default exports a component for the page. In the case that we're looking at on the slide here, you don't have to return much, just some JSX, and then next.js will build the page for you based on that path. The contents of the page are entirely up to you. You can use whatever html contents, whatever style you want so long as it's a react component. Voila, here we go. We can see that this Next beautiful starter component is now rendering all of a sudden. Good for us. A little bit of cool stuff from Next to start us off is its routing logic. Next supports SPA or single-page app style navigations, which means that instead of having the browser fetch an entirely new html page every time you want to navigate, Next provides a link component that wraps and takes over the linking behavior of your normal anchor tags. So let's go to a quick page, pages slash with link, which means that if we go to slash with link, we get the corresponding page in our browser for this component and file. Now, this one uses the link component as seen on the slide, which means that if I click home, which is an anchor tag, notice how the page will not refresh. There's no new html file. It just directly quickly brings me to the home components. Awesome. If I go back and forth in the browser URL bar, it's able to do SPA style navigations without a full refresh. Fantastic. Fan diddly-tastic. Thanks, Next. Now, I have seen rumors online and some substantiation of this idea that Next will actually prefetch data for links that appear within your viewport, if it's a link to a next page using this link, which I think is just the coolest darn feature in the world. Now, the way Next is able to do that is not just by controlling your page generation and then the linking, but also the data that's used to power those pages. To start, if you have a static page, meaning a page that gets built into a static html file that can be immediately served, very good for performance, highly recommend when possible. Next lets you export a getStaticProps function from that file, which can be async, and in some way finds the data for that page, then returns the data as props to be passed to that page's default components. In development, this getStaticProps function will be called every time you try to load the page. But in production, the page is pre-built with html, and then this data is cached, so you don't have to keep querying for it over and over again. Just quickly looking at a page, pages slash with static props. Here we see the getStaticProps function, which calls some stub api setup, which just waits two and a half seconds, then returns some data. Let's bring that down there. Then the component itself just uses that as a prop, and then maps over to render a list. Let's look at with static props, wait two and a half seconds to simulate the api call, and voila, we have our static data. Awesome. That's all you got to do to pass data to next components. Now, I've just opened the devtools, and I highly recommend if you haven't yet installed the react to browser devtools, they give you this awesome components panel, which shows you a tree view of all your components. I'm going to use it just to show that, yep, react is getting the exact array that we expected from Coliseum api. Love it. Thanks, next.js. You might have noticed in the code, I actually had this revalidate member here. You don't have to build all your static pages upfront with next.js, you can use what's called incremental static regeneration or ISR. It says that instead of building all these things upfront, whenever someone requests a page that isn't already built, for the next X number of seconds, use a particular piece of data which you will then fetch now. In other words, once an unfetched or uncached page is fetched, fetch the data for that page and then keep it cached for that number of seconds. It's a mouthful. This is great though because despite being hard to explain verbally, it means that you can, instead of building all the pages upfront, wait to build them until you need them, which if you've ever made like an e-commerce site or say with a lot of different locales and translations comes out to a lot of time saved. Then data loading is cached and deduplicated nicely between requests. Next does all that magic for you behind the scenes. So all you got to do is define your logic the way it runs, when to run it, and then Next will handle the rest. Yay, next.js. Some pages do need server-side data, meaning data that comes in for every request. There is a disadvantage here in that if you do need to fetch data on every request if it's a learner dashboard for a learning tool or a timeline for a social media app, well then your page does have to break for that request every time it's called, but you do get fresh data on every request, so there are pros and cons. It looks visually very similar. You just call it get server-side crops instead of get static crops. Fine. In a nutshell, next.js handles the back-end infrastructure of your front-end pages, which I think is a really cool way to look at how a lot of these new front-end tools like next.js and gatsby are popping up. There is within the realm of the front-end, a back-end infrastructure section that's getting really addressed by these frameworks. Anyway, shifting gears a little bit, let's talk about CodeGen before we loop it back in to how it integrates with next.js. We're going to use graphql's really strong typings and awesome schemas to generate code for us. Now, you might have as graphql folks already played with GraphiQL and awesome tool that lets you preview graphql queries and endpoints. I am going to quickly bring up my second repo here, yarn start. I've already get cloned and yarned it. Now, this repo uses the Express graphql library to set up a quick little graphql server that has two queries on it and all in a random. If I query for random, it gives me a random cat joker pun. I'm a sad individual and these make me happy. You can preview this on my GitHub slash graphql Galaxy, a lovely graphql server or the standard one with many more features and things, Swappy-graphql. In a quick summary, what I'm really excited about here is that graphql's api type safety means tools such as graphql, GraphiQL can generate code automatically from schemas. When I say generate code, I don't just mean give you little IntelliSense. I mean a website, GraphQLCodeGenerator.com's contents literally generate your code for you from your graphql queries. Amazing. To start, let's take a quick look at a very simple YAML file. There it is, CodeGen.YAML. This is in my repo and I've hooked it up. Let's take a look at each of its lines. I'm saying in this file, take from the schema, this one that we just looked at, my graphql schema, and generate my source generated graphql TS file using the graphql CodeGen plugin typescript. In my package of JSON, I take in this graphql CodeGen CLI and the plugin for typescript. I've generated this GQL script. When I run in a new terminal, yarn gql, it's going to generate this source generated graphql.TS file. Takes a little bit, so I've pre-created it. Here we have the first instance in this talk of a few of typescript types getting created for our graphql endpoint. If you remember the endpoint, you saw there was a query that had two things on it, two queries and all which is an array of strings, and a random which is a single string. These types are a little more convoluted than I would have hoped, but whatever, it's fine. That's amazing. We can generate full typescript types for our graphql schemas, just with a single command, yarn gql. That's just one of the plugins that's available to us, the typescript one. These plugins are incredibly configurable, and I have links to docs for these in the end of these slides. You can generate hooks, components, higher-order components, all sorts of wild and wacky stuff for your code. Now, those of you who use.graphql files might have already experienced this, but for those who don't, you can create a.graphql file for your graphql queries and get nice little syntax highlighting and editor execution, IDE features in it. I like doing this because it makes it easier for my graphql code gen to create functions and components and types for me. In this queries.graphql file, I've said that in my app, I would like to have two queries made available to me. I get all query which returns all and a random query which returns random. I've set up a GQL operations for my code gen-operations.yaml file, which takes a look at these documents, these queries.graphql and adds in this typescript operations plugin. If I do yarn gql, I forgot the command, gql operations, there we go. I take a look at my graphql operations file. Here we see that not only do I have types for all my queries, similar to before, I now have types for my specific queries. These very specific ones I have defined in my graphql file. My random query is specifically taking in a random string, or rather returning a random string. Its variables are, this is another way of saying nothing. That is awesome. Now if I have code that needs to interact with my graphql queries, I can have auto-generated types for the return types of those queries, which is super useful. You might be thinking, okay, that's nice. You've generated types for things you could have written them by hand. How are these.graphql files actually useful? How are these actually being used in something good? To show you that, I will now introduce apollo, which is a fantastic set of tools and CLIs and shenanigans for graphql. apollo provides a suite of tools for managing graphql, and in particular, we're going to today look at its code gen areas, the way it interacts and integrates with graphql code gen. I don't want to mislead you. There is a heck of a lot of really cool stuff in apollo, each of which could honestly have a huge list of conference talks, server stuff, dashboards for your deployments, federation to unify multiple graphql endpoints. It's incredible the amount of things they've made, and very painful to only be able to talk in this limited time slot about just one, but such is life. apollo Client. It's a state library that integrates closely with graphql requests. I just have a quick code sample here. If you want to create a new apollo Client, you give it a URI, and here I've also given it an in-memory cache for its requests. It will then be able to client.query, send queries to that graphql URI, and store the results in the cache to cache and deduplicate them nicely. Now, I'll note that it requires queries pass through this GQL string formatter, which does some behind the scenes niceties, but also means that VS Code extensions and other ID extensions know to give you nice syntax highlighting. These, what, four, one, two, three, four, five, like dozen lines of code. This is a quick way that you can send a query to graphql endpoint to get the results and have it be nicely cached in memory. But the real magic of apollo Client comes in when you start using its tools for other frameworks such as apollo Provider, which sets up a react context for apollo Client to become available to queries within. Now, to start, you can take in this useApolloClient hook in your components. I'm starting to do that here. So let's take a look. My components, apollo, component, apollo, one, here we go. Here in my getServerSideProps, I haven't even used the provider yet. I'm just creating a new apollo Client, and I am awaiting client.query here to get the results in my component as jokes. Here we go, return props jokes, which is either failed or the data, and then that's best components. Here we have my nice little getRandomJoke GQL. But there's some really nice apollo component. There's some really nice tools that get generated for you. For example, if you wanted to write a query, what you can do is you can say const result equals apollo.useQuery, and then pass in your GQL of query. Or you can use the apollo code gen to generate the apollo functions, the apollo hooks for you that use your queries from your graphql. Here I have the generated code from apollo Client code gen, which I will show you the schema for. It's really beautifully small. This typescript react apollo plugin for your code gen, which then spits out these hooks that use the apollo client, which is then available within components wrapped by apollo provider. Now I have a component which in a single line of code runs this random query, which is defined in my auto-generated code from my.graphql file. In a nutshell, putting it all together, I have defined in my.graphql file a random query here, which then gets auto-generated into a constant variable here, and a hook here that then returns loading error or data, one of which will be populated at any given time. If I go to source pages with apollo query, therefore local 2000 with apollo query slash components, wait for it to build the page. Voila. Now on my page, I get a random cat, pun, sad little joke every time I load the page. Just looking at the network tools to see how that looks. Here we go, my.graphql fetch, which has a payload with the query, and then the response data sent back to me. Amazing. Using this apollo provider, we can then create these apollo query hooks that return this tri-state data or error or loading, and generate from our darn.graphql file, a whole list of things we can use. Unfortunately, I can only show you these quick little examples. Use query, use lazy query, use mutation, use subscription. There's all sorts of stuff and just use query gets shown. But trust me, there's a lot of great stuff and I have docs in the slides for more data if you're interested. Now, graphql code gen can generate apollo components, hooks, etc from graphql files, and that is, I think, an incredible way to live your life. You take from your graphql queries, this entire area of code generated for you so that you don't have to keep writing boilerplates. I highly recommend trying these out if you have the ability to. Mind freaking blown. So let's talk a little bit about where you can go to see more information. I have all these things and a little bit more in the companion repositories, graphql Galaxy, a lovely trio, and a lovely graphql server. The core technical resources, nextjs.org, graphqlcodegenerator.com, and apollographql.com are all excellent. If you want to see some cool additions, blitz.js is a framework that builds on top of next.js, and RemixRun is a somewhat of a competitor to next.js that came out open source recently. Lastly, my favorite, typescriptblind.org, just a great language to write your stuff in. Thank you to everyone, in particular, the graphql Galaxy organizers. I'm Josh Goldberg. You can find me on Twitter at joshuakgoldberg and on the web at joshuakgoldberg.com. Thanks and bye.