tRPC - Move Fast and Break Nothing


How, why and how to use tRPC by the creator of it


So, welcome. I'm really happy to be here to talk about my baby TRPC. And yeah, my baby is really growing up. Like, right now we have over 24,000 stars on GitHub, closing in on 200,000 weekly npm downloads, and there's no signs of slowing down. It's really growing a lot. But I want to ask, like, who here have used TRPC? Okay. All right. Hopefully a bit more after today. So, a bit about me. Here's me at my first mob programming session at the age of eight or nine, maybe. Around this age as well, I started doing websites using Microsoft Frontpage. And then I started with this sort of, like, LAMP stack, PHP, and MySQL, you know. And I moved to, like, node.js mainly in 2011 or something like that. And PHP, for me, has always been a bit like a Northern Star DX. I really loved the simplicity of just being able to, like, call a database query next to your html and just render it. And did it go blank? Okay. Technical issues. Okay. It sleeps if I don't touch it in a while. So I'll speed up. But yeah, ever since I moved from PHP, you know, you have to work with the APIs. When you do, like, native apps, I work with that as well. You have to work with APIs. And I feel like whenever you build or consume APIs, it's a pain. We spend a lot of time doing api specifications. We spend a lot of time arguing about what is the right shape of the data. And we have a lot of different fragmented tooling to deal with it, both on the back end and the front end. And just look at how we do an api today. So, today, usually when you start with making an api, you start with a specification. Because you want to have, like, a contract between your back end and front end, so you know how the shape of your data should look like. And then, hopefully, you have some code generation in order to have a sort of type safe or safe environment to work with on the back end, where you validate that your api confirms to the specification. And there you write your actual business logic as well. And then, on your front end, you write in the case of graphql, you write graphql query. And then you wait for some more code generation. And then you get a nice, like, in the case of react, a nice hook at the end that you can use. And I just feel like this quite a few, there's too many steps on this. So, I wonder if we could just make APIs as easy as calling a function. Because a lot of us here today, we're all Node people, like, we'll be using javascript probably both on the front end and the back end. So, why not just be able to, like, call a function, rather than going through all these steps to have a type, the type thing to just call and get some data or write some data. So, how do you do the same thing in tRPC? The first thing you do is to write a back end function. I'll go a bit more into this. It's a bit small. And then you use that back end function. So, all you need to do is to define a function in your back end. All the type data gets inferred straight into your front end without having any code generation or any extra steps. Let's look at a bit more involved example. Here we have a full node.js server using tRPC. At the top, we import some dependencies. We set up tRPC. We create the tRPC router and an endpoint or a procedure or a function. I'll be using, like, the words endpoint, procedure, and function a bit interchangeably in this talk. And then at the end, we start an HTTP server. What I want us to focus on is this part. This is the thing that changes from, like, router to router to endpoint to endpoint. So, what we do here is that we set up a router in tRPC. We defined a procedure endpoint function called greet. We say that this takes an input argument that is a string using a type safe validator called Zod. And then we say that this is a query. And we return a greeting with hello, user. And then here's the magic of tRPC and typescript. We just export our backend as a type. And in the frontend, we use that, we use that, let's see, that type to set up a tRPC client. And straight away, you get auto completion on all of the api routes that you have. You get type safe, type safe outputs inferred straight from your function backend. Note here that you don't declare any types whatsoever. You just get it straight away. What tRPC does is that it allows you to build type safe APIs easily without any schemas or code generation. And again, a bit more involved example. In this one, we are actually querying a database. Here we have a post router where you can query posts by ID. You can query a list, you can query, you can add a post. So here we have a procedure that takes an input that is an object and an ID. And we say that this is a query. We use prisma, which is a type safe ORM for typescript to query our database, get some fields out and return that post. What you get straight away in the frontend then is you get auto completion of all your api routes. You get type safety and input and auto completion on the query. Here I'm using the react library of tRPC. And then you get a type safe result straight from the database. So if you change anything here, you will have it updated straight away in your frontend. To show you some live coding, I recorded a video just before this talk today because live coding on stage is a bit risky. So I'll just show you here. Here we have a tRPC starter application where you can look at a few posts, you can add a post. And if we submit this, we get some validation error from the backend because our text is too short. And then you can go and view that post. So what I want to focus on is this page, how it works. So here we can see we have a next.js application here. And in our pages folder, we have this post slash ID, which corresponds to this react component here. And here we query post by ID. And you see that we have type safe response straight away from our database query. And if I go and command click my react hook, I actually get straight into my backend in this function that I'm defining. So there's no extra steps in that. And if we take this side to side and we edit what we're going to return in our database, we will get type errors straight away on our frontend. So without even saving the file, you comment out that and we get a type error here that we don't return title from our database anymore. And I think I'll jump over the last part of this demo. So who here uses typescript? Yeah, everyone. Great. I don't need to convince you that. typescript is great. You can use it on the backend, frontend, you can use it on mobile. I really love that we can use the same tool everywhere. I really think that less is more. Maybe javascript or typescript is not the nicest language for everything, but it is something you can use everywhere truly. And with tRPC, I think you can have a lot better collaboration between your backend and frontend teams, because all you need to do to understand what's going on is just a command click away. There's no complicated architecture on figuring out where stuff is coming from. And tRPC is not tied to react or node.js at all. And there's no dependencies on it. So you can use it in deno, you can use it in svelte, you can use it in react Native, and it works the same. And there's no build steps either. So you don't have to worry about any webpack magic or whatever. It's just typescript. And you can have your backend and your frontend in two independent packages in a monorepo. They don't have to be deployed together, but you can still get this magical type safety where you can just dive into your backend from wherever you are. And you can use it for full stack web development, mobile development. A lot of people use it for like a back-end for frontend frameworks. As a back-end for frontend framework, if you have a lot of services and you don't want to like stitch together api responses on the frontend, you can do like a slim tRPC layer where you do that sort of like gluing together APIs. And also in Node, you can use it for like service to service communication. Obviously, this is sort of a surface level talk of tRPC, but we have a lot more features on the client. We have borrowed a lot of concepts from graphql. So we have like automatic batching on the backend. We have things that you probably already used to in like Express. So we have like middlewares, we have request context. So like when an HTTP request comes in, we create the context objects of that, that you can use for like user, contextual user information. And I'll show you a bit more, I'll show you a middleware in tRPC that is pretty cool. Here we have, before we talked about procedures, all I'd showed you was public procedures. And here we have a public procedure where we use a middleware. And if the context objects will return a session or a user based on the incoming request. And here we're creating a protective procedure where we throw an error if there's no user in the context. And then we call our next function with the user that is now known to be non-null because we throw in every other context. What we then get when we use this protective procedure is this behavior here where when you define a procedure, you'll know that the context user is set. If we list here, we have this context user that is user or undefined because we're using the public procedure. So just by doing this, you get like type safe middlewares that goes for end to end. I don't know why it goes into sleep mode. And it's getting, we're getting a really large ecosystem around TRPC as well. Sorry. We're getting a really large ecosystem around TRPC. There's obviously create T3 app that is very popular sort of starting point for setting up an application with next.js, Tailwind and NextAuth, et cetera. For instance, a TRPC open api package where you can use TRPC as a foundation to make like open api compliant APIs. And there's like TRPC Chrome for making Chrome plugins and just a lot more. You can check it out on slash awesome. And also I want to take a moment to just like say thanks to these people. If you have a phone, take a photo of this slide and follow these people. They're great. Yeah. There's a lot of contributors to TRPC. It's not only me doing this. Like I've been doing this for a bit more than two years now and I wouldn't be able to be here unless there was like a big open source community. And if you like the looks of TRPC, you like hacking on typescript, please chat to me because we're always looking for more people to help out. So companies using TRPC, you might recognize some of those logos. It's not only like a toy project for the startups. There's a lot of really serious companies using it as well. And yeah, I hope you will give TRPC a go. And if you have questions, please do. Awesome, Alex. Thanks a lot. It was a very nice talk. We have a lot of questions. All right. Yeah. Yeah. Let's begin with the first one. By the way, the order is very random to me. How do you go about sharing the TS contract between different code repositories? So the recommended approach with that is that you use like a mono repo, right? So you use NX that are here or like Turbo repo or something like Learn Now or something like that to have all of the, both the front and the back end in the same repo, because then it's easier to share this sort of like type information. But you can use TRPC with separate repositories as well, but then you need a way to publish the types of your backend as an npm package that you then can import on the front end. And if you do that, you miss some of the niceties where you can, you know, come on, click into the right thing in the package and just update the backend straight away. But it's definitely possible to use it as well without a mono repo. Yeah. And next one is actually related to that. In a mono repo setup, where is the backend is not really exporting anything? What's the best practice to exposing the app router to the client? So what you could do is you can do like a package that is your sort of like backend logic as its own package. And then you have like application using both your front end and your backend using that package. And for the sort of like to make it extra, extra safe, you can do a package for the client where you only export the type. So you can be guaranteed that your backend application never ends up like in the browser where someone can use like read that source code. Yeah, next one, I maybe you would know how to answer that. How does that compare to quick dev dollar server function? I mean, quick, I think TRPC works with quick dev dollar sub function. I've seen someone doing a proof of concept with that. With quick, it's very like, it's very bare bones, right? You basically have a callback function with a handler. And yeah, it's very, very, very coupled to your application. And in TRPC, you can reuse the same api across multiple applications as well. But you can also use like TRPC within the context of quick callback functions. But I have not personally used quick very much. But I guess it's similar to what I've seen with bling and things like that. Yeah, so we're right now working on doing some sort of support for bling and similar projects. Yeah. And how about nest.js? Is it supported there? I know people have used it. I've not used nest.js much myself. But I know there are some people that have done adapters work to use it. So I think if you Google like nest.js, TRPC, GitHub, there's a bunch of, I know there's a GitHub discussion where there's a lot of like findings on how to use it with nest.js. Awesome. Yeah, it's a lot of interesting questions, actually. We have some time to try to answer those. Why do you think CORBA, RMI, TRPC has never gathered much interest? Pardon? Why do you think CORBA, other protocols, I like RPC protocols, RMI, TRPC has never gathered much interest in your opinion? I mean, TRPC is pretty big, right? I think it's pretty well known, used by a lot. But I mean, the fact why TRPC specifically got so much interest is probably because it's so easy to set up compared to like gRPC, where you have to do like the protobuf step spec and everything with TRPC. It's just like, it is called RPC, but you don't have to like write any, you don't have to write these like interfaces or schemas for your communication. It's just magically, I should avoid words like magic, right? But it's just in the typescript compiler. It's just transient living in typescript compiler. There's nothing at runtime that defines your like outputs from your backend, unless you explicitly define that. And you don't have to generate it as well. Yeah, you don't have to generate anything, any types because yeah, the code is the source of truth. Yeah. Is typescript syntax sufficient to cover all data types that are necessary for efficient contract definition? Yes, question mark. I mean, what data types would we look for? Like TRPC is already more flexible than for instance, REST, open api or REST, because with TRPC, you can, for instance, return a data object in your backend and use that data object in your frontend straight away because we have supports to have custom serialization of JSON. So you can just use all the built-in javascript objects like map sets and dates, and it will automatically serialized and deserialized over the wire. Got it. Do we have in-built validation in TRPC? I think you showed that. Yeah, yeah. So we have an input and output validation of your procedures and we support a bunch of different input validators. SOD is the one I always refer to because it's my personal favorite, but it also works with job joy and you can do your own like input and output validators if you like that. I don't know why anyone would do that, but... All right. How good is your Portuguese? Where do you live in Brazil? I mean, it's pretty embarrassing at this point. Like it's four years ago since I spoke it a lot, but it's all right. Cool. Yeah, I've got one. How about native mobile applications? I'm not sure which slide is it referencing to. So native mobile is a fun one, right? So if you're using react Native or Expo, you can just use TRPC the same way. If you want to use TRPC and have clients in other languages that aren't typescript, you probably want to use the TRPC open api package to generate sort of an open api compliance spec. So you can then generate a type safe client on the front end. We are working on tooling for like static analysis of your TRPC backend in order to generate real like TRPC clients automatically and other languages. But it's a bit... It's not coming in the like next few months or like very short term. Okay. If you're looking into the generating approach as well. Yeah. Okay. What was your motivation for building TRPC? Scratching my own itch. Like I've used graphql for like five, six years. Ever since it came out, it was sort of like a eureka moment for me when it came out. I'm still a big, big, big graphql fan. However, I was building my own company at the time a couple of years ago and I was doing this sort of like full stack web application in react and next.js or whatever. And I wanted a backend for that. And it felt a bit silly to make like a full graphql backend for an application that only has one consumer. Like the graphql is amazing and very flexible, but like I don't, didn't really need that flexibility. And yeah, I was also contributing to blitz.js early on that also has a similar RPC idea, but I only really wanted a RPC layer. And once I found out that you can actually do that without any code generation, I just went crazy on like hacking on trying to make something work. Yeah. And it works. Awesome. Do you know, does TRPC work on different js runtimes? Like cloudflare workers? Yeah, it works on like Edge runtimes. We have adapters for Edge runtimes and a lot of different backend frameworks like fastify we have an adapter for, and you can use it in deno. We have some people doing that. So yeah, it doesn't have any dependency. We don't import anything from Node in our backend. So we don't use async storage or anything. Yet I would like to, it would make a lot of things nicer. All right. Well, that was a long Q&A session. I think, yeah, honestly, we have a lot of more questions pending, so I encourage you guys to join the Q&A room and join Alexander there. Thanks a lot, Alex, again. Thank you. And also come talk to me.
26 min
14 Apr, 2023

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Workshops on related topic