Connecting to tRPC
Connecting to the tRPC server from the frontend
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Lesson Transcript
[00:00 - 00:14] Now that we have the TRPC server running, let's try and connect to it from our frontend. We'll need to add the TRPC client library and perhaps surprisingly we will also need to install the server library on our frontend.
[00:15 - 00:27] I'm not sure exactly why this is but that is just how it is and you can confirm it in the docs if you want to. So we'll go to our frontend folder and we'll install these two.
[00:28 - 00:40] In addition to that, I'm going to install React Query from TANstack which is something that TRPC has a slight wrapper around. It's a very nice way to access all the TRPC endpoints from React.
[00:41 - 01:06] So I'll install TRPC/client and TRPC/server as well as TRPC/react query and then the original React Query because that is required as well. That's TANstack/react query.
[01:07 - 01:22] Right. And with that in place, let us create in the frontend a little file called TRPC .
[01:23 - 01:33] Oops. This is also almost strictly copied from the docs but let's just go over it quickly.
[01:34 - 01:49] What we're doing here is we're creating an instance of TRPC React using the React Query wrapper. And this is where our app router type comes into play and if you are not used to this, it should trip you up that we're importing it from the backend.
[01:50 - 02:06] So what we're doing here is actually making an import statement outside of the root folder of our project which should be illegal by the TS config which specifies that everything should be in the source folder. However, the reason why this works is that we're just importing the type.
[02:07 - 02:28] So as you know, TypeScript types are being removed when you actually compile to JavaScript. So the two exceptions are classes and enums and because those generate actual JS code, but something like a regular type like this will create no JS code so it will just be deleted when it's being compiled.
[02:29 - 02:40] And that's why TypeScript allows us to import something from wherever we might want on our hard drive. You might argue that we should be using our MPM workspace for this instead.
[02:41 - 02:47] And we could, so that might be something you'd want to change it to. It's really just a matter of preference.
[02:48 - 02:54] This works and this is how they do it in the official docs so that's what I'm sticking to. But I hope that explains it.
[02:55 - 03:13] We're going to create a URL that it will use to find our backend and we're just going to take whatever protocol and host name we're already on so that it works with local hosts when we're developing and if we deploy to some domain, it will go to that domain. We'll stay on the same port and this I might want to change in production as well.
[03:14 - 03:22] But then slash T RPC, that's going to be our URL. And then we create this T RPC client here that has an array of links.
[03:23 - 03:32] And if you're not familiar with links, it's similar to what they do in GraphQL Apollo client and possibly others. It's sort of similar to middleware.
[03:33 - 03:44] This allows you to add some processing to every request, both before and after the response. So you can create logging and authentication and stuff like that in links.
[03:45 - 03:57] The last link has to be what's called the termination link and that's the HTTP batch link for this. So that's just part of the T RPC client library and that takes a configuration which we will just give our URL.
[03:58 - 04:18] So with this in place, we have the T RPC instance which is what we're exporting and then we're also exporting this T RPC client as a named export because we will be using that in a different file. But the T RPC instance is what we're going to be accessing in our components in order to make actual queries and mutations.
[04:19 - 04:30] There's a bit more plumbing code we need to do before we can start using it. So both T RPC itself and React query come with providers that we need to wrap everything in where we need to access it.
[04:31 - 04:47] So if you've done any serious React development, you've probably seen before how you end up with a big Christmas tree of providers outside on the root level. Just a bunch of things that provide context but don't actually render any DOM or anything.
[04:48 - 05:01] I tend to create something called a providers component that wrap all of these and then takes a children property which I will use for my actual app. So let's create a providers.tsx file and do that.
[05:02 - 05:22] I will create a file here and I'm just going to paste this in here. So you can see we create a query client from the React query here and we also have T RPC dot provider.
[05:23 - 05:31] That's the T RPC instance here. So basically we create a T RPC provider and inside of that we create a query client provider and then we supply the children.
[05:32 - 05:51] So the children is what's going to be inside of this provider's component. And the nice thing about isolating this is that often you're going to want to create tests that have similar providers but maybe with marked data and it's just nice to have it in one place where all the providing stuff is.
[05:52 - 06:07] Let's add it to our main dot TSX. So in here we're going to add providers and that's been automatically imported.
[06:08 - 06:18] And you might notice here that we have two things in our Christmas tree already . So you might be tempted to add React dot strict mode into providers as well and I've done that in the past.
[06:19 - 06:32] You can, it works, but you get one tiny and rather annoying warning triangle in the React dev tools if you do because the provider's component itself then won't be in strict mode. Doesn't matter at all.
[06:33 - 06:39] If you feel like doing it, go ahead and do so. But this works as well.
[06:40 - 06:59] Now we specified that the URL should reach the same port as where the front end is, which means that TRPC is going to try to connect to the VIT server instead of our back end. So in order to make that work in development, we are going to proxy the requests that go to anything slash TRPC to go to our back end.
[07:00 - 07:45] So we do that by changing the VIT config here. So we can create a server that takes a proxy and we say that anything that targets slash TRPC is going to actually target our local host slash TRPC and we will need to change the origin and we will rewrite the URLs to remove the TRPC part of the path.
[07:46 - 08:01] We could do this in other ways as well, but let's just do this now. So a reg X that says TRPC to remove it from there.
[08:02 - 08:08] And I need to escape this slash like so. Okay.
[08:09 - 08:19] So now VIT should proxy our requests onwards to our actual local host back end. Okay, so now let's try and actually use TRPC.
[08:20 - 08:37] We already have an endpoint that will return service types, even if it's a dummy endpoint and we have a page called choose type page, which offers all of these service types to the user. So let's change that to actually use TRPC to fetch whichever service types are available from the back end.
[08:38 - 08:51] If we go into the choose type page, we have here an unordered list with two list items in it. So instead of these being hard coded, we're going to change that to be a query.
[08:52 - 09:02] So let's start by creating a query up here. I tend to call my queries Q and my mutations M, at least if I only have one in the component, but that's just my own little convention.
[09:03 - 09:12] You can call them something more specific if you feel like it. And I often do when I have more than one query, but for some reason it tends to be one query per component.
[09:13 - 09:17] And I'm not sure if that's because that's a good pattern or not. That's just how it typically ends up for me.
[09:18 - 09:33] So we're going to be accessing the TRPC instance here that sits in this front end folder. And the nice thing is now that when I hit the dot here, I get suggestions for these are the routes that actually exist on our back end.
[09:34 - 09:40] This is where TRPC really comes into play. So you can see that I have the ping route and the get service type route.
[09:41 - 09:46] And then there's some other utility stuff. But what we want here is the get service types route.
[09:47 - 09:51] So if I call that, oh, sorry, I'm not supposed to call it. I'm supposed to access it as a namespace.
[09:52 - 09:58] And I can say you dot use query. So there's a hook in this namespace called use query.
[09:59 - 10:05] So my queue instance here is now a query instance. And I want to check.
[10:06 - 10:19] So when that has succeeded, then I want to show the list of service types. So Q can also be in a loading state or in an error state.
[10:20 - 10:26] And you should definitely handle both of those as well. For now, we're going to handle those by just simply not showing anything.
[10:27 - 10:33] But when it has succeeded, we're going to want to show the on noted list. So let me just do this.
[10:34 - 10:40] And then we want that to go down to here. I will get rid of this one list item here.
[10:41 - 10:53] And then instead I will use the other one to map over. So in this scope, Q.is success is true, which means that Q.data is going to be well defined.
[10:54 - 11:07] So I can create another piece of our expression here where I map over data. And I can say item.
[11:08 - 11:22] Let's call it service type. And then I'll move this down to here.
[11:23 - 11:32] So you can now see that service type has this type, which is exactly what's returned from our endpoint. So this is what you get from using TRPC.
[11:33 - 11:40] This is where the value is. Not only do you get IntelliSense by hovering over it, but you will also get squ iggly lines and error messages.
[11:41 - 11:49] If you try and access something on this, that doesn't exist. In this situation here, we know that because the query has succeeded and we have, we're mapping over it.
[11:50 - 12:03] We'll know what type each element is. So I can use the ID as a key here.
[12:04 - 12:34] And down here, I can update it so that it will have the value if I wanted to as the ID as well. So if this is equal to the actual service type ID, and then I can change this.
[12:35 - 12:39] So now this isn't hard coded anymore. So we're not sure which value we're going to hit.
[12:40 - 12:49] So let's reach for the target. Then we will use target.value.
[12:50 - 12:56] And you can see here that what comes out of target is always a string and we want to convert it to a number. So we're going to do that first.
[12:57 - 13:06] We're going to change it to a service ID later on, but we don't have that in place just yet. So this is how we're going to do it for now.
[13:07 - 13:25] We should change this ID as well to be, let's make it a template string that says type dash. There we go.
[13:26 - 13:33] Oh, and this should obviously be the name. There we go.
[13:34 - 13:52] We have our choose type page, which should be accessing our back end. So the only thing that's missing now before we can try it out is that we need to start both our back end server and our front end server and have them both running at the same time before it will actually work.
[13:53 - 14:07] We could obviously just do that in two different terminals, but let's just create a script that will turn both of them on at the same time. So let's edit our root level package JSON and add some scripts there.
[14:08 - 14:24] We have these two scripts already, so we'll add another three that I will just copy here. So NPM has a parameter called prefix, which you can use to specify a certain folder that it should run something from.
[14:25 - 14:42] So we're telling it here that when we call the script dev back end, it should run it with the prefix back end and then it should run dev and similar for front end. So dev out here in the root level means that we're going to run dev back end and then a single ampersand run dev front end.
[14:43 - 14:56] And for the front end, we're going to say clear screen false because VIT will normally clear the screen and that's a bit annoying when we have both servers running at the same time. So this will start both servers in one console.
[14:57 - 15:21] I want to give a little hint though, one thing that I tend to do, if you're on some console that has Tmux available, I don't know that Windows does unless you use Sigmund or obviously you can use WSL. But if you're on a Mac or on a Linux machine, you can easily install Tmux and then you can add these two scripts that I add to anything I'm working on.
[15:22 - 15:36] So Tmux, I create one that's called dev B and one that's called dev H and that 's for vertical and horizontal. And basically it just creates a Tmux session with each of these processes running in a split window.
[15:37 - 15:47] One of them is split horizontally and one of them is split vertically. And the reason why I have both of these is that I tend to prefer the horizontal one, it seems to be easier for me to read.
[15:48 - 16:04] But every now and then I have my back end printing out a URL or something and in that case it's nicer to have the vertical one simply because you can click the URL in the terminal. And if the horizontal mode is on that breaks the line and the terminal gets confused about that.
[16:05 - 16:22] So with these in place, I'm going to show you how I run with, let's just say, dev H. So you can see what this does is it spins up this thing called Tmux that you can just go and install, you'll have to find instructions for that online.
[16:23 - 16:36] And then it starts the back end server over here and then the front end server over here. So let's try and go to our local host here and you can see it's already loading and it's already fetching service types one and two.
[16:37 - 16:57] And that's obviously what it said before so we can't actually know that this works but let's see what it says here in the network tab. So it looks like there was a response here with some data and those were indeed the things that we were expecting and we can maybe try and go into our back end index.
[16:58 - 17:19] Sorry, not the back end obviously the app router and try and change this. Service types one and two exclamation point, back end has restarted and we will try and refresh in here and now there's exclamation points.
[17:20 - 17:36] [ Silence ]
This lesson preview is part of the Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
![Thumbnail for the \newline course Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL](/_next/image?url=https%3A%2F%2Fs3.amazonaws.com%2Fassets.fullstack.io%2Fn%2F20240619184857865_KristianDupont_FullstackTypeScriptwithTailwindCSSandtRPCusingModernFeaturesofPostgreSQL_1450.67x816_CoverImage%2520%25281%2529.png&w=3840&q=75)