- It's designed specifically for a full-stack TypeScript app. Your API is implemented as strongly typed server-side functions.
- The input type is specified using a schema library like Zod or io-ts.
- TypeScript infers the return type of these functions.
- You can then import the type signatures of your functions into your client. Just types, no runtime code! This is safe in typescript with the `import type` syntax. tRPC uses those type signatures to provide a typesafe client API, basically an SDK for your API. There's no codegen happening - the client uses TypeScript generics to provide a set of strongly typed "proxy functions" that can be "called" on the client. These proxy functions execute HTTPs requests under the hood: https://trpc.io/docs/rpc
The point is to avoid the boilerplate, codegen, and lack of DRYness associated with building a strongly typed API in TypeScript. You can do this with GraphQL but it relies on code-generation, requires complete buy-in, and (IMO) doesn't provide a great developer experience. TypeScript has a native way of representing types, so the goal is to avoid an intermediate representation (in the form of an OpenAPI spec or GraphQL schema) entirely. As you update your server code, the client's type signatures update instantaneously.
Another important goal is to make it easy to write DRY code when building APIs. Without tRPC, it's common to manually provide type definitions for the results of API calls. But those definitions can easily get out of sync with your actual server code. tRPC infers types from your code itself and provides a typed interface for your API thats doesn't require any manual type annotations.
As far as I can tell, tRPC basically bridges (hides) network communication and allows doing remote procedure calls almost like regular, type-safe function calls on the same machine within the same process.
Now I would give a fortune for having something like that also for cross-language communication and for communicating with other processes (binaries and shell scripts). I've been thinking about this a lot in recent years: In SWE we need to jump through many hoops only because it's so god damn hard to invoke a function or a whole API living somewhere else in a type-safe manner. Intermediate formats like JSON, protobuf, standards like REST, OpenAPI, and GraphQL, and even languages like SQL (and the various ORM libraries it inspired) are all a result of that to some degree: Once data leaves the safe haven of your (hopefully statically typed) programming language where the compiler/interpreter knows exactly what its type is and what the signature of the function is that you're trying to call, you're basically on your own.
I recently read about WASM Interface Types[0] and it seems like a step in the right direction, though unfortunately it will only bridge the – let's call it – type safety gap between processes, not between different machines in a network.
[0]: https://hacks.mozilla.org/2019/08/webassembly-interface-type...
A truly huge amount of time, money and optimization went into a project like that and has been proven to work well for years now.
The JS ecosystem confuses me with things like this regularly just the other day I was watching a video where the lead devrel person from Vercel was trying to explain “edge functions” to a senior backend engineer that started falling apart under the most rudimentary questioning so much so that in the video they have this awkward hard cut and they rush to wrap up the interview. Link if anyone is interested https://youtu.be/yuxd2kurpzk
This gives me kind of similar vibes in that I just don’t really get the use case here unless it’s to intentionally stay strictly in the JS ecosystem for some reason?
There will be an openapi generator some time in the future so that could help with generating clients for other languages (https://github.com/trpc/trpc/issues/1724).
I don’t have a problem with the code generation personally, if anything I appreciate having something I can go and inspect if things go wrong so avoiding it isn’t an obvious plus to me.
OpenAPI already exists and anyone can write a spec today and have code generated (servers, clients, models) today. Same principle as protobuf but the message and service description is much more verbose.
> tRPC to OpenAPI generator
So, … another level of indirection? Why would I ever pick this up when I can just use OpenAPI directly?
The type exchange seems to rely on shared code between the frontend and the backend to exchange types, rather than using schemas like other systems.
Not implementing server-side events seems like a shame because they're a very capable mechanism for subscriptions without resorting to websockets.
https://github.com/bcherny/json-schema-to-typescript
It works really well
And that's what tRPC does but adds some generics in the middle to make things seamless.
Explanation here: https://colinhacks.com/essays/painless-typesafety
type UserAPI1 = "users" :> Get '[JSON] [User]
In tRPC based on the example it looks like you start by defining and instance then grab the type and export it.
https://github.com/graphql-editor/graphql-zeus
I did a 5 min talk about these newer breeds of codegen tools (where it's a single client SDK that does automatic return type inference based on the input args), they're really neat:
https://www.youtube.com/watch?v=7n3MeMFHiMk
(Skip to 2:14 to see the autocomplete/type-safety)
With tRPC if I change the return type of an API, I get instant feedback on my frontend code with errors and autocompletion.
Is my understanding correct?
See this for more info: https://github.com/trpc/trpc/issues/1724
He's also using a stricter mathematical definition of "type safety" whereas tRPC means it in the colloquial way it's used in the TypeScript ecosystem (that is, a fully typed interface between client and server, ideally that's non-duplicative and inferred directly from your code instead of being manually defined).
Never had such a seamless experience building and deploying “full stack” apps. Multiple classes of bugs just, like, don’t happen now?
Helped build up a lot of the GraphQL tech at twitch, and I still love it, but man do I not miss all the work maintaining the “contract” between front and back. I know we will have to move off tRPC eventually, but I’m hyped at how far it’s taken us already
Is that when you can no longer get by with only NodeJS/TypeScript on the backend?
I've been thinking about that in a greenfield project I'm trying tRPC out.
What is a type definition if not a schema?
https://github.com/julienr/liveboard-rs
Basically it uses actix for the backend and yew (Vue-like rust frontend framework) for the frontend. This enables one to share types (and helper functions) between both, which is great:
https://github.com/julienr/liveboard-rs/blob/master/shared/s...
That being said, I think maturity-wise, Typescript is probably a better bet for this right now, so I'll definitely look at trpc for $dayjob.
Disagree here and it’s a bit disconcerting to see this as an opening premise.