Get rid of your API schemas with tRPC

Rate this content

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.

29 min
02 Dec, 2022

AI Generated Video Summary

Today's Talk introduces TRPC, a library that eliminates the need for code generation and provides type safety and better collaboration between front-end and back-end. TRPC is demonstrated in a Next JS application integrated with Prisma, allowing for easy implementation and interaction with the database. The library allows for seamless usage in the client, with automatic procedure renaming and the ability to call methods without generating types. TRPC's client-server interaction is based on HTTP requests and allows for easy debugging and tracing. The library also provides runtime type check and validation using Zod.

1. Introduction to API Schema with trPC

Short description:

Today we are talking about how to get rid of your API schema with trPC. There are two main ways to communicate from your server and client: open API and GraphQL. Open API requires learning a new specification, writing case-sensitive JSON or YAML, and generating schema and type script types. With GraphQL, you need to learn a new specification, generate type script types, and dump them into the client. I found a solution in TRPC, a popular library with over 100,000 weekly npm downloads and 60,000 stars on GitHub.

I'm so happy to be here. And today we are talking about how to get rid of your API schema with trPC. So I want to start my talk with schema fatigues. So we have two main way to communicate from your server and client. We have open API, and we have GraphQL. So open API is open API specification, the final language agnostic interface. So you know HTTP verbs like POST, GET, PATCH, DELETE, et cetera, et cetera. And it's a new language to know.

So if you want to use open API, you have to learn a new specification. Then you need to write case-sensitive JSON or YAML. By the way, YAML sucks. And you have to generate your schema, your type script types, every time you change something into the open API documentation.

Let's see the GraphQL part. With GraphQL, it's an open-source data query, manipulation language, again language, and you need to learn new things. So it's a GraphQL format. And you need to learn the new specification, so query, mutations, stuff like that, so on and so forth. And then you have always to generate your type script types. So if you change something in the GraphQL, you need to generate this type and you dump it into the client.

I'm struggling a lot with this kind of things because I'm working in a consultancy company, Flowing, and I found a solution in TRPC, and then I will show you how.

My handle in LinkedIn and Twitter is Giorgio underscore boa. If you want to tweet about this talk and tag me and tag also the conference, I really appreciate.

So let's jump back to TRPC. TRPC is a quite famous library. More than 100,000 weekly npm downloads and more than 60,000 stars on GitHub. So quite popular. Okay. All the library is based on this type of that you can see on the screen. Okay.

2. Implementing TRPC with Next JS and Prisma

Short description:

The library is based on extracting the shape of an object using TRPC. A Next JS application is used to demonstrate the implementation of TRPC and its integration with Prisma. The author router is defined with different procedures for getting a list of authors, adding authors, and deleting authors. The Prisma API is used in the business logic to interact with the database. In the client folder, the TRPC file is defined with the up router obtained from the server folder.

All the library is based on this type of that you can see on the screen. Okay. So here we have an object. My job object with my first name and last name. And with the type of, we are able to extract the shape of this object to get a type. Okay. And now we will show how it works with TRPC.

Here I have a next JS application, a simple one, and I decided to add from scratch TRPC to show you how easy it is to implement it. So I created also a connection with Prisma because TRPC and Prisma are really a big match. Okay. So here we have our schema, Prisma schema is our model, model author, okay, and we have a seed because Prisma can help us with the seed in our database if it is empty. Okay, we have a source folder, and as you may say, know, in pages we have the slash API folder. Inside of API folder we have we need to create a tRPC folder, and inside of a tRPC folder we need to define a file like this one with square brackets, and next for us grab all the query parameters and give us the information. So we need to expose this endpoint. In this endpoint we define from tRPC next with this API, we define our endpoint. In this endpoint we have a few configurations, but the most important thing is this up-router. In this up-router we have the possibility to define many routers. Here we have only the author router and here we have the typeof I mentioned before. So, from this object we are extracting the shape of the object and defining the up-router. This type is really important for the client. And now we will see how. This is my author router and in this author router, I have a few different procedures. So, I define to get a list of authors, I can add authors and then I can delete one, of course. So, this is my business logic and in the business logic, I put the Prisma API. So, Prisma author dot find many or, for example, if I want to add a new author, Prisma author find first and then if it's not present, I will create the record.

Okay, but let's jump to the client. We see before that we are export type up router. So, we are extracting the shape of this router and now in the client folder, we define the TRPC file, and in this file, there is a few configuration, but the most important part is this one create TRPC next with the generic and here we define up router. The up router arrive directly from the folder we saw before. So, server routers underscore app.

