Introducing tRPC
Setting up tRPC with Koa
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:09] Now that we have a bit of back-end code and a bit of front-end code, it's time for us to connect the two. And as you know, we're going to be using TRPC for this.
[00:10 - 00:25] TRPC is a great framework for creating type-safe APIs, and it works really well when you have a setup like we do with a mono repo, where you control both the back-end and the front-end. It will need an adapter for whichever framework it's running on top of, which in our case is CoA.
[00:26 - 00:31] And those adapters are quite simple, so you can write them yourself. I've done so in the past.
[00:32 - 00:41] But luckily, somebody has made one for us that we're going to use. So let's install the TRPC server component and the CoA adapter.
[00:42 - 01:11] I will go into the back-end folder and install TRPC/server and TRPC-CoA-adaptor . And now that that is installed, let's try and attach it in our back-end.
[01:12 - 01:25] So we go to this index here and we'll import. Hit CoA-metalware from the adapter, let me turn off CoA.
[01:26 - 01:36] And in it, TRPC from TRPC server. So these are the two things that we need.
[01:37 - 01:55] So after our routes here from the regular rest router, we will install the TRPC adapter. And I'm just pasted this from my article here, but basically we create an instance of the TRPC framework, I guess, and then a router.
[01:56 - 02:03] And this router that we're creating right now will just have one procedure. And we'll get back to what procedures and queries and mutations are in a little bit.
[02:04 - 02:13] But for now, we can just say that we have a query called ping and it will respond with pong. And we then create the middleware using that adapter.
[02:14 - 02:23] So this creates a CoA-metalware using our TRPC router and we then in our CoA app use this adapter. So this should set up TRPC.
[02:24 - 02:32] Let's try and run it and see if we can connect to it. I'm in my back-end folder here.
[02:33 - 02:49] So it says server is listening, so at least it's working. Let me create another terminal and see what happens if I try and call this ping endpoint.
[02:50 - 02:58] And you can see I get this JSON out that says result data pong. So that is how TRPC wraps things and we'll get a little bit into that as well.
[02:59 - 03:09] But at least we can see here that the server seems to be working. And you can also see that the logger locks this endpoint just fine because the logger is a middleware that is installed before the TRPC and middleware.
[03:10 - 03:20] So that goes through that just as everything else. Before we move on to creating more advanced endpoints, let's just restructure things a little bit.
[03:21 - 03:41] I'm going to go by the conventions as they're specified in the docs by creating a TRPC folder in the back-end source folder and creating a file called TRPC.ts in there. Let's start by creating this folder.
[03:42 - 03:49] And obviously that should not have an extension. But this file should.
[03:50 - 03:59] So in here we're going to be initializing the TRPC instance instead of out in the index file. And so this is just copied from the docs.
[04:00 - 04:08] This is sort of semi-standard. One thing I want to note here, besides from us creating this instance here, we 're exporting some things.
[04:09 - 04:19] And one of the things to note here is that we're exporting T.procedure as public procedure. So in a normal setup, we would obviously be introducing authentication.
[04:20 - 04:34] And for any endpoint that is only allowed for people who are logged in, we would create something called protected procedure or private procedure or something to that effect. Maybe even an admin procedure if you have the different roles and so on.
[04:35 - 04:42] In this course, however, everything is going to be accessible to everybody, so we're not going to be doing that. But that's just to note why this is called as it is.
[04:43 - 04:54] And that is the thing that we're going to be using for our router. Let me create a file called app router, which is also a sort of semi-standard.
[04:55 - 04:59] And we'll move things from our index here. So this is the router that we're creating right now.
[05:00 - 05:12] It's called TRPC router, but we'll change the name here. And so instead of this, we will import the router that we have locally.
[05:13 - 05:26] And instead of procedure, we'll change this to public procedure and import that as well from locally. Finally we'll export this.
[05:27 - 05:37] And then we will change, we can now get rid of this in the shalization here and change this and import that from there. Get rid of this one as well.
[05:38 - 05:45] And then let's add another endpoint to this. So I'm just going to copy something here and paste it in here.
[05:46 - 05:57] So get service types is a public procedure as well. And it returns an array of objects, which each have an ID that's a number and a name that's a string.
[05:58 - 06:08] And I want to stress here that I'm not specifying types for neither input nor output. And what that means is that TRPC is going to rely on TypeScript to infer the types.
[06:09 - 06:21] And that works perfectly well. So this get service types endpoint is typed so that it returns an array of objects that have an ID, which is a number and a name, which is a string.
[06:22 - 06:37] So you do have Type Safety without being explicit about it, but it does help to be explicit. I personally have a rule that I'm allowed to use inference if a function is sitting within the same file as where it's being called.
[06:38 - 06:51] So utility functions and things like that. But if I'm creating anything that resembles a public API, even if it's just something that's going to be used in other places in the same app, I will be explicit about return types and input types.
[06:52 - 07:00] And there's a little interrule that enforces that that you can go and install in your project. But we're not going to be doing that in this project, but just to mention that it does exist.
[07:01 - 07:07] But this now creates a temporary first endpoint for our service types. We obviously need to connect that to the database.
[07:08 - 07:15] We're going to be getting into that later on. So for now we just get these two services.
[07:16 - 07:25] The last thing I need to do in here is to export the type of the app router. And you'll be see when we get to building the front end, you'll be seeing why this is necessary.
[07:26 - 07:39] So for now I'll just use this. So this specifies that the app router, which is with the capital A, is going to be the type of the app router.
[07:40 - 07:42] And that we will be able to access from the front end.
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)