Video Summary and Transcription
This Talk explores the evolution of RPC and its relevance in modern full stack development. It discusses the limitations of SOAP and REST and introduces GraphQL as a solution. The focus is on RPC frameworks like tRPC and BlitzRPC, which provide end-to-end type safety and improved developer experience. The Talk also highlights the advantages of RPC in the context of full stack development with frameworks like Next.js. Future improvements for RPC libraries are discussed, including enabling server APIs for multiple clients and creating a developer experience tool combining the best features of BlitzRPC and tRPC.
1. Introduction and Sponsor Acknowledgement
Hello everyone, welcome back here in Berlin and welcome back on the live stream if you're watching from home. We are about to introduce our next speaker, Alexander. Thank you Callstack for sponsoring. Callstack is a team of React and React Native consultants and developers with core contributors on board. Thank you also to Brintem who helped the world stay on schedule with its JavaScript widget library. Now, without further ado, we're gonna invite Aleksandra on stage. Aleksandra is a software engineer and she's based in Wroclew in Poland. She's a full stack developer. She's worked on Elixir, Golang, Python, and TypeScript. Thank you very much. Let's give a big applause to Aleksandra Stikora. Welcome, everyone.
Hello everyone, welcome back here in Berlin and welcome back on the live stream if you're watching from home. We are about to introduce our next speaker, Alexander, in just a second, but before that, just say a couple of words about our wonderful sponsors.
Thank you Callstack for sponsoring. Callstack is a team of React and React Native consultants and developers with core contributors on board. I have personally worked with them, and they are wonderful people. Thank you also to Brintem who helped the world stay on schedule with its JavaScript widget library. The UI toolkit contains scheduling, Gantt chart, and datagrid components. Visit Brintem in their booth over here for a personal demo or if you're at home, go to Brintem.com.
Now, without further ado, we're gonna invite Aleksandra on stage. Do remember to ask questions on Slido. So if you go to Slido.do and you use the code 0212, you'll be able to ask questions that will then ask Aleksandra here on stage live. Aleksandra is a software engineer and she's based in Wroclew in Poland. She's done a lot of things. She's a full stack developer. She's worked on Elixir, Golang, Python, and TypeScript. She was previously tech lead for the Hasura console and very recently been working, being the lead maintainer of Blitz. Thank you very much. Let's give a big applause to Aleksandra Stikora. Welcome, everyone. Thank you for the introduction.
2. Exploring the API Layer and RPC
Today, I will focus on building full stack React applications, specifically the API layer. APIs act as bridges for communication between client and server applications, solving problems such as boilerplate code, type safety, and error handling. Tools like TRPC and BlizRPC offer solutions to these challenges. To understand their approach, we'll explore the history of RPC, which is the foundation of web services. RPC, or Remote Procedure Call, was coined by Bruce J. Nelson in 1981. Let's dive in!
So my talk today is take a rest from rest. So you're probably wondering what happened here, yeah. What's this talk about? So I'm going to focus on building full stack React applications, but specifically I want to talk about the API layer because it's for me it's like super exciting what's going on in the full stack web development. We have new Next.js with React server side components. We have tRPC becoming super popular. We have Remix that is growing and it's been recently acquired by Shopify. So there's a lot going on around the API layer around building full stack applications.
So before I start, I want to explain. Yeah, there is a meme. I want to explain what an API is. So in a distributed programming world, when we have computers that have to communicate with each other, for example, we have client application, server application, or different servers that have to talk to each other, we need a bridge that allows that communication and an API is that bridge. So why are we talking about this? Because a common scenario for a full stack application is that you have a database and the client and the client has to access this database. But even if your database was publicly accessible, you can't call it from the client because that would expose all your database credentials. So usually we have servers that are responsible for communicating with the database. But whenever we have to make two separate entities talk to each other and understand each other, in this case client and server, we face a lot of problems. And some of them are tons of boilerplate, losing type safety, repetitive error handling. So can we do something about it? Luckily for us, yes, we can. We now see new tools, new projects that are ready to solve this problem. We have TRPC procedures. We have BlizRPC with query and mutation resolvers. We have Remix Data Loader, React Server Site Components, and probably many more that I didn't put on this slide. But with my talk today, I'm going to focus on the approach taken by the first two, by TRPC and BlizRPC.
So that means that we are going to talk about RPC. But in order to understand how we got here, how we got to have tools like TRPC and BlizRPC, I'm going to take you back to the 80s to see a little bit of history. Why are we starting here? We are starting here because RPC is the beginning of web services. And 1981 was a year when Bruce J. Nelson wrote a thesis and coined this term. So let's start by explaining what is RPC. It stands for Remote Procedure Call. So imagine you have a local procedure, Welcome.
3. RPC, Corba, and SOAP
RPC is the practice of remotely calling functions. It solves problems such as tight coupling between client and server, language dependency, and lack of request cancellation. Corba, an improvement over RPC, aimed to be platform and language agnostic with the introduction of interface definition language. However, Corba had mapping problems and a steep learning curve. This led to the development of SOAP, a simpler protocol using XML for requests.
And when you have it on the same computer, you just call it like that, like on the slide. But now imagine that Welcome is on a different processor, on a different server, and you have to use a network to call it. So that's when RPC comes into play, and RPC is the practice of remotely calling functions. And an RPC API is built with functions, and the functions are called with arguments. Of course, that's not how RPC looked like 40 years ago because there was no HTTP or JavaScript yet, but that was the idea.
So now, what were the problems? One of the major problems was that the procedure convention made client and server tightly coupled, meaning it was almost impossible for the server to be consumed by many clients. Another problem was that it was tied to a specific language. So other problems were like no-request cancellation, parameter marshaling, exceptions handling, and forcing developers to use multi-threaded servers. Some of those problems are not even relevant any more, but those 40 or almost 40 years ago, it made developers to look for something better, something more suited for the distributed programming world. And this new thing was Corba.
So what was cool in the 90s apart from boy bands, Nintendo, and rollerblades? Object-oriented programming. And that's what Corba have we rely on. So in Corba we have a server process, which contains objects, and we have a client process that makes requests to get this object. Corba, in contrast to RPC, its goal was to be platform and language agnostic. And in order to achieve that, it introduced interface definition language. So that was a huge improvement. And one of the most popular IDLs that you may be familiar with is currently Protobuf. But introducing IDLs it's solved a bunch of problems, but it wasn't also that easy. There were a bunch of mapping problems. Because can we map everything, like types, exceptions, exceptions handling? The answer ended up being no. And apart from that, this goal of being agnostic added a lot of complexity and caused Corba to have a steep learning curve. So there was, again, a need for something better, something new.
And since Corba was complex and heavy, there was a need for something simple. So here we go, simple object access protocol in late 90s. So in SOAP, we have this envelope that the requests are by default HTTP posts. However, SOAP is not tied to any transport protocol. But by default, it uses HTTP. So it's XML. We have an envelope which identifies the requested API. And then we have a SOAP body with the parameters that are passed to the server.
4. SOAP, REST, and GraphQL
SOAP, although better than Corba, had its own limitations. It was heavy, tightly coupled with the server, and lacked caching on the HTTP layer. REST, on the other hand, is a set of architectural constraints that focus on resources rather than procedures. However, REST can be difficult to follow and many APIs claiming to be RESTful are actually RPC over HTTP. This leads to problems such as overfetching and the lack of end-to-end type safety. To address these issues, GraphQL was introduced, allowing for efficient data fetching with just one query.
Here's an example of a SOAP request and a response. So that was better. That was supposed to be easier than Corba. And in fact, SOAP is still used to this day. But because it was XML only, it was heavy and required more bandwidth. And since it was using POST by default, there was no caching on HTTP layer. And another problem. It was tightly coupled with server. So we are back with the same problem as with RPC.
So again, what's next? Rest. It's not a protocol like SOAP. It's a set of architectural constraints. In Rest, the server exposes resources and the client requests the resources or updates them. So, since SOAP had this envelope concept and it was heavy, you can often find comparisons that SOAP was like an envelope and Rest was like a postcard, so lightweight. So how it compares to RPC? RPC was about procedures and Rest is about resources. So here's the comparison of how a similar API would look like in both RPC and Rest. So in Rest, you ask the server, can you give me the state of this resource or here's the state of the resource, can you please store it? And with RPC, you say to the server, can you call this procedure for me? So that's cool. But what's wrong with Rest? Well, firstly, it's very difficult, like, it's difficult to follow the constraints. They're awesome. They make you gain a bunch of guarantees about your API, but they are also quite limiting and difficult to follow. In fact, most of the Rest APIs that call themselves Rest are not really Rest. They are RPC over HTTP, which uses JSON. But it doesn't matter, like, whether your Rest API is, like, fully Restful or somewhat Rest.
There are common problems to deal with. Some of them are, for example, overfetching, so getting unneeded data and plus one problem, so having to do multiple round trips to the server to fetch data for one view. Limiting constraints that I mentioned before. And what's also important, no end-to-end type safety. So then came GraphQL, aiming to solve those problems. And with GraphQL it was very easy to solve the n plus one problem, because in order to fetch data for a view, we can send just one query. This n plus one problem is not really solved, because we just push it to the server, but from the user perspective, someone who is using the GraphQL API, we don't have to do those multiple calls like with REST.
5. Exploring GraphQL and RPC
GraphQL shares some similar ideas as SOAP and has its own problems. Writing GraphQL servers can be difficult with a lot of boilerplate. Revisiting RPC allows treating remote calls as local, providing end-to-end type safety. A client-side API client can eliminate the need for fetch calls and provide a better developer experience. A demo application for drawing names with trpc and Blitz RPC is showcased.
It's also easy to eliminate the overfetching problem, because it's the client who controls the data it gets. But GraphQL shares some similar ideas as SOAP, which means it also shares its problems. One of them is that it's also by default HTTP post, so there's no caching on HTTP layer unless you use something like GraphQL CDN created by MaxTeuber. Then, if you want to have end-to-end type safety, you have to generate types, which isn't a big problem. It works very well, but there is an additional step that you always have to consider.
Another problem is that writing GraphQL servers is quite a difficult task, and there's a lot of boilerplate you have to do. On the other hand, you can use tools like Hasura or Postgre file, but those tools map your database to a GraphQL API, which can mean that you push a lot of domain logic to the frontend.
So, what's next? As we recently learned that GraphQL is just a bunch of poorly batched RPC calls, we're going back to talking about RPC. And we're going to revisit the original promise of RPC, which was enabling you to treat remote calls as if they were local. So why is that cool, and why is that important right now? It's because TypeScript and static typing became de facto a standard, and having end-to-end type safety has never been more important. So this problem of end-to-end type safety regarding the API layer is a crucial thing to solve. So we saw this welcome example before. Right now, I just put additional database call. So if your backend is perfectly type safe, then you make this fetch call on the frontend and you're losing this type safety. I mean, you could generate types, that's one option, or you can type it again on the client, but, you know, that's additional work. It would be cool if we could get rid of this fetch stuff, if we could, for example, create a client on the client side that knows everything about the API, knows what are the procedures available on the server, what are the argument types, and so on, something like this.
So now I have a small demo application. So this is something I've built recently, because it's Christmas soon and I really don't like getting too many presents, because that's a lot of waste. So I built this app that I'm using with my family and my friends, which lets you draw a name, so you can only buy a present for one person. And we're going to see how this draw a name looks like in both trpc and Blitz RPC. So I'm going to take you to VS code. So here's a draw name mutation with Blitz RPC. So what's going on here is I'm using resolver pipe from Blitz. It's not even necessary. I won't go into like the very details of that. But what's important here is that this mutation is an async JavaScript function. I have all the logic inside. I have calls to the database, logic figuring out what names are available, and so on. And then what happens is I'm using this function by directly importing it from the server, from the mutations folder in my React component. There is this useMutation hook which is a Blitz wrapper on React query.
6. Exploring BlitzRPC and tRPC
Blitz is a magical import that swaps with an HTTP call at build time to prevent database data leaking. Type definitions and argument requirements are known. tRPC defines procedures in a Next.js project as a Next.js API route. The goal is to showcase full stack type safety and the possibility of improving past technologies. Next.js and Remix are frameworks that enable this.
It has the same properties. So what happens here is that Blitz is kind of magical. This import is being swapped with an HTTP call at build time so that there's no database data leaking to the front end. But we have all the type definitions we know with domain mutation returns. We know we have access to all the React query properties. We know what arguments does this function accept. So I have a usage here, it accepts a group name and a member name, so if I remove this I will get an error, TypeScript will tell me that I'm missing an argument.
So that was bitsRPC, now let's ctRPC. So with tRPC I'm defining the procedures, this is a Next.js project, so I'm defining it as a Next.js API route. I create a tRPC router. That's unexpected. That's very slow. Okay. Anyway, I'm writing all my procedures, both queries and mutations in one file, and then I am not sure why it doesn't scroll, but then if I go to the same file when I was calling the donor mutation, if it lets me. It doesn't. Oh, yeah. It works. Now I always have to scroll. Okay. I don't have time to wait for VS Code to catch up.
So that was an overview of how it works in BlizzRPC and tRPC. My goal wasn't to go into very details. My goal was to give you a sneak peek that those things like having full stack type safety and 10 type safety are now possible. I think my laptop froze. So let's wrap it up. I will give you my finger. Yeah, I think my laptop is restarting. There are only two slides left, so I think I can improvise. The takeaway from my talk is that sometimes we don't need a brand new thing. We can revisit things from the past and iterate on them, we can improve them, because the thing is that RPC had a bunch of problems a while ago, but now we have frameworks like next.js, like Remix.
7. Revisiting RPC and its Advantages
RPC is a natural fit for the increasingly ubiquitous practice of full stack development with frameworks such as next.js. Telefunk is another tool similar to TRPC and BlitzRPC. RPC APIs, once seen as a disadvantage due to tight coupling, can now be used to our advantage with TypeScript.
We can revisit ideas like RPC, and now they are a perfect fit for the JavaScript ecosystem of things like next.js. I have this quote, which is, in my opinion, a good summary of my talk. So, RPC is a natural fit for the increasingly ubiquitous practice of full stack development with frameworks such as next.js. And, by the way, Telefunk is another thing similar to TRPC and BlitzRPC. So we can see that we have a bunch of them. We have a bunch of tools that are now relying on RPC APIs because what was once disadvantaged, like that RPC is tightly coupled with the server and the client, can now be used to our advantage. Because now we have TypeScript, we want to know exactly what are the procedure names, we want to know exactly what are parameters that are accepted by our APIs. So that's all.
Q&A on RPC and Backend Solutions
If you have any questions after this talk, you can follow me on Twitter. Alexandra says, if you scan this QR code, it will take you to my personal website with the slides. I also have a bunch of resources that I used to prepare this talk. And if you want to buy fewer presents, you can visit Everybody.gives. Let's start with a simple question from the audience. If someone has never used RPC, what would you recommend them to try out first? So I think you can start with tRPC or even BlitzRPC. It depends on the project that you want to build. Nice, and here's a question that dovetails nicely to that. What would be a smooth RPC solution when the back end uses Java or Kotlin like a JVM back end? And is RPC an appropriate solution for a non-monolanguage environment? When I was talking about Korba, I was talking about this IDL, interface definition language. So we need something like that. We need a mapping between languages.
If you have any questions after this talk, you can follow me on Twitter. Alexandra says, if you scan this QR code, it will take you to my personal website with the slides. I also have a bunch of resources that I used to prepare this talk. And if you want to buy fewer presents, you can visit Everybody.gives. Thank you. Thank you so much Alexandra. Why don't you take a seat and I have some questions.
Okay. That's awesome. Yes. Let's see. All right. Cool. So congratulations for making it through the day's first technical challenge. Yeah, that was stressful. Yes, but I think you handled it very well. So good job.
Let's start with a simple question from the audience. If someone has never used RPC, what would you recommend them to try out first? So I guess, which library or which tool, which approach? Well, RPC is not such a new idea. You can imagine that when you're calling JavaScript functions, like that are in a separate file, but now they are not in a separate file, they are somewhere else, and you need this bridge that I was talking in the beginning of my talk, to be able to access it. So that's the whole idea behind RPC. So I think you can start with tRPC or even BlitzRPC. It depends on the project that you want to build because BlitzRPC currently only works for Next.js. tRPC is working with Next, Spelt, and it's framework agnostic. So you can start playing with tRPC, see how it works for you, and that should be a good start to learn more about RPC.
Nice, and I think here's a question that dovetails nicely to that. What would be a smooth RPC solution when the back end uses Java or Kotlin like a JVM back end? And then maybe a broader question there is, is RPC an appropriate solution for a non-monolanguage environment? Yes, yes, but we need to have... When I was talking about Korba, I was talking about this IDL, interface definition language. So we need something like that. We need a mapping between languages.
RPC Frameworks and their Suitability
So for example, there is this RPC framework, gRPC, which uses Protobuf, and that mapping between different languages, so you can have communication between servers written in completely different languages. And Protobuf has all the information about the schema, the types, how the mapping should work. When you have multiple clients to a single server, using gRPC or Blitz may not be a problem if you have the same application with a web and mobile client. However, BlitzRPC and tRPC are not meant to create APIs consumed by many clients. They are a great fit for full stack frameworks like Next.js, where everything is tightly coupled. RPC's suitability today is influenced by the evolution of languages, frameworks, and the current state of the ecosystem. With the rise of full stack frameworks like Next.js, Remix, Svelte, Kit, and the popularity of TypeScript, RPC solutions like tRPC and bt-rpc can be revisited. The emergence of distributed JavaScript edge runtimes also makes RPC more attractive as the network boundary becomes faster, allowing for easier modeling of function calls.
So for example, there is this RPC framework, gRPC, which uses Protobuf, and that mapping between different languages, so you can use... You can have communication between servers written in completely different languages. And Protobuf has all the information about the schema, the types, how the mapping should work. So in order to use Java as the back-end and something else as maybe another back-end or as a client, you need to have something like that. So maybe gRPC is something to try or something similar. I would guess that that's the way to go.
Nice. Let me ask then the opposite question, which is that when you have multiple clients to a single server. So the question here is, isn't using gRPC or Blitz a problem when we have multiple clients, for example, a native mobile app and a web client? Well, if you have the same application and you have a web application and a mobile application, it may not be such a problem. But that's true that BlitzRPC and tRPC, it's not meant to create APIs that are consumed by many clients. For those kind of things we have GraphQL, we have REST. And what's worse BlitzRPC and tRPC great fit is full stack frameworks like Next.js, when we have everything coupled together because that's what I think is also mentioned in tRPC docs that for better or for worse tRPC tightly couples client and server. Yeah, I think, you know, if I may kind of inject there, the way I've always thought about tRPC, it's kind of in the name, it's a remote procedure call. Like it's almost like you want to make a function call, but there's a network boundary in between. And so it's just a solution to that problem and not necessarily like an API layer for all. Yeah, yeah. Yeah, cool.
I'm going to take a couple of more audience questions, but I wanted to ask my own question, I think, because one thing the historical perspective that you gave is, you know, we went through, you know, these different approaches, you know, Corba and SOAP and so forth and so forth. And sometimes it feels a little bit like we're just making this up. Like we keep going, you know, from a FAT client to THING client. We keep doing RPC to like service oriented catalogs, and then we go right back to the previous one. Yeah. Are these just like trends and forces? Or do you think there's like something changing in the kind of environment or the problems that we're trying to solve that now truly makes RPC a more appropriate solution today than it was maybe five years ago? Yeah, yeah. I think it's still related to how other things evolve. So how languages evolve, how frameworks around languages evolve, because, you know, with I don't know, with a state of frameworks and a state of JavaScript and Typescript, I don't know, 10 years ago, RPC and you know, like tools like tRPC and bt-rpc wouldn't make such sense. But right now, since we have this evolution in fullstep frameworks, like Next.js, Remix, Svelte, Kit and the TypeScript becoming super popular, we can revisit those things. And I think this is, this is why we like keep going in circles because, you know, other things are becoming popular or other things are being created. So some things that were once a bad fit for the current state of ecosystem can now be revisited. Interesting. And do you think that the rise of sort of, like distributed JavaScript edge run times is also making RPC sort of more attractive because suddenly the network boundary becomes a lot more fast, right? Like it's easier to model things as a function call.
Drawbacks and Future Improvements of RPC Libraries
RPC was marketed as treating remote procedures as if they were local, but the network and transport layer introduced issues. With functions on edge, the network problems are minimized, making the promise of treating remote calls as local more feasible. The drawbacks of current RPC libraries include tight coupling between server and client. Future improvements should focus on enabling server APIs that can be accessed by multiple clients and creating a developer experience tool that combines the best features of Blitz RPC and tRPC.
Yeah. Yeah, I think, I think it is. So, um, yeah, so actually one of the things why RPC was kinda like hated or not particularly liked back then was because it was being marketed as something that allows you to treat local remote procedures exactly the same as if they were local, but that was very flawed because there was a network and the toward the, there were a bunch of issues that you have to face when there's network involved, when there's transport layer involved.
So, um, so now I think when we, uh, when we have like this, this, uh, functions on edge and when we kind of like limit those problems with network, we can kind of revisit this promise. We can kind of like, not be so skeptical about this promise of treating remote calls as if they were local, because there's actually this network, uh, network part is very minimal. So the problems will be minimal.
Yeah. It's almost as if the physics are changing, right? If you can call a remote function, the 60 times a second, you know, suddenly, uh, things become a lot, you know, a lot more attractive. Yeah. Cool. Let's go back to audience questions. We have a few more minutes. Um, so every solution has its drawbacks. Whoever brought this up, it is unfortunately true. What are the drawbacks for the current state of RPC libraries and which of them should we work on to remedy? So what's still missing in the landscape of let's say, for example, JavaScript or TypeScript RPC that we should be working on next?
Oh, that's a good question. Um, so something that might be missing is this. Uh, so I mentioned before that TRPC and BlizzRPC tightly couple server and client. So maybe that's something next to work on so that we have, uh, we have server API's that are, uh, that, that can be accessed by multiple clients. It's the, it's the first thing that we were discussing, uh, today. Uh, that's that's, that's one thing. And, Well, I'm still looking forward to, to having like the best, uh, developer experience tool, because, uh, to be honest, I may be quite opinionated here because I used to work on Blitz RPC. But I still like the developer experience of Blitz RPC. I like how, how it works. There is a trade off. Like, uh, it's this magical imports, uh, have this drawback that a Blitz messes up with Webpack. But, but it's, it's quite nice developer experience. And tRPC works slightly different, like it's more explicit. Um, so I would, I would love to see a tool that combines it. That is like framework agnostic. It has more of the Blitz RPC, uh, experience.
Future Plans and Availability of Demo Code
As the final question, the speaker is asked about their plans for the future. They express their excitement about working on APIs and databases. The demo code shown during the talk will be available on the speaker's GitHub. Unfortunately, there is no more time for questions as lunch is waiting.
Yeah. Um, so, but you, you currently, you, we talked yesterday on the speaker's dinner and you currently don't actively full-time work on Blitz right now. So, um, as final question, what's next for you? Like, what is it that you're excited about and what do you want to work on? Um, I don't know. That's, that's the very honest question. I'm sorry. I thought it was going to be an easy question, but uh, no, no. I'm still figuring out. Uh, there are a melt of things I like. I like the talking about APIs. I like databases, so I think something around it.
Nice. And, uh, will the demo code that you just showed us, will that be available online? Uh, yes. Yes. Uh, that's, that's on my GitHub. Uh, my nickname is B-Rose. Yeah. Nice. I use emoji journal. Cool. All right. What we don't have, unfortunately, any more time for questions because lunch is waiting.
Comments