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