3. Using TRPC in the Client Part

Short description:

In this way, we are able to use TRPC in the client part. We can call the add, delete, and list methods without generating any types. We manage the handle delete and handle save, and every time I save and delete, I invalidate the list to refresh it. One cool thing is that TypeScript automatically renames procedures when changed. Interacting with TRPC from the server and client part is a great benefit. Now let's go deep into the library and see how it works under the hood. We define the methods in the TRPC client, and query is a get while mutation is a post.

In this way, we are able to use TRPC in the client part. So, here is our slash index, okay, the own page of our application. We can use TRPC like this, TRPC dot author dot list, but if I remove this list and I press control space, as you can see with TypeScript, we are able to know that I can call the add, delete, and list. And this is so cool because we didn't generate any kind of types to do that, is all of things out of the box.

Okay, so I, okay, great, so as you can see here, we are looking for the authors. Then we manage the handle delete and handle save, and every time I save and delete, I invalidate the list to refresh the list. So we can start our application. Here there are some Prisma codes. Okay. And if we go here, we have this list, and with the save button we save a new author, and then we can delete them. Great. One really cool thing is that if you go into the routers, in the author router, great, and we decide to change the name of the procedure, so let's change this one, we can rename the Add to new, and boom, into the index here, you can see that TypeScript renamed it for me, so it's really great things. But if we decide to, don't do with the renamed symbol, but do it manually, so I remove here head, okay, if we do it manually, like this one, as soon as I move myself into the index, we can see that TypeScript is notify me that something changed under the hood. So it's a really great benefit to interact from your server and client part, and I think this is so cool.

But I want to show you more. Now we are going deep into the library, because I want to show you how it works under the hood. So let me refactor my class. Here, add new, remove, save. So I think now it's okay. So if I go here. Yeah, perfect. If I open the inspect, I place the few breakpoints into the client library of TRPC. Okay, so if I click on this one, great. And I refresh. As you can see here, we are defining, we are into the TRPC client. Maybe you can't see. Maybe yes. Okay, we are inside of the TRPC client, and we are defining the methods. So, query is a get, mutation is a post, of course, because a mutation needs to have some information extra. Okay, if we go on, we did debugger, and we enable this to debug.

4. Understanding TRPC Client-Server Interaction

Short description:

Inside the client, the library triggers an HTTP request with a specific URL structure. This allows the client part of TRPC to call the business logic. When debugging the application, breakpoints can be set in the business logic part and traced back to the library. The OPTS property contains procedures such as list, add, and delete, which are internal functions of TRPC server. The delete procedure includes the underscore def resolver, which ultimately calls the function.

Okay, refresh. Maybe I can, okay. Okay, zoom a little bit. Okay, as you can see, we have use query. This is our internal function, and inside of use query, we have the path, so author.list. If we go on with debugger, we have the mutation, so we have author.add, and also author.delete. Great.

And I want to show you another things from the client. If we go on, here we have the HTTP request, so under the hood, the library is going to trigger an HTTP request, and look at the URL. So as you can see, slash API slash TRCP slash blah blah blah. So author.list is our procedure, and then you have a lot of parameters that Next.js under the hood, grab for us, and then we, the client part of TRCP is able to call our business logic. But how? Let's see in action the client part, the server part.

So if I put a debugger here, and I run, maybe I stop this one, and I run the debugger from the Visual Studio Code, the application, of course, is the same, because it's the same code base. Okay. As you can see here, we have a breakpoint into our business logic part. But if we jump back a little bit, we can go into the library. So here you can see TRCP server, this index dot blah, blah, blah. Okay? So if I refresh the application, I want to show you this particular property. So let's check. Okay. Great. So inside of the OPTS, we have procedures. Inside of these procedures, we have list, add and delete. And this is the internal function of TRPC server. And inside of delete, we have underscore def. And inside of underscore def, we have the resolver. Resolver is a function. We have Webpack stuff. But in the end, the function is our function. So Prisma dot author dot find many.

5. TRPC Server Pros and Cons

Short description:

The TRPC server works by selecting the procedures and running the application. The library has pros like no code generation, type safety, and better collaboration between front end and back end. However, there are cons like requiring a Typescript stack and the need to create more procedures for versioning and selective field selection. To expose the API publicly, the TRPC-openAPI library is used. A summary of TRPC includes the option to use for quick setup and the recognition of companies like Netflix and as users of TRPC.

