tRPC - Move Fast and Break Nothing

Rate this content

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

26 min
14 Apr, 2023


Sign in or register to post your comment.

AI Generated Video Summary

TRPC is a tool that simplifies API development by allowing you to call functions in the backend and have the type data inferred into the frontend without code generation. It provides type safety and auto completion when querying databases using Prisma. TRPC can be used with various frontend frameworks and has features like automatic batching and middlewares. It can be shared between repositories using a monorepo or by publishing the types as an npm package. TRPC is easy to set up compared to gRPC and provides built-in input and output validation.

1. Introduction to TRPC and API Development

Short description:

I'm really happy to be here to talk about my baby, TRPC. It's really growing a lot. But I want to ask like, who here have used TRPC? A bit about me. I started doing websites using Microsoft Frontpage. And then I moved to Node.js mainly in 2011. PHP for me has always been a bit like a northern star in DX. Ever since I moved from PHP, you have to work with APIs. We spend a lot of time arguing about what is the right shape of the data. And just look at how we do an API today. 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, we'll be using JavaScript probably both on the front and on the back end.

So, welcome. I'm really happy to be here to talk about my baby, TRPC. 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? OK. All right. Hopefully a bit more after today.

So, a bit about me. Here is 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. 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 in 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 when you do like native apps, I worked with that as well. You have to work with API. So I feel like whenever you build or consume APIs, it's a pain we we spend a lot of time doing an API 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 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, that your API confirms to the specification and in 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, this 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, we'll be using JavaScript probably both on the front and on the back end.

2. Calling Functions and Querying Databases with TRPC

Short description:

So in TRPC, you can call a function in your backend and have the type data inferred into your frontend without code generation. You can set up a router, define a procedure, and use type-safe validators like Zod. TRPC allows you to build type-safe APIs easily without schemas or code generation. You can also query a database using Prisma and get auto completion and type safety in your frontend.

So why not just be able to like call a function rather than going through all these steps to have a type 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 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 that a bit more involved example. Here we have a full a full Node.js server using TRPC. In the top we import some dependencies, we set up TRPC, router and an end point or procedure or function. I'll be, I'll be using like the words endpoint procedure and function a bit interchangeably in this talk. And then at the end, we start up 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, so what we do here is that we set up a router in TRPC, we defined a procedure and point function called greet. We say that this takes an input argument that is a string using a type, a type safe validator called Zod. And then we say that we, this one, 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 front end, 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 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 or M for TypeScript to query our database, get some fields out and return that post. What you get straightaway in the front end 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 that type safe result straight from the database. If you change anything here you will have it updated straight away in your front end. To show you some live coding, I recorded a video just before this talk today because live coding on stage is a bit risky.

3. TRPC Starter Application and Type Safety

Short description:

Here we have a TRPC starter application where you can look at a few posts, add a post, and view the post. The focus is on the page and how it works. In the Next application, the pages folder contains the React component for the post ID. The query for the post by ID provides a type-safe response from the database. Clicking on the React hook takes us directly to the backend function. Editing the database return immediately shows type errors on the frontend.

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 back end 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 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 that 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.

4. Benefits of tRPC for Collaboration and Development

Short description:

And with tRPC, you can have better collaboration between backend and frontend teams. tRPC is not tied to React or Node.js and has no dependencies. You can use it in demo, Svelte, React Native, and there's no build steps. It provides magical type safety for full stack web and mobile development. It can be used as a backend for frontend frameworks and for service to service communication. tRPC has features like automatic batching, middlewares, and request context.

And I think I'll jump over the last part of this demo. And so who here uses TypeScript? Yeah, everyone. Great. I don't need to convince you that. Like 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. And I really think that less is more, like 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 like a lot better collaboration between your backend and the frontend teams, because all you need to do to like understand what's going on is just like it's just a command click away. There's no complicated architecture on figuring out where stuff is coming from. tRPC is not tied to React or Node.js at all. And there's no dependencies on it. So you can use it in demo. 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 like 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 sort of like magical type safety where you can just like 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 backend for frontend frameworks. As a backend 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, where you do that sort of like gluing together APIs. And also a node, you can use it for like service to service communication. And 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.

