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
AI Generated Video Summary
This talk provides an overview of using GraphQL, Apollo, and Next.js together. It covers Next.js' data loading and routing capabilities, code generation with GraphQL, and generating TypeScript types. The talk also explores Apollo Client and its integration with GraphQL code generation. The speaker recommends checking out companion repositories and resources for more information.
1. Introduction to GraphQL Apollo Next.js
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 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. 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.
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 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. 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-type-kit book. So, hit me up if you're interested about that. The way you can hit me up is on my Twitter at Joshua K Goldberg 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, Create Next App, that the Next folks made, similar to Create React app. They've gone ahead and done that for us at GitHub.com slash Joshua K. Goldberg slash GrapQL. 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 kind of quickly. So to start, I have already Git cloned and yarned. So if we do yarn dev, Next.js starts a remarker 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 roots 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.
2. Next.js Routing and Data Fetching
Next.js provides a link component for SPA-style navigation, eliminating the need for full page refreshes. It can prefetch data for links within the viewport. Next.js allows exporting a GetStaticProps function to fetch data for static pages, improving performance. The DevTools panel in React browser DevTools provides a tree view of components. Incremental static regeneration (ISR) allows on-demand page building.
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. 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. 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 component. Awesome. And if I go back and forth in the browser URL bar, it's able to do spot-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 the linking, but also the data that's used to power those pages. 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 component. 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 2.5 seconds then returns some data. Let's bring that down there. And 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 2.5 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 just opened the DevTools and I highly recommend if you haven't yet installed the React browser DevTools, they give you this awesome components panel which shows you a tree view of all your components. And I'm going to use it just to show that React is getting the exact array that we expected from ColSum API. Love it. Thanks Next JS. You might have noticed in the code, I actually had this re-validate member here. You don't have to build all your static pages upfront with Next JS. You can use incremental static regeneration or ISR. It says instead of building these things up front, 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.
3. Next.js and Code Gen Integration
Next.js handles the back-end infrastructure of your front-end pages. Code Gen uses GraphQL's strong typings and schemas to generate code automatically from queries. GraphQL tools like GraphiQL and graphqlcodegenerator.com can help with this process. A simple YAML file, codegen.yaml, is used to configure the code generation process.
In other words, once an unfetched or un-cached 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 up front, wait to build them until you need them. Which if you've ever made an e-commerce site or site with a lot of different locales and translations, comes out to a lot of time saved. And then data loading is cached and deduplicated nicely between requests. Next does all that magic for you behind the scenes, so all you've 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, say, 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-props instead of get-static-props. 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 Code Gen before we loop it back into 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, an 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, 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. GraphQL... There it is, codegen.yaml. This is in my repo, and I've hooked it up.
4. Generating TypeScript Types and Introducing Apollo
Let's take a look at how we can generate TypeScript types for our GraphQL schemas using graphql-codegen-plugin. By running yarn gql, we can generate full TypeScript types for our queries. We can also use .graphql files for our queries, which provide syntax highlighting and editor execution IDE features. These files can be configured in a gql operations YAML file, allowing us to have auto-generated types for our specific queries. Apollo is a fantastic set of tools and CLIs for GraphQL, and we will explore its code-gen areas and integration with GraphQL code-gen.
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 and generate my source-generated GraphQL TS file using the graphql-codegen-plugin type script. In my package of JSON, I've taken this graphql-codegen-cli and the plug-in for type script and I've generated this GQL script.
So when I run in a new terminal, yarn gql, it's going to generate this source-generated graphql.ts file. It takes a little bit so I've pre-created it. And here we have the first instance in this talk of a few of type script 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 an 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. And that's amazing. We can generate full typescript types for our graphql schemas just with a single command, yarn gql. And that's just one of the plugins that's available to us, the type script 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 dash operations yaml file, which takes a look at these documents, these queries.graphql, and adds in this typescript operations plugin. So if I do yarn gql, I forgot the command, gql operations, there we go, and 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. So 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. And 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.
5. Exploring Apollo Client and GraphQL Code Gen
Apollo Client is a state library that integrates closely with GraphQL requests. It allows you to send queries to a GraphQL endpoint and store the results in the cache. Apollo Client's real power comes when used with tools like Apollo Provider and useApolloClient hook. By generating code from .graphql files, you can easily write queries and have tri-state data, error, or loading returned. GraphQL code gen is a powerful tool that generates Apollo components and hooks from GraphQL files, saving you from writing boilerplate code. For more information, check out the companion repositories, nextjs.org, GraphQL code generator.com, Apollo GraphQL.com, Blitz.js, RemixRun, and TypeScriptBlind.org.
Apollo Client is 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 de-duplicate them nicely. Now I'll note that it requires queries passed through this GQL string formatter, which does some behind the scenes niceties, but also means that VS Code extensions and other IDE versions know to give you nice syntax highlighting. So these, what, 4, 1, 2, 3, 4, 5, like dozen lines of code, this is a quick way that you can send a query to a 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, and I am starting to do that here. So let's take a look at my components, Apollo, component, Apollo, wrong 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 back to the components, and here we have my nice little GetRandomJoke GQL. But there's some really nice Apollo, oops, 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. So 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 plug-in 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. And 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. So 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. And if I go to source pages with Apollo query, therefore, look host 2000, with, or...what is it? With Apollo queries slash components, wait for it to build the page, d-d-doo! Voila! Now on my page, I get a random cat, pun, sad little joke every time I load the page. And just looking at the network tools to see how that looks, boop-ba-boop! Here we go, my GraphQL fetch which has a payload with the query and then the response data sent back to me. Amazing. So 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. 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 and 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, GraphQL code generator.com and Apollo GraphQL.com are all excellent. And 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. And 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.