Select them. Blah, blah, blah. So if I run the application, as you can see, all the flow ends here. So this is how more or less the TRPC server works.

Great. So let's jump back to the slides. To discuss about the pros and the cons of the library.

So pros. No code generation, as you see before. We didn't generate any kind of code about our procedures, mutation and stuff like that. Type safe by default. So we changed the name of the procedure, and TypeScript soon alert us that something is wrong. And then better collaboration between front end and back end. Because we have a big language, because in the back end, we call the add, and in front end the same. With REST API, sometimes the name of the function are different. So now, with this library, collaboration, I think is better.

What are the cons? Typescript stack. So you need to have back end in TypeScript, and front end in TypeScript as well. If you want to have a versioning of your API, or select some particular fields in a model, you want to select only one field, stuff like that, you need to create more procedures. One for version 1, one for version 2, and so on and so forth. And another cons, that is not really a cons. If you need to expose this API to the public, you need to use this particular library. This library is on top of TRPC and it's TRPC-openAPI. So with a decorator, you are able to expose this API in a public and create also the open API documentation.

Great. So, a summary. If you want to start right now with the TRPC, you can use This library bootstrap TRPC application with Tailwind, Prisma, NextAuthentication, and etc, etc. A lot of things to do without manual configuration and it's really cool. Who is using TRPC? Netflix,, but in this particular issue, you can find a lot of company that signed the name to show that they are using TRPC and if you want to try it now, you can go in and you found a lot of resources about TRPC.


Q&A Session: Elon Musk and TRPC Calls

Short description:

During the Q&A session, the speaker addresses the question of whether Elon Musk would approve of more than 200 TRPC calls and how to prevent poor batching. The speaker explains that the answer depends on the context and suggests dividing procedures into multiple services and communicating with them through TRPC or other channels.

So here I insert a slide to take a picture of you because I need to prove to my wife that I was at the conference. Can you say hi? Hi. Great, great. Thanks. Thank you very much Giorgio. Please come into our Q&A booth.

That was a great talk. I have been a little bit lazy myself learning about TRPC and I'm glad I didn't because now I learned it from you. So that was time well spent. That's awesome. And I think a lot of other people have also learned a lot because we have a lot of good questions here.

And of course we have to start with the first question. It is the Elon question. Okay. Would Elon Musk approve of more than 200 TRPC calls and how do you make sure that they aren't poorly batched? Okay. I think Elon Musk is too pitchy. Let me say. Okay, it depends on your context. You have to reason on the TRPC stack. And if you have a lot of procedures, you need to divide them into many services and then communicate with the services, with the TRPC or maybe other channels. Yeah. Okay. So basically he does not know what he's talking about. Yeah. Yeah. Never, never. Ellie is clapping over there. Yeah, very sad clap. Okay. Let's keep going.

Handling Multiple Repos and Scale with TRPC

Short description:

How does TRPC handle multiple front ends that aren't in a mono-repo with a back-end? It is possible to include TRPC in your application with multiple repos, but it may come with challenges in terms of code refactoring and versioning. TRPC is best suited for microservices and creating multiple services. The advantages of TRPC over Relay, Facebook's relay framework, are subjective. Caching and cache invalidation in TRPC can be handled using React query, and TRPC also offers batching for multiple calls.

This is a question I actually also was thinking about. Like how would you handle a situation where you have multiple front ends that aren't in a mono-repo with a back-end, right? Is that something TRPC can support or is it only for that sort of like back-end for front-end architecture?

Okay. So you have a mono-repo with a ... You don't have a mono-repo. Don't have a mono-repo. So you have a client in one repo and you have a server in another repo. How do these two things keep in sync and how do they communicate? Okay. This is a really great question. Unfortunately, I have the answer. So you can ... If you have multiple repo, you lose the refactoring feature, of course, because you have the code base in two different parts. But if you encapsulate the type of the router inside our library, you are able to include that library in the client. But in the end, you will struggle with versioning things and stuff like that. So you can do it. Would you recommend it? I think the full stack TypeScript is the best approach. But if you want to include tRPC in your application with multiple repo, you can do it.

Next question is a question of scale, as always. Can tRPC work for large-scale applications, especially monoliths? Or is it best suited for smaller apps and microservices? I think it's best with microservices and create multiple services. There are some POC from the author of tRPC that is showing how to integrate multiple services to communicate and create microservices architecture. That's cool.