5. TRPC Middleware and Ecosystem

Short description:

Here we have a middleware in TRPC that is pretty cool. It allows you to create a protective procedure where you can throw an error if there's no user in the context. By using this protective procedure, you get a type-safe middleware that provides a reliable behavior. TRPC has a large ecosystem with tools like create T3 app, TRPC OpenAPI package, and TRPC Chrome. There are many contributors to TRPC, and companies of all sizes are using it. If you're interested in TRPC and TypeScript, please reach out as we're always looking for more people to contribute.

And I'll show you a bit more a bit, 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, is this behavior here where when you define a procedure, you'll know that the context, you 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, type safe middleware that goes for you end I don't know why it goes into sleep mode. And as it's getting, we're getting a really large ecosystem around here per se as well. Sorry, we're getting a really large ecosystem around here per se. 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. This, for instance, a TRPC OpenAPI package where you can use TRPC as a foundation to make like OpenAPI compliant APIs. And there's like TRPC Chrome for making Chrome plugins. And there's a lot more. You can check it out on the 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 the 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. And so companies using TRPC, you might recognize some of those logos. And 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 ask. Awesome, Alex, thanks a lot. It was a very nice talk. We have a lot of questions. Alright, cool.

6. Sharing TS Contract Between Repositories

Short description:

To share the TS contract between different code repositories, the recommended approach is to use a mono repo like NX, Turbo repo, or Lerna. This allows both the front end and back end to be in the same repository, making it easier to share type information. However, tRPC can also be used with separate repositories by publishing the types of the back end as an npm package. Although this approach may not provide all the conveniences of a monorepo, it is still possible to use tRPC without one.

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 Lerna or something like that to have both the front end and back end in the same in the same repo, because then it's easier to share this sort of type of information. But you can use tRPC with separate repositories as well, but then you need a way to publish the types of your back end 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, command click into the right thing in a package and just update the back end straight away. But it's definitely possible to use it as well without a monorepo.

7. Exposing App Router and Compatibility

Short description:

In a monorepo setup, the best practice to expose the app router to the client is by creating separate packages for the back end logic and the client, where only the type is exported. This ensures that the back end application is not accessible in the browser. tRPC can be used with quick dev $server function, allowing the same API to be reused across multiple applications. Support for bling and similar projects is currently being developed. There are adapters available to use Nest.js with tRPC, and there are discussions on GitHub on how to integrate the two.

Yeah, next one is actually related to that. In a monorepo setup, where the back end is not really exporting anything, what's the best practice to expose the app router to the client? So, what you could do is, you can do a package that is your back end logic, as its own package, and then you have applications using both your front end and your back end. And, 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 back end application never ends up in the browser, where someone can just read that source code.

Awesome. Yeah, next one. Maybe you would know how to answer that. How does that compare to quick dev $server function? I mean, quick... I think tRPC works with quick dev $server function. I've seen someone doing a proof of concept with that. With quick, it's very bare bones, right? You basically have a callback function with a handler. And yeah, it's 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 tRPC within the context of quick callbacks 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 that supported there? I know people have used it. I'm not. I've not used Nest.js much myself. But I know there are some people that have done adapters work to, to use it. So I think if you Google like Nest.js, gRPC, GitHub, there's a bunch of, there's a, I know there's a GitHub discussion where there's a lot of like findings on how to use it with Nest.js.



Short description:

