YouTube Transcript:
tRPC vs oRPC: Typesafe API battle!
Skip watching entire videos - get the full transcript, search for keywords, and copy with one click.
Share:
Video Transcript
Now we got two competing standards for
type safe remote procedure calls or RPCs
in your Nex.js or NestJS or Tanax
application. It's TRPC and ORPC. So in
this video we'll compare those things
and we'll develop this handy grid that
you can use to choose between raw API
requests, server functions, TRPC or
ORPC. Let's get right into it. Right.
Right. [Music]
[Music]
The first one we're going to take a look
at is TRRPC. And to do that, we're going
to go and create a Tanstack start
application. And to do that, we're going
to use create start app. This is an
application I run. This is a CLI
builder, and it just happens to have
configurations for TRPC and ORPC. So,
let's give it a go. So, I'm going to
call this one TRPC test. And
importantly, down in add-ons, I'm going
to select TRPC. I'm going to bring that
up in my editor. Now, let's fire that up
and have a look. All right, so here's
our app. And what we're going to do is
we're actually going to build this up.
We're going to start looking at raw API
access. So, post and get endpoints with
Tanstack query. And then we're going to
look at server functions. Then we're
going to look at TRPC. And then we're
going to look at ORPC because you're
going to see the different layers of
type safety and input validation as we
go through these. And it'll give you
some sense of what your different
options are. And at each point that
we're going to use a to-do. So we're
going to start off with this tan stack
queries to-do list. We have our to-dos
here. We can say, you know, new to-do
and we can add it. And you know, it
looks pretty good. So let's go and see
how this is actually implemented. All
right. So if I go over here to routes,
we can see API demo TQ for Tanacquery
to-dos. We see up at the top some
inmemory to-dos. And then we define our
server route. So, we've got get that
returns the to-dos and then post that
takes the incoming JSON request, gets
out the name from that, just a string,
and then adds that to the list of to-dos
and responds with the new to-do that it
created with a new ID. The corresponding
UI code is just as simple. So, right at
the top of our UI, we have to manually
define the type of the to-do because
that hasn't been defined thus far. And
we need that because we're in Typescript
and we want to use use query and we want
the data coming back from the use query
to be of that type so that we get type
safety. So that's where we use the
generic there on use query and we get
back data which is an array of to-dos.
To go and get that data, we just simply
call that API endpoint that we created.
By default, that's going to be a get and
we return the JSON off of that. Once we
have that data, then we can format the
to-dos. And then to add a to-do, we have
an input field that manages a to-do as
well as a button that calls submit
to-do. So what is submit to-do? So
submit to-do adds the to-do and then
sets it to an empty string. So what is
add to-do? Well, add to-do is a function
that we get back from use mutation. We
get the mutate function. We map that to
add to-do. And then that mutation
function calls that same API endpoint,
but this time with a post to go and add
a new to-do. And then the body is the
string. And once that's successful, then
we refetch the list of to-dos. So really
the important part is that there's no
type safety between these two things. If
the API contract of TQ to-do changes,
then we don't get any notification about
that on the client side. And on the
client side, if we call it in a way that
we don't expect, then I don't know what
happens. In fact, actually, let's wrap
this in an object and and see what
happens. All right. Now, send in an object.
object.
Yeah, boom. Because we get back an
object and then when we try and render
it, it blows up because in React
rendering an object blows up. So yeah,
not going to work. So that type safety
is clearly the first problem with this.
The second is input validation. We're
not doing any kind of validation on that
post request to make sure that what we
expect to come in off that request.json
is what we actually want. And if we
wanted to do that manually, you might
use something like ZOD or Valabot to do
that kind of validation. Here, we're not
doing any of that, and that's why it
blew up. All right, so let's call this
the raw API pattern and talk about what
it supports and what it doesn't support,
and we'll go and normalize that against
all of our other options. So, first off,
does it support TypeScript? It does not.
Does it support O? Would it support O if
we had this authenticated? Yes, it
would. You'd have to go and manually add
it, but that's basically the same with
any of these solutions. Does it validate
inputs? Certainly not by default. Of
course, you'd have to add that. You do
get complete control over the URL. You
do get complete control of the output of
the API, meaning you can return any kind
of JSON format you want or an HTB stream
or an SSE stream if you want. That's all
up to you. But of course, because you
define it, it's not in any kind of
standardized format like for example,
GraphQL or Open API. All right. So, how
can we improve on this? How can we make
this better? Well, one great way to do
that inside of systems like Nex.js or
Tanac start is to use server functions.
So, let's go take a look at the UI for
server functions. So, if I go over here
to start server functions, tada, we got
another to-do.
Crazy. It's as if somebody thought, huh,
it would be great to be able to compare
these different mechanisms using to-dos.
Amazing. Okay, so all right, let's go
and add another here. Add that to-do.
Easy peasy lemon squeezy. Let's see how
this is actually done. Okay, let's take
a look at the demo start server
functions route. And right at the top
here, we're going to bring in create
server function from React start. That's
how we define server functions. And
we'll use that create server function to
define two different server functions
we're going to use. We're going to use
get to-dos to get the current list of
to-dos. We're going to define that it's
a method get. That's great. So, you can
actually define the HTTP method that you
want to use. And then we're going to
define add to-do. We're going to put
that one on post because we're adding.
And then we get to define a validator.
So we get to define an input validation
flow for this to make sure that we're
getting the right data. And then we're
going to define the handler. And in this
case, the handler is going to read the
to-dos from a file and then push on the
new to-do, write the file, and then
return a complete list of to-dos. That
read to-do function just reads that
to-dos.json file. And then if it doesn't
exist, it goes and puts in some default
to-dos. Okay, let's take a look at how
we're going to use this thing. All
right, so this particular setup of tens
start is serverside render. And so what
we want to do is we want to go and get
those to-dos so that when we render the
page, we actually render the to-dos
right onto the page. To do that, we
define a loader. And that loader is
going to call that get to-dos server
function, get back that data, and then
we can use that data inside of the route
by just saying route. Loader data, and
that gives us back a list of to-dos.
Now, now all the UI stuff is pretty much
the same. So let's just take a look at
submit to-do. This is where we add a
to-do. And it's pretty interesting here.
So if we go and change, for example,
this to an object, well, we know that
add to-do takes a string. So that's
actually going to give us the type
checking right here. So we actually do
have a completely end to end type safe
flow with our server functions. So let's
bring the grid back and we'll add server
functions. So TypeScript, yes, you can
add O support. No problem with that. We
get that input validation. All right.
All right. Well, let's go and actually
go back to the client and see what does
the URL look like and what does the
output format look like. All right. So,
if I add one more to-do, so the URL for
this one is this long conjugation of the
module as well as the name of the
function. We just don't get to control
that. So, we don't get to control the
URL of this endpoint. Nor do we get to
define what the payload is, nor do we
get to define what the response output
looks like. And this is not a
standardized format. This is just
something that Tanstack start does in
terms of how it does its server
functions. It is not compatible with how
Nex.js does its server functions or
other platforms do their server
functions, nor are any of those
interoperable. So there's really no
standards going on here, but it is
incredibly convenient. All right, now
that we take a look at raw API use and
server functions, let's take a look at
TRPC so we can see what advantages it
brings. So we'll start off by looking at
the TRPC to-do. We'll add hello again
to our TRPC to-dos list and we'll take a
look at how this is implemented. So we
got our demo route right up here at the
top and what the demo route is doing is
it's using a combination of React Query
and TRRPC. In fact, in this case, TRPC
is basically built on top of React
Query. So our loader which is getting
our to-dos at serverside rendering time
is calling prefetch query on our query
client to initialize it with the query
from TRPC. So in this case it's TRPC
to-dos list. So where is that defined?
Well, over here in integrations, TRPC
and our TRRPC router has an in-memory
list of to-dos as well as two public
procedures. One for list and one for
add. List is a query that returns
to-dos. And add is a mutation that adds
the to-do. Both of these can be async,
of course, you've got any kind of IO
to-do. In this case, it's just in
memory, so it's not async. And then that
to-dos router is added on to the overall
TRPC router. And you can have as many of
those routers as you want. So you can
create a very sophisticated API here.
And again that type safety is routed all
the way up to the client. So let's go
take a look back at our TRPC demo. For
example, we can see here that the data
coming out of that use query is indeed a
to-do that has the ID and the name as an
array or undefined in this case if it's
not ready. And then our mutation for add
to-do. Well, let's try and add something
to that. So add fuar. And we can see
that we get a typing error because that
add to-do mutation that we defined over
in the router only takes name as a to-do
item. Super great. So I think you can
see why so many people like TRPC. So
let's go and add it to our list of
options and see how it compares
everything else. So first off obviously
TypeScript. Yes. Yes, you can add
protected procedures to give yourself an
O support. It's got that input
validation. In fact, it does all that
for you for free. In terms of
controlling the URL, you get to put that
wherever you want. In the case of this
setup, I put it on API TRPC, but you get
to decide where you want that. And in
fact, with V11, you actually now also
get to define the methods that are used
for setting and posting and all that
stuff. All right, let's take a look at
the request to see how it's formatted.
The output here is super JSON, but
that's because we chose that as the
serializer. You can choose whatever
serializer you want for the output. You
can also have it send back SSE streams
or HP streams. So, it supports all of
that. Now, in terms of standards, I'm
going to say no because out of the box,
it doesn't come with something standards
compliant like say a GraphQL or an open
API. Although, you could add the open
API later with an extension. Now, one
thing that's really interesting about
TRPC is when you think from an
architectural level, you could have one
definition of your TRPC router that's
implemented by say your tens start
application or your next.js application
and then also have a React Native
application that connects to that router
to get those typings
in say a monor repo. You could do that
and I think that's really interesting.
But that would be inside of said one
project maybe inside of you know one
organization with a company. So what if
you want to have RBC endpoints that are
type safe but also are presented in a
standard that can be used by say go or
rust or given to a customer so they can
then connect to your endpoints. Well
that's where our RPC comes in. All
right. So let's create another
So, we'll select ORPC and we'll bring
that one up. And now we see instead of
TRPC to-do, we have ORPC to-do. We can
add another to-do.
There you go. And let's go take a look
at how this implemented. All right, so
let's take a look at the routes again.
We'll take a look at demo RPC to-do.
This time we're bringing in OPC from the
OPC client. I'll show you that in just a
second. But if I take a look over here
at list to-dos for example, we get back
that list to-dos has an array of those
to-do objects. So you can see the strong
typing already. We're doing exactly the
same thing as we were with TRBC where
we're pre-fetching that query for tanac
query. Again, both of these systems are
layered on top of react query. So very
easy to use. Let's go take a look down
at our use query and our use mutation.
So use query there on line 19 is exactly
the same as what we saw in the loader.
What's actually happening is that
because we did that prefetch, it's just
getting that data right away. So when
you're doing the SSR on the server, it's
ready to go off of that loader. And the
mutation is calling RPC add to-do call.
And just like with TRPC, if I add, you
know, foo bar there, we're going to get
an issue because foo is not recognized
as an input to add to-do. All right,
let's go take a look at how the ORPC is
implemented. So over here we got a
directory called ORPC and within that
router. Router brings in two functions,
list to-do and add to-dos. They're from
to-dos. Again, we have an in-memory list
of to-dos. To define a function, you
just chain on top of the OS variable or
OBC server. You give it say inputs if
you have any kind of authentication or
anything like that. You can add use
endpoints. You can also specify a path
as well as a method. And of course, the
handler here where in this case we're
just defining the to-dos. Add to in this
case uses dad to define the input schema
and then has the handler to go and
handle the incoming request. One of the
things that's really cool about this is
if we take a look at the routes. So our
a API RPC route is how everything gets
routed to the RPC system. But there's
also this API dollar. So anything that
comes out API is going to hit this
optional handler and this optional
handler gives you a UI on top of open
RPC. This is super cool. So I navigate
to / API there. I get this full UI that
shows me all of the different methods
that I have. I can invoke them from
here. I can see the different types of
models that I have. This is amazing. And
even cooler, I go back to the top
and I download the open API document.
Oh, this is so cool. Okay, I'm going to
go over here. I get the Tanagc
playground.json file. Going to go over
to my Postman. Going to drop that in there.
there.
Going to bring it in as an open API 3.1
with Postman collection. I'm going to
import that.
And now we can see that I have a the
different Postman endpoints. I hit send,
get back my data.
This is incredibly cool. All right, so
let's talk about how ORPC stands up.
Typescript, yes. O support, yes. Input
validation, yes, you saw it with Zod.
URL control, yes, you get full control
over the URL that you want to use for
each endpoint if you want to, as well as
getting to specify what method you want
to use. in terms of the output is
essentially exactly what you send back.
This is exactly the format of the JSON
we send back. No mutation on that
whatsoever. And if you want to use HTP
streams or SSE event streams, those work
as well. And then as a standardized
format, well, you can see it right here.
We were able to export the schema of our
API endpoints just as easily as that.
bring it into Postman or you could use
use it with Go or Rust or whatever you
want and you get access to your endpoints.
endpoints.
Really great. All right. Well, I hope
this helps you make your decisions
between the different options that you
have raw APIs, server functions, TRPC
and ORPC. Of course, there are other
things like gRPC that I haven't
mentioned here, as well as GraphQL.
There's a lot to think about, but I hope
I've given you enough detail so that you
can kind of get your feet wet. If you
have any questions or comments, be sure
to put that in the comment section right
down below. In the meantime, if you like
this video, hit that like button. If you
really like the video, hit the subscribe
button and click on that bell. You'll be
notified the next time a new blue collar
Click on any text or timestamp to jump to that moment in the video
Share:
Most transcripts ready in under 5 seconds
One-Click Copy125+ LanguagesSearch ContentJump to Timestamps
Paste YouTube URL
Enter any YouTube video link to get the full transcript
Transcript Extraction Form
Most transcripts ready in under 5 seconds
Get Our Chrome Extension
Get transcripts instantly without leaving YouTube. Install our Chrome extension for one-click access to any video's transcript directly on the watch page.
Works with YouTube, Coursera, Udemy and more educational platforms
Get Instant Transcripts: Just Edit the Domain in Your Address Bar!
YouTube
←
→
↻
https://www.youtube.com/watch?v=UF8uR6Z6KLc
YoutubeToText
←
→
↻
https://youtubetotext.net/watch?v=UF8uR6Z6KLc