Fullstack TypeScript (feat. GraphQL & Node.js) Provider & UI Consuming Data
Transcript from the "Provider & UI Consuming Data" Lesson
>> The next change we're gonna make is wiring up our UI so that it consumes real data. And this is where we're gonna get into the React app, right? This is where we're gonna start making those queries and getting data flowing into that React app. So, the first thing we need to do is we'll be opening our client sub project is we will need to import ApolloClient.
[00:01:15] We don't have to worry too much about n of the exact same request going out within a very short period of time. So those are the imports we need. We're gonna create our ApolloClient, passing a cache into it, so you can do this right below the imports. And then we're gonna create our ApolloProvider, Which is gonna wrap the app component.
[00:01:45] So we're doing this in index.tsx. You could do this in your app.tsx as well, you want this to cover everything else that's within your app or at least wherever you're fetching data. So we can go down here to where our app component is, right down here, and I'm gonna put it within this error boundary component.
[00:02:07] Can someone tell me what an error boundary is in React, if you've used this before? It's like a catch, think of it that way. So if there's a problem that occurs, rendering something, this will intercept it. And its job is to put something on the screen so that we don't have to watch our console quite so much, we can just watch the rendered DOM.
[00:02:33] All right, so there's a ApolloProvider, co-pilot helping me out like a pro. And now what this means is I can use Apollo's hook API to make queries, and that's both the equivalent of a get request and a post request. So we would say queries are for fetching data and then there's something we'll talk about later called a mutation, and that's changing or destroying data.
[00:03:08] So that's all we should have to do in this file. To recap, we imported the Apollo stuff, we instantiated a client with an in memory cache, here's our URL. It's the same one, by the way, that we're hitting for our dev tools. And then down here, we're wrapping our app in the ApolloProvider.
[00:03:34] That's it. So now it's time for us to create our first operation. And this word operation is often used to describe queries that are defined in your code base where you're either fetching data or you're mutating data, but these are things that your API consumer is performing. There's some data in app.tsx.
[00:04:04] In fact, quite a lot of data, so you can see we have our CURRENT_USER, we have an array of TRENDS. We have an array of SUGGESTIONS. So these two things are both in the right sidebar over here. Here's our TRENDS up here. These are our suggestions. Our CURRENT_USER is driving this header area over here as well as the sidebar, right?
[00:04:25] That's like the user's name and their handle. So all of that is sort of loaded with the app. It's like the initial load at the topmost level, cuz there's no routing here, so to speak. We wanna replace these arrays with real queries, and we're gonna first start by asking for the CURRENT_USER and the SUGGESTIONS.
[00:04:50] So before we can make a query, we need to import this GQL utility, which is the same thing that we used for our type definitions in our first setup for Apollo server. It's that tagged template literal where we can define that special string that defines a query in this case, it was the schema before but we could use it for a query now.
[00:05:17] And then this is part of code that will be generated for us, it's a type that defines what we need to pass in and what we can expect back from a particular query. So we can expect this here to error until we generate some code, it's normal for it to error.
[00:05:40] But let's add these to the top of app.tsx. And let me make sure, yep, I was just double checking, I don't have a folder here called generated yet, I want it to fail as it will fail for you. All right, next, it's time for us to make our query.
[00:06:04] So I like to make these all caps, snake case constants, and we're gonna wrap it in this GQL tagged template literal. And you can see here it kinda looks a little bit like interfaces, almost like JSON without the punctuation. You can think of these as, I mean, it's the same stuff that we're passing in here in our tool, right?
[00:06:31] So this is a top level query, and then the fields we want to retrieve, and another top level query and the fields we want to retrieve. What you name it here is not gonna be of great consequence the way we're using things today, but there are things you can do to refer to this later on.
[00:06:53] So let's grab this, add it to our app.tsx, we're gonna put it right down here below of the fixture data. So now that this has been added, we can run our codegen utility. It's the same command, just run it in the client folder. So it's yarn codegen. And you should see some checkmarks, everything's successful, and you should see a new folder has appeared called Generated > graphql.tsx.
[00:07:28] This is a good time for me to talk about, how is all of this happening? So there's a library called, I think it's graphql-codegen, there it is. So this is a project that's doing this generating, and there are config files like this that effectively define where GraphQL stuff can be found and it's capable of parsing these strings from TypeScript.
[00:07:56] And then what do you want generated, so this is what's giving where I'm defining the name of the file, and then these are plugins. So this is gonna define, what is the output? What exactly is operating on the parsed GraphQL stuff? And then that's the exact same way it's working on the server except you can see I have resolvers, right?
[00:08:28] I have operations generated on the client side, I have resolvers generated on the server side. Imagine if you had a mid tier API that had both operations that it was sending to some other back end and resolvers it was using to serve data to someone else that's upstream or downstream, you might have both operations and resolvers in here.
[00:08:51] So that's it. And, I just wanna show you the list of languages that are supported. A lot of TypeScript, React, you can have it wired up for Vue, or Angular, C#, Java, you can use it to generate flow types. So this is a great compatibility layer, if you're migrating from flow to TypeScript or back, so it's quite flexible.
[00:09:28] So now that that's generated on our front end, this import that we had up here, it is no longer causing a problem, in fact, it's got a really complicated type coming back. That's a complicated type we didn't have to write, but let's look at exactly what's happening here.
[00:09:47] So it looks like this is a function. So it's not strictly a type. This is actually a function that's returning something, and it's saying Apollo.useQuery, and it's passing in a query of some kind. And it's got GetCurrentUserQueryVariables. So here's the query, here are the variables passed to this query.
[00:10:08] These might be thought of as the the query params or the path params that you'd put in a URL for a REST API call of some sort. And then we have a return type, which is, sorry, it's actually gonna be inferred based on what Apollo.useQuery returns. So this is the codegen looking at the schema, understanding what does this query need, what do we expect to get back?
[00:10:42] Let's put it into action. So inside the component, we're gonna invoke this hook, useGetCurrentUserQuery. And you may wonder, if you've used React hooks before, use state, use effect, things like that. Often you'll pass something into this, but this is something that's already pre-baked for us. It's part of the generated code, it has that query baked in, it has the right type associated with it, it's all ready to go.
[00:11:09] What we get back are three things, we get loading, error, and data. So these let us conditionally render something if this request is in progress, if something went wrong. And if this is a nullable type, there's always a possibility that no data will be returned. So for now, we're just gonna emit cursory things.
[00:11:35] We're gonna return cursory things from the component if we run into those situations. And that will let us get to this point where we'll use the structured assignment to pick out data like the currentUser and the array of suggestions, we'll grab that from the response payload. So I'm gonna grab this and post it into my component before the return.
[00:11:59] So that will go down here, right here. And now we have to use this data somewhere, but if we look at this, we can see, hey, look at those nice little types coming through. Nowhere have I said that there's this avatar URL or anything like that. But it's all coming through, this is all based on our GraphQL schema.
[00:12:26] So I'm going to start to pass this data into our components. So here's the first one, just replacing this red line with the green line below it, that is right here. Now the reason I'm doing this is, we haven't handled everything that's on our fixture data for the CURRENT_USER, in particular there's this favorites thing, and we don't have that yet.
[00:12:55] So I'm gonna need to do basically an object to sign, kinda merge these things together. I'm gonna keep fixture data in there but I'll override it with real data for now, we'll get a mix, so we can save that. And then the other place we can use this is suggestions, and this we should be able to replace outright.
[00:13:16] So right bar, actually here. Suggestions, there we go. And I think this means, can we delete SUGGESTIONS? We can, it's not used anymore, fixture data gone. Now we'll know this works, if you recall we had one suggestion of who to follow before, we should see more than one.
[00:13:42] And we do, here's jQuery's Twitter account showing up. So now for the first time we have real data coming in and we're seeing real suggestions. Other data is being used as well, you see John Doe up here. It used to say student, but now this is from the fixture data on our back end.
[00:14:05] So this is now coming through our GraphQL API. And we can see in our Network tab if we like, see this in action just to round it out. Here it is. There's that GraphQL request and response. Sorry, it is a post request, of course. So here's the request payload, and you can see, we have an operation name, we have the stringified query.
[00:14:30] This looks a lot like, I'm gonna highlight the one below it, cuz it's easier to see. This here looks like, This query GetCurrentUser, currentUser. query GetCurrentUser, so there it is, it's just literally that string. And here's the response we get back, data, there's currentUser, there's suggestions. So this is how things are working behind the scenes.
[00:14:58] We don't need to worry about much of this because it's all happening between Apollo client and Apollo server. So great, now we're at a point where our UI is consuming real data.