Why do you think gRPC hasn't gathered much interest? TRPC is easy to set up compared to gRPC, as it doesn't require writing interfaces or schemas. TypeScript syntax is sufficient for contract definition in TRPC. TRPC provides built-in input and output validation, supports various input validators, and allows custom serialization of JSON. TRPC can be used in native mobile applications with React Native or Expo. For clients in other languages, the TRPC Open API package can be used to generate an Open API compliant spec. Tooling for generating TRPC clients in other languages is being developed. The motivation for building TRPC was to scratch the creator's own itch after using GraphQL for several years.

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 gRPC has never gathered much interest? Pardon? What do you, why do you think Corba other protocols, I like RPC protocols, RMI gRPC has never gathered much interest in your opinion? I mean, gRPC is pretty big, right? I think it's pretty well known and used by a lot. But I mean, the fact why tRPC specifically, I got them so much interest is probably because it's so easy to set up compared to like gRPC where you have to do like the proto, proto buffstep spec and everything with gRPC. 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 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 you look for? Like TRPC is already more flexible than, for instance, OpenAPI 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 JSONs. So you can just use all the built-in JavaScript objects like maps, sets, and dates, and it will automatically be serialized and deserialized over the wire.

Got it. Do we have inbuilt validation in TRPC? I think you showed that. 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 Jup, and you can do your own input and output validators if you like that. I don't know why anyone would do that.

So, 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. Yeah, I've got one. How about native mobile applications? I'm not sure which slide is that referencing to. So, native mobile is a fun one, so if you're using React Native or Expo, you can just use our, you can 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 compliant 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 next few months or 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 edge, like I I've used GraphQL for like five, six years.

Motivation for Building TRPC

Short description:

Ever since GraphQL came out, I've been a big fan. But when building my own company's web application, I didn't need the full flexibility of a GraphQL backend. I was contributing to BlitzJS, which has a similar RPC concept, but I wanted a simpler RPC layer. When I discovered that I could achieve this without code generation, I was thrilled.

Ever since it had come 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 BlitzJS 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.

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

React Day Berlin 2022React Day Berlin 2022
29 min
Get rid of your API schemas with tRPC
Do you know we can replace API schemas with a lightweight and type-safe library? With tRPC you can easily replace GraphQL or REST with inferred shapes without schemas or code generation. In this talk we will understand the benefit of tRPC and how apply it in a NextJs application. If you want reduce your project complexity you can't miss this talk.
GraphQL Galaxy 2022GraphQL Galaxy 2022
16 min
Step aside resolvers: a new approach to GraphQL execution
Though GraphQL is declarative, resolvers operate field-by-field, layer-by-layer, often resulting in unnecessary work for your business logic even when using techniques such as DataLoader. In this talk, Benjie will introduce his vision for a new general-purpose GraphQL execution strategy whose holistic approach could lead to significant efficiency and scalability gains for all GraphQL APIs.
React Advanced Conference 2021React Advanced Conference 2021
20 min
Advanced Patterns for API Management in Large-Scale React Applications
In this talk, you will discover how to manage async operations and request cancellation implementing a maintainable and scalable API layer and enhancing it with de-coupled cancellation logic. You will also learn how to handle different API states in a clean and flexible manner.

GraphQL Galaxy 2022GraphQL Galaxy 2022
22 min
Handling Breaking Changes in GraphQL
Requirements change, but API contracts are forever - I wish! A breaking change is something that is not backwards compatible. This means that a consumer of your API would not be able to use the new version without making a code change themselves. We avoid breaking changes if possible, but there are cases when they are inevitable. It could be something small: like making a mandatory field optional. Or it could be something big: like removing a query or a mutation. In this talk we'll review the types of breaking changes you may encounter and how to deal with them gracefully.
JSNation 2023JSNation 2023
28 min
APIs are Evolving. Again.
As developers we stand on the shoulders of giants, and it can be helpful to take a look at the past to gain a better perspective. In this talk we’ll briefly explore the past decade of backend development and architectural patterns.
We’ve often ditched technologies in an attempt to make the developer experience frictionless. However we sometimes forget what we can learn from “the good old days”.
What are you building: a monolith, a microservices system or something in between? A shift in how we see things can help us keep moving forwards.
Node Congress 2021Node Congress 2021
29 min
Safely Handling Dynamic Data with TypeScript
TypeScript makes JavaScript safer adding static type definitions. Static definitions are wonderful; they prevent developers from making trivial mistakes ensuring every assignment and invocation is done correctly. A variable typed as a string cannot be assigned a number, and a function expecting three arguments cannot be called with only two. These definitions only exist at build time though; the code that is eventually executed is just JavaScript. But what about the response from an API request? In this talk Ethan Arrowood, Software Engineer 2 @ Microsoft, he will cover various solutions for safely typing dynamic data in TypeScript applications. This talk features popular technologies such as Fastify, JSON Schema, Node.js, and more!

