10 ms·
TRPC: End-to-end typesafe APIs made easy
- stickfigure 4y agoThe docs don't say anything about the wire protocol - is this based on REST/JSON, or something proprietary? If proprietary, is it spec'd and documented? Support for implementations in other languages?
- tcbyrd 4y agohttps://trpc.io/docs/rpc https://trpc.io/docs/rpc
- bradrn 4y agoI’ve never used this, but it looks like a very similar idea to Haskell’s Servant library [https://docs.servant.dev/en/stable/ https://docs.servant.dev/en/stable/]. Could someone who knows more enlighten me as to how correct this comparison is?
- aranchelk 4y agoThey seem similar. With Servant you start with a type definition describing your API (using type-level functions), from their docs: 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.
- Vosporos 4y agoHi, Servant user here: Haskell's type system is sound, which means that you can have type safety. TypeScript's type system is unsound, so every guarantee that you may think you have wrt. type safety go out of the window at the moment you start the typechecker.
- lalaithion 4y agoHey, don't be this way. Haskell's type system is also unsound (see: undefined, unsafePerformIO). Typescript has done an amazing job bolting an advanced static type system on top of a dynamically typed language. The edge cases of that type system exist, and are a bit more prevalent than Haskell's, but there exist a number of libraries in Typescript that take inspiration from Haskell libraries. This question is about the differences between the design of these two ways of statically representing APIs and not about the fundamental differences in the type systems of their host languages.
- tome 4y agoThere's a huge gulf here. undefined doesn't introduce unsoundness, and unsafePerformIO isn't part of the language standard, it's strongly discouraged, and rarely used. I've been writing Haskell professionally for 10 years, for example, and I've never written unsafePerformIO.
- tantalor 4y ago> without schemas What is a type definition if not a schema?
- sirtimbly 4y agoConceptually, yes. But type definitions are exported by declarative lines in the same code that runs. Basically the schema is imperative code that runs actual validations, the tRPC methodology simply looks at the inferred types from that code to enforce consistency between client and server rather than parsing an actual static schema artifact (e.g. a .gql file).
- jeroenhd 4y agoOnly supports using Javascript/node servers it seems, so sadly it's not really usable for me. 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.
- sachinraja 4y agoI don't believe there's anything really preventing the use of server-side events. The Websocket implementation is via an adapter and special client so I think the same could be done for SSE (probably achievable in an external package too).
- goodoldneon 4y agoIf you're using OpenAPI, you could use this to generate TypeScript interfaces: https://github.com/bcherny/json-schema-to-typescript https://github.com/bcherny/json-schema-to-typescript It works really well
- chrisarnesen 4y agoTRPC is designed for systems where the front and back ends are both TypeScript. In that case it's simpler to have them share code than to go through an intermediary type system such as GraphQL.
- gavinray 4y agoYou can do this with GraphQL too: https://genql.vercel.app/ https://genql.vercel.app/ https://github.com/graphql-editor/graphql-zeus 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 https://www.youtube.com/watch?v=7n3MeMFHiMk (Skip to 2:14 to see the autocomplete/type-safety)
- deleted 4y ago[deleted]
- hu3 4y agoIt's not the same though. tRPC requires no code generation. 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?
- sirtimbly 4y agoCorrect! Instead of codegen, it relies on the TS language server to enforce schema compliance.
- eandre 4y agoIf you want a similar experience to this but more optimized for backend development using Go, I've been building https://github.com/encoredev/encore https://github.com/encoredev/encore for the past few years!
- colinmcd 4y agoI wrote the initial proof of concept for tRPC a little over a year ago (though I'm no longer involved in the project). Seems like there's some confusion about how this works. A more complete description is available here[0] below but I'll put a brief explanation below as well. - 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 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. [0] https://colinhacks.com/essays/painless-typesafety https://colinhacks.com/essays/painless-typesafety
- hegem0n 4y agoI love this. This is the future
- jre 4y agoI like this idea very much. Shameless plug and I don't want to be the Rust fanboy, but I've played with something similar in Rust: https://github.com/julienr/liveboard-rs 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/src/datatypes/mod.rs 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.
- evantahler 4y agoThis is one of the best things about typescript. You can do this kind of thing without much special tooling at all - https://www.evantahler.com/blog/post/2020-10-16-typescript-frontend-backend https://www.evantahler.com/blog/post/2020-10-16-typescript-f...
- janpot 4y agoNice! I wrote something similar for Next.js a while ago. The pattern is so much more ergonomic than everything else I've used before. https://npmjs.com/package/next-rpc https://npmjs.com/package/next-rpc
- kristiandupont 4y agoI recently gave a talk about our experience with tRPC. So far it's looking very promising! https://www.youtube.com/watch?v=k1TCueEhhJo https://www.youtube.com/watch?v=k1TCueEhhJo
- vander_elst 4y agoHow does this compare to gRPC? That the wire protocol is actually http+json instead of binary? I wasn't able to find much on their website
- sachinraja 4y agotRPC offers typesafety across your frontend and backend without needing to generate any code. This makes it so updates in your backend "router" are immediately reflected in your frontend code. You can't use gRPC with TypeScript without codegen. tRPC may be more familiar to TS/Node.js devs too.
- lowwave 4y agointeresting. Kinda like fastify json schema.
- alexdotjs 4y agoAwesome to see my lil' baby on the frontpage!
- Vosporos 4y agoyou can't have type-safety with an unsound type system, silly.
- sachinraja 4y agoCould you elaborate on this? What part of tRPC do you think is unsound due to the type system?
- colinmcd 4y agoTypeScript's type system is unsound in a mathematical sense: https://effectivetypescript.com/2021/05/06/unsoundness/ https://effectivetypescript.com/2021/05/06/unsoundness/ Though this has little bearing on practicality which is probably why the original comment is at the bottom of the pile. 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).
- sachinraja 4y agoThanks for clarifying!
- markoutso 4y agoI am really not getting this. If you run Typescript on both ends, can't you just share the source code that defines the types?
- hu3 4y agoYou kinda can share function signatures with TypeScript's import type. 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 https://colinhacks.com/essays/painless-typesafety
- ricardobeat 4y agoYou could argue that this is actually adding a lot of (nicely knit) seams.
- colinmcd 4y agoI think that's a good characterization!
- colinmcd 4y agoBasically tRPC lets you define a router containing all your endpoints in a single structure. Then you can import the type definition of your router and make typed API calls without needing to wire everything together with types.
- theobr 4y agotRPC has been a lifesaver for us at Ping.gg 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
- hu3 4y ago> I know we will have to move off tRPC eventually 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.
- awhitty 4y agoThis project looks interesting! I have used a similar project called tsoa [1] and have appreciated that it generates an OpenAPI spec that can be consumed readily by many other clients, even outside the JS ecosystem. Does TRPC have plans for a similar feature set? [1] https://tsoa-community.github.io/docs/ https://tsoa-community.github.io/docs/
- alexdotjs 4y agoYup, with the optional `output`-property we actually have all the type information needed to generate an openapi-schema. See this for more info: https://github.com/trpc/trpc/issues/1724 https://github.com/trpc/trpc/issues/1724
- awhitty 4y agoThanks for the link! That looks really stellar actually. Excited to see how it shapes up.
- deleted 4y ago[deleted]
- arpinum 4y agoI'm not seeing the appeal of this over Smithy, which can target multiple frontend and backend languages. What am I missing? What is wrong with codegen tools? Especially when they help you design strong contracts upfront, rather than ad-hoc API design as their demo shows.
- mhoad 4y agoNot looking to actively bash anyones work here but I’m really confused on the value proposition here over something like gRPC which has a lot of substantial advantages from speed, to wide cross language support and has been battle tested in the most extreme scaling scenarios possible. 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 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?
- sachinraja 4y agoYou can't provide typesafety (with TypeScript) across the frontend and backend for multiple languages without codegen. There's no intention for this to be strictly JS, but there's no easy way to offer this for multiple languages. 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 https://github.com/trpc/trpc/issues/1724).
- rad_gruchalski 4y agoSo what problem does this solve? Protobuf + grpc already provide types for tons of languages. As in, messages are generated to models/structs/classes what have you, depending on the language… 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?
- mhoad 4y agoI think maybe that’s the part I’m not getting. 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.
- AvImd 4y agoDoes this work with NestJS?
- sachinraja 4y agoIt can be made to work with any framework with a proper adapter. NestJS is quite opinionated though so I suspect the two will not work well together.
- hardwaresofton 4y ago> Currently GraphQL is the dominant way to implement typesafe APIs in TypeScript (and it's amazing!). Disagree here and it’s a bit disconcerting to see this as an opening premise.
- darepublic 4y agointeresting this came up because I'm looking to do exactly this -- but my first instinct is simply to share declaration types from my server with client as a dependency