Apollo Client v3 Fullstack Next.js Setup with SSR + Nexus Schema

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

I walk through the Next.js example, but explaining why certain things are done... we'll also do it in TypeScript and use Nexus Schema as well. https://github.com/vercel/next.js/tree/canary/examples/api-routes-apollo-server-and-client

👍︎︎ 2 👤︎︎ u/monosinplata 📅︎︎ Aug 17 2020 🗫︎ replies
Captions
hey how's it going everyone it's lee holiday and in this tutorial we are going to be working with apollo server and client setting it up from start to finish in next js and we're going to take the next js example from the repository which is fantastic but they don't really explain why they're doing certain things they're just sort of like here's the example uh good luck with it so we're going to take that and go through the whole thing from start to finish but we're also going to add in typescript and nexus schema at the same time and this is with apollo client version 3 which is the latest and greatest so if we go down to the terminal we'll create a brand new next.js app using npx create next app and we'll give it a name of apollo next yes so this will just take a second to install all of the packages with the packages installed we can cd into the folder and then we'll just add the three different packages we need for this example so yarn add apollo client that will be the v3 one apollo server micro and i'll explain why micro in a sec and then also nexus schema to help us build our graphql types and resolvers with a code first approach so we'll just wait for this to install i think it'll be pretty quick there we go so here's our next.js app we've got our pages that has an api folder and we've got hello.js so this is the one we're going to replace and call it graphql.typescript let me take a minute to talk about app signal who's partnered with me on this video in this bear sightings application i built which uses nexjs with apollo on the client and also on the server i just finished integrating it with app signal so if i pop over to my dashboard i can start to see information right away about this application even when i'm just developing locally things like it's throughput response time etc but one really neat thing about integrating app signal with next js is that you get access to the web vitals dashboard which reports on all the different lighthouse scores like time to first bite first contentful paint etc so you can try to give your users the best and optimal experience if you'd like to try out appsignal it is free for the first month and if you use the coupon code li l-e-i-g-h you'll get 10 off for your first year now let's get back to this tutorial and the first thing we're going to build is the back end because then we have a front end that can sort of utilize what's already going on in the back end and what we want here is to create a new instance of the apollo server so we will import apollo server from apollo server micro so the reason micro this is sort of a framework that next js uses for their server-side routes so this one is actually official by apollo and it's set up to already work with sort of the inputs and the outputs that you're expecting to receive within next.js so we are going to create an instance of the server so server is equal to new apollo server and we need to give our server a schema so we don't have that yet but we'll come back to that in a second the next thing we need to do is receive a handler from this server so it will receive the incoming request and then respond with the json response so we say server create handler and we need to tell it what path that the requests are going to be coming in on so that it can parse out the incoming requests correctly so because we're inside api graphql that is what our path will be and then we can export this as the default so export handler but if we were to do this as it is it would sort of time out indefinitely and that's because we need to add this one extra export so export a config and the config will have api body parser false so without this it won't work and we basically need to tell next js like no worries i got this do not parse the body because apollo handles that itself so schema this thing's giving us an error so why don't we import the schema from src schema so this doesn't exist yet but i am going to go create it so folder src and inside of here we will create schema.ts and before we get too far this import won't even work until i configure typescript correctly so here's like a little bit of a trick if you just start next js it's gonna freak out and tell you you have to install typescript so we paste that in and then as soon as it's finished installing that we'll just start it up again and the first time it boots the app it will create the ts config file so we can just pause that for now but now we have the ts config and why do i want this at this point because i can define the base url and tell it sort of where to start parsing from and by putting in base url of dot uh dot meaning the current folder so the the root of everything this import now will work correctly the only reason it's failing is because um it's not actually exporting anything uh yet from this file so we need to go create a schema so we are going to import a couple things from nexus schema which is the code first graphql server approach that i've sort of enjoyed working with lately i don't want to keep my types defined here and my resolvers defined here i like to do it all in code and the graphql types will be an artifact of the code that i'm working with so we'll import make schema and we need another one called query type that we'll use in a second so our schema this is make schema and you need to provide some types to it so now we define types and that will be for now nothing but we'll define our first type which would be the query root node so const query is equal to the query type and the definition for this um for the query type the the root of our graphql query will have one field which will be a string and we'll just return my name so return lee holiday like this so with our query type defined we can pop this into the types object and now we're providing this in the schema and the last thing will be to export this so export schema you know what we can just skip that and say export const schema here and hopefully this thing is all cleared up now there's no more error it now knows that i'm going to be receiving this schema here so with that in place we should be able to start up our app and hop into the graphql playground and see if it works so the home page i think it's still just the default one but if we go into api graphql it's already set up here because i had been playing with this previously but i can execute my query and the back end is responding with the data that i told the query resolver to return with so the back end is done we've set up uh apollo server using nexus schema and now it's time to move on to apollo client on the front end so the next step that we're going to do is um go and create a file called apollo dot ts and we're going to be basically defining uh the apollo client in this file but why don't we start with where this apollo client is actually used it's actually used for the first time in this special underscore app component that we are going to rename to tsx and whenever you do that you need to pause the server it freaks out see it's already freaking out doesn't know where to find this file okay so app.txt is a special component that wraps around every single page level component that you have in next.js and it receives the page as this component here and it right now it's just returning it but what we can do is wrap the apollo provider around this so we will import apollo provider from apollo client and apollo provider is a component that should go around your entire sort of application any part of it that wants to use apollo oh man there we go but apollo provider wants to receive an instance of the client so that's what we need to give it client is equal to client and we need to get get access to this instance so we're going to say here const client is use what are we going to call this use apollo just like this and this function does not exist right so we need to import this use apollo from src apollo okay so this is reasonably happy for now it's telling me that i haven't exported use apollo function yet but that's to be expected because we have to go create it so inside of this function we are going or this file we are going to import a few things from apollo client so we are going to import the apollo client itself so from apollo client and we are also going to be importing um in memory cache and this other thing called normalized cache object that's just going to be used for helping our typescript definition and we'll start at the top sort of right out here not in a function at all to create an instance of the apollo client and actually sorry i lied we're not creating an instance of it we're creating a variable that we'll eventually put it into but we'll start it out by just leaving it undefined and we'll tell it what type of data that it is going to have and it is going to have an instance of the apollo client and the reason we import the normalized cache object is to tell it what type of cache that it's going to have so it's actually going to be using in memory cache but this is sort of a generic one that you can use that represents sort of any type of normalized cache that you can use in apollo so next things first or next thing why don't we create that use apollo function so we'll export it so export use apollo like this export function use apollo okay and what we want to do in here is we want to return a copy of the apollo client so we are going to return and instead of sort of um just creating an instance of it right in here we're actually going to call a function called initialize um apollo just like this and before i get too far i'm sort of missing something so in the example you'll see that in the app.tsx it's actually taking page props and it's passing in something called initial apollo state just like that so we're passing some initial apollo state to our use apollo function so initial state and we'll be passing this in to initialize apollo that we'll create in a second but because um if this function's called repeatedly we don't want to re-initialize if we have the same initial state what we can do is use use memo from react to sort of memoize this call to initialize apollo and put it into a variable called store so use memo and when the data has changed call initialize apollo which we'll do define in a second and what data are we looking to see if it changes the initial state just like that and we'll return the store cool so we need to go create initialize pollo right now so we're going to export this as well because we'll use it elsewhere as you'll see in a second and this will be initialize initialize apollo that will take in the initial state and if you don't pass it we'll just say no further is none and inside of this function what we're going to do is actually set up sort of like a temporary variable and we'll give it a name of apollo client and it is going to be equal to either the apollo client if we've already put an instance in this variable but if we don't have anything in there yet we'll use the nullish coalescing operator so it's basically look in here first if this is sort of nullish go to the right side of this operator and what we'll do is create a new instance of the apollo client and hopefully we'll make more sense shortly why we're doing this step and part of it is because we have to differentiate between whether we're running on the server or whether we're running on the client because we're building this to support uh server side rendering or in next.js terminology server side generation so why don't we just pause this function just like this for a sec and let's go define our create apollo client and if you look at the example um on the next.js examples directory i'm literally writing it exactly as they have it here because it's the cleanest approach i've seen yet and in apollo client 2 there was this insane one that i actually never understood but this one i can sort of wrap my mind around so create apollo client we want to return a new instance at this point of the apollo client and whenever you create a new instance of the apollo client you need to give it in this case three things so the first thing is you need to tell it whether it's running in server-side rendering mode or not and the way we can determine that is by checking if there's a window object available so what we'll do is just say type of window is equal to undefined just like that and now we need two other things we need a link which we'll set up in a second we'll just set it to null for now and we need a cache so cache will be an instance of this in memory cache in new uh in memory cache like this so in memory cache cache in general in apollo is basically where it stores the results of queries that are run and this is really important in server side rendering especially because if we run a query on the server when it finally renders in the client we don't want to have to re-run a query that it had already done on the server so we're basically going to take whatever cache was run on the server and initialize our client copy of apollo with that same information and that's what this initial state is that's being passed sort of from the page props to use apollo and we're sort of passing all the way down and we'll use it more shortly right here below and what isn't it liking about this boolean is not oh it's because it's not ssr it's ssr mode there we go okay so we need a copy of link right and this is normally where you tell apollo how to go execute graphql queries are you going to do an http request or are you going to use a local schema that you have similar to the one we created here because when you're running in the client in the browser we need to go across the internet make an http request but if we're already on the server we can just reuse the same schema so we're not having to make an extra http request which would just slow things down so we're going to create a new function called create ice isomorphic link isomorphic meaning it's either going to be running on the client or on the server so function create isomorphic link and in here we're going to have an if statement and we want to check if we're on the server or we're in the client so type of window equals equals equals undefined so that means server else meaning client so why don't we just do the client one first so we want to create a new instance of http link and return it so http link but where do we come where do we get this from because i didn't import it up here and there's a reason for that we're actually going to do a require statement right here and we'll grab http link using this require statement so require apollo client um link http so why the heck would we do this and took me a little while to figure this out i think next js has some sort of parsing that they do when they're building your application and they look for this text here i believe and because it's in an if statement they sort of know that if we're in this statement we're on the server and if we're here we're on the client so that means they would want to include anything required in here in the webpack build that's going to be sent down to the client whereas anything that's on the server branch of the if statement doesn't need to be bundled into that webpack client i tried to get fancy when i was playing around with this to put this into a function called on server which would return me a boolean because i thought oh man that's so smart i'm not going to have to repeat this every time i want to know if i'm on the server but it actually didn't work and it caused me problems so i think they must be looking for this i could be wrong tell me if i am but um so back to http link we need to tell it uh what url our graphql api exists on or at so we tell it uri just graph api graphql which is the same one we had set up here but the reason for is because that's where it actually exists so why don't we do the server setup right now so here we're going to use something called schema link which we will require from apollo client link schema and to use schema link you need a copy of your schema meaning this thing right here so we will import that con schema equals require schema and then we can return a new instance of the schema link passing it in the schema cool so we've created our crate isomorphic link which means our apollo client now correctly has a link and now let's finish off this initialize pollo so inside of this underscore variable we either have an existing apollo client or we'll create a new one so now what we're going to do is we're going to take a look to see do we have any initial state and we'll we'll talk about where that would actually come from in a second we haven't touched on that yet but let's just assume this will be called sometimes with initial state and if we do receive initial state we want to go into that apollo client access its cache and restore it to the initial state just like this so after this if statement we're going to check if we're on the server again so we'll just say if type of window is undefined we are going to return apollo client so what this means is that on the server we are always returning a new version of the apollo client because never are we assigning anything to this apollo client without the underscore variable and that's because every server requests we want a new instance so that my user's request and some other users request their caches don't conflict they're not shared imagine um my bank account is in your cash and now you're viewing my bank account that'd be a disaster so that's why you always want to return a new instance of the apollo client so if we get past this if statement we know that we're on the client and we want to at this point set this apollo client variable with a value so what we can do is we can say apollo client is equal to and what we can do is again just use the knowledge coalescing operator to say if there's a value in apollo client use it we want to reuse it it doesn't hurt to reassign it to our to our self but if it doesn't have a value this is where we want to take the apollo client just like this um and moving on we just want to return an instance of the apollo client and at this point you could use the underscore or the non-underscored version they have the same value in it so it doesn't really hurt anything but at the end of all of this like 50 lines of code we finally have a client that we can pass to the apollo provider so what this allows us to do now is to go into our home page and we'll change it to typescript tsx we will remove everything here like that and it's time to perform our first query in the client so we're going to import two things use query and gql from apollo client and we use gql to define our query the actual graphql query that we want so we'll just call it my query and it will be equal to gql and we'll say we're going to perform a query named my query that pulls the name down and what we can do here is we can um say const something is equal to use query my query so the one we defined above and this gives us back two things or well many things but it gives us the data it gives us a boolean for loading it tells us whether there's an error or not why don't we just go with these two for now so if loading just return a span that says loading that means if we get down to here we know we have data i'm just going to get rid of this head for now and that's get rid of everything so we don't need styles either so inside of this fragment or we could do a div it doesn't matter i'm just going to output whatever's in data so here's a little trick you can stringify the data but if you do that i'll show you in a second so why don't it's already started go to the home page hopefully it works loading so there we go we get um this here and it showed loading for a split second if you pass in null as the second argument which is a replacer that i've never actually used in my life in the third argument you can pass the number of spacing to um to use when it's sort of prettifying um json output and here you can see that it's now outputting sort of brace indented brace so it formats sort of whatever you're working with so we're almost done so if i reload this may be hard to see on video but for like a split second it says loading and if we go into the network tab and search for uh graphql you'll be able to see that it's making a graphql request to our server that means it's happening client-side in the browser now we want to support server-side rendering as well where when the page loads if it already has all the data it needs it won't actually have to do that http request and the way we'll do that is by exporting an async function that's called getstatic props so this is a special one used by nexjs that only ever runs on the server so in here we want an instance of the apollo client and we'll get that instance by importing it from um [Music] we're going to import the initialize apollo function from src apollo initialize apollo just like that so with our instance of apollo what we're going to do is perform any queries that we want um to grab data for for server-side rendering so what we can do is await uh apollo client to execute a query and the query that we want was called myquery so what we're doing here see we're not actually putting the response inside of data like this we're just sort of awaiting it and the reason for that is because we're populating the cache the apollo in memory cache with the results from this query that's being executed on the server so now what we can do and the response from this function is that we can return props that when rendered in the client those will be passed as initial props so remember here we had page props and we're expecting initial apollo state this will be what we're returning from this server side get static props function so we'll return the initial apollo state that we will grab from the apollo client cache dot extract so just to step through this again server side this thing runs we get apollo client because it's server it's always a new instance we execute any queries we want it to have inside of its cache and then we return that cache as the initial apollo state because this component is run within the special underscore app we have access to the page props initial apollo state that we pass to our use apollo function which generates a new instance of of apollo and restores the cache in the client to whatever the server had given us so that's a mouthful it's crazy but i'll show you the result of that if everything worked correctly i can reload the page and notice that i still have my data here but it did not do an http request to the server so if i were for example to just come back here and give this a different name refresh the page because it doesn't have that initial what was it called again initial apollo state it had to go and go back to the server to ask for more data but if we provide that initial apollo state just clear this out it's able to render um without having to go back to the server again so you're all about sort of saving work that your code has to do so that's everything i hope you enjoyed the video i'm just going to link to no i'll push this up in a repo because we did it with typescript and we did it with nexus schema but i will also link to the official apollo example sorry the official official next js apollo example so that you can use that as well as a reference thank you very much take care bye
Info
Channel: Leigh Halliday
Views: 12,930
Rating: 4.9735684 out of 5
Keywords: nextjs tutorial, apollo tutorial, apollo client v3, apollo server nextjs, apollo nexus schema, apollo client ssr, apollo nextjs
Id: y34ym0-KZ8A
Channel Id: undefined
Length: 30min 52sec (1852 seconds)
Published: Mon Aug 17 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.