Workshops on related topic

GraphQL Galaxy 2021GraphQL Galaxy 2021
48 min
Building GraphQL APIs on top of Ethereum with The Graph
The Graph is an indexing protocol for querying networks like Ethereum, IPFS, and other blockchains. Anyone can build and publish open APIs, called subgraphs, making data easily accessible.
In this workshop you’ll learn how to build a subgraph that indexes NFT blockchain data from the Foundation smart contract. We’ll deploy the API, and learn how to perform queries to retrieve data using various types of data access patterns, implementing filters and sorting.
By the end of the workshop, you should understand how to build and deploy performant APIs to The Graph to index data from any smart contract deployed to Ethereum.

React Summit 2022React Summit 2022
147 min
Hands-on with AG Grid's React Data Grid
Get started with AG Grid React Data Grid with a hands-on tutorial from the core team that will take you through the steps of creating your first grid, including how to configure the grid with simple properties and custom components. AG Grid community edition is completely free to use in commercial applications, so you'll learn a powerful tool that you can immediately add to your projects. You'll also discover how to load data into the grid and different ways to add custom rendering to the grid. By the end of the workshop, you will have created an AG Grid React Data Grid and customized with functional React components.
- Getting started and installing AG Grid
- Configuring sorting, filtering, pagination
- Loading data into the grid
- The grid API
- Using hooks and functional components with AG Grid
- Capabilities of the free community edition of AG Grid
- Customizing the grid with React Components
Node Congress 2022Node Congress 2022
98 min
Database Workflows & API Development with Prisma
Prisma is an open-source ORM for Node.js and TypeScript. In this workshop, you’ll learn the fundamental Prisma workflows to model data, perform database migrations and query the database to read and write data. You’ll also learn how Prisma fits into your application stack, building a REST API and a GraphQL API from scratch using SQLite as the database.
Table of contents:
- Setting up Prisma, data modeling
- Exploring Prisma Client to query the database
- Building REST API routes with Express
- Building a GraphQL API with Apollo Server

GraphQL Galaxy 2021GraphQL Galaxy 2021
175 min
Building GraphQL APIs With The Neo4j GraphQL Library
This workshop will explore how to build GraphQL APIs backed Neo4j, a native graph database. The Neo4j GraphQL Library allows developers to quickly design and implement fully functional GraphQL APIs without writing any resolvers. This workshop will show how to use the Neo4j GraphQL Library to build a Node.js GraphQL API, including adding custom logic and authorization rules.
Table of contents:
- Overview of GraphQL and building GraphQL APIs
- Building Node.js GraphQL APIs backed a native graph database using the Neo4j GraphQL Library
- Adding custom logic to our GraphQL API using the @cypher schema directive and custom resolvers
- Adding authentication and authorization rules to our GraphQL API

React Advanced Conference 2022React Advanced Conference 2022
206 min
Best Practices and Patterns for Managing API Requests and States
With the rise of frameworks, such as React, Vue or Angular, the way websites are built changed over the years. Modern applications can be very dynamic and perform multiple API requests to populate a website with fresh content or submit new data to a server. However, this paradigm shift introduced new problems developers need to deal with. When an API request is pending, succeeds, or fails, a user should be presented with meaningful feedback. Other problems can comprise API data caching or syncing the client state with the server. All of these problems require solutions that need to be coded, but these can quickly get out of hand and result in a codebase that is hard to extend and maintain. In this workshop, we will cover how to handle API requests, API states and request cancellation by implementing an API Layer and combining it with React-Query.
To make the most out of this workshop, you should be familiar with React and Hooks, such as useState, useEffect, etc. If you would like to code along, make sure you have Git, a code editor, Node, and npm installed on your machine.