There's a question. What are the advantages of tRPC over Relay, specifically, Facebook's relay framework? Have you used that and do you know what the advantages might be? No. Yeah, that's a tricky question, I think. Relay is one of those things where the people who love it truly love it and everybody else doesn't understand it. So talk amongst yourselves, find yourself a Relay buddy and convince each other to use it. I don't think I have answered this question either.

It's a Elon Musk question. How do you deal with caching and cache invalidation of entities in tRPC? Is it built in or do you have to do it yourself? Hander De Hoody is using a React query so you can grab all the features of a React query. Also a cool feature about tRPC is the batching. So if in one second you fire a lot of calls, Hander De Hoody is batching them to create cool stuff.

Q&A: tRPC Conflict Resolution and Use Cases

Short description:

tRPC handles conflict resolution in the business logic by checking the existence of primary keys before creating new entries. The tRPC client is dependent on the tRPC server and is used to call the trpc endpoint. While tRPC is a powerful solution in certain contexts, REST API and GraphQL may be better options for exposing public APIs and handling multiple clients with specific property requirements. tRPC is not a replacement for REST API or GraphQL, but rather a suitable solution in certain scenarios.

Nice. Let me just see, there's a couple more questions, maybe let me just get them through the moderation and then we'll read them together. Here we go.

Does tRPC handle race conditions when multiple people hit the API to perform the same action? Or are things like that offloaded to Prisma? So basically I think the question is about conflict resolution. The conflict resolution is inside of your business logic. As I showed before, if I want to create another author with the same last name, last name for in this case is the key, the primary key, you need to check before if the primary key exists or not. And then, if it exists, throw an exception. All right.

This is an interesting question. So tRPC for clients only? Does tRPC have any use if you don't actually have a server component? There's not much you can do with it, right? I think no. No. So, the tRPC client doesn't make sense without the tRPC server. Because it's calling the trcp, trpc endpoint, and no. Yeah. By the way, tRPC, it's a hell of a mouthful to say. So RPC is a remote procedure calls. But what's T for? Is it TypeScript or types? TypeScript, I think it's TypeScript RPC. Because RPC is calling a function of another server. I misspell trcp, trcp a lot. It's a mess. Yes.

All right. Well, let's get into our hot topic, hot potato issue. Do you think GraphQL or REST is better than tRPC in some cases? Are there cases where tRPC is not going to be the right solution and GraphQL or REST would be a better approach? Yeah, I'm smiling. Because I know the answer. Okay? In some context, tRPC is so good. But if you need to expose with a public API, maybe REST API is better, GraphQL as well. If you have multiple clients, like let me say TV, mobile, and frontend application, and you need to grab some property from a model, maybe GraphQL fits better for you. So there are many use cases to use GraphQL and OPA API as well. This won't be a replacement for them, so it can be a good solution in some contexts.

TRPC Runtime Type Check and Validation

Short description:

TRPC provides runtime type check and validation of data coming into the API using libraries like Zod. Zod has gained popularity in the TypeScript development world for its user-friendly API.

Nice, yeah. Always use the best tool for the job. There is no one silver bullet or magic hammer. And always it depends. It depends, of course. Does TRPC provide a runtime type check or the validation of data coming into the API? Yeah, this is a part that I need to skip for the timing. But when you call a mutation, you have in the input object of course, if I want to add an author I need to pass first name, last name, and in this case, the country. And then you have Zod and many other libraries for validation the input, and throw an exception and notify you that you are passing something wrong. So Zod is at the base layer for TRPC and there are many other validation libraries that can be useful in this case. It's incredible how much Zod has taken really like the TypeScript development world by storm because there's been libraries for this forever but I think Zod just gets something right about the API. It's just so friendly to use. It's really amazing. It's very nice. I use it for everything as well. It's wonderful.

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

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.
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!
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.
React Summit 2023React Summit 2023
28 min
Advanced GraphQL Architectures: Serverless Event Sourcing and CQRS
GraphQL is a powerful and useful tool, especially popular among frontend developers. It can significantly speed up app development and improve application speed, API discoverability, and documentation. GraphQL is not an excellent fit for simple APIs only - it can power more advanced architectures. The separation between queries and mutations makes GraphQL perfect for event sourcing and Command Query Responsibility Segregation (CQRS). By making your advanced GraphQL app serverless, you get a fully managed, cheap, and extremely powerful architecture.

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 & migrations- Exploring Prisma Client to query the database- Building REST API routes with Express- Building a GraphQL API with Apollo Server
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.
Prerequisites: 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.
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