No video
I Never Want to Create APIs Any Other Way
In this video we'll discuss how we can create typesafe REST APIs using ts-rest. This solution works for NestJS, NextJS, ExpressJS, and even Fastify APIs. With this solution we're able to consume the API on the client with a fully type-safe RPC-like client, leading to the best possible developer experience. This is a specially useful pattern if you happen to be developing your backend and frontend in monorepo. Must watch!
Пікірлер: 123
The day has finally come omg. So much better than trpc. Thanks for finally making a video on ts-rest :) I'd love to see a ts-rest with react query and fastify video!
@mariusespejo
Жыл бұрын
Haha thank you I remember you making the suggestion! I’m thinking of doing a follow up for Next which can contain the react-query integration. For fastify honestly if you look at the integration package for it, it’s largely the same syntax but I’ll consider covering it
Hey it’s Michael Angelo from the core team at ts-rest, great job!!
@mariusespejo
Жыл бұрын
Hello! Glad to see someone from the team in the comments, awesome work!! The new api for Nest is really nice
@greggsworld4453
25 күн бұрын
first time seeing this, great tool! We chose Hono because it come with RPC but now want to use this but see Hono does not have any support yet but seems like it shouldnt be too difficult to get it to work?
Thanks for this video. We build a pretty complicated application with multiple apis + projects and used trpc for it, but we kept on running into very hard to debug issues. This looks a lot better, since it still uses rest under the hood, so it's also trivial to debug. One disadvantage we faced with trpc was the difficulty in getting simple things, like web-hooks to work, since they use a very weird url pattern.
I'd love to see a ts-rest with react query and express video. Thanks for making this.
The reason why this is such a great pattern is because where the source of truth is. Docs are fine, docs are good but like tech books (exactly why tech books), they go out of date because they bit-rot. If you instead have this setup executing constantly, generated automatically, semver'd etc ... you'd have a method to maintain your API while creating clients. Pact is another way to do it, given different goals. But it works for the same reason. The best part of swagger is codegen to me but many people stop at doc gen. Trpc has similar ideas but then you'd have to gen a REST API and then wire that up to swagger and then gen a client. If I have a mobile app or a need for automation/interop, I think I would go with ts-rest first. Now the question is, does it work with Remix?! 🙃 Probably not or not yet. Honestly, this was the promise of express. "One language" but it didn't materialize (to me) because express was a microframework and TS (when express came out) didn't exist (iirc). Now, yeah, you have end-to-end type safety but you also have one language and types end-to-end which is new. The only limit is Javascript and what Typescript can't solve but I think even that can evolve with browsers. I don't know what the old alternative would be, plugins like Applets I guess but that idea didn't work out.
@mariusespejo
Жыл бұрын
Good thoughts! Just to answer the Remix question, I don’t think ts-rest is relevant there. They have a concept of “loaders” for routes which would be your data providers. There’s type safety built into using that so they already have that problem handled. And remix in general isn’t really designed for making REST APIs from what I can tell.
@megacronom
Жыл бұрын
@@mariusespejo If the business logic is not on remix app it should work fine to call the API from the loaders right? Like request -> remix ssr -> api (using ts-rest). The remix server side will act like a BFF
@mariusespejo
Жыл бұрын
Yeah totally, if you’re saying remix is just the client in this case and the api implementation is somewhere else. in that case you’d just use the client api
This is exactly what i needed for my current project, i missed trpc but i also like nest js
That's awesome thanks Marius. I was just starting to do the same, I guess manually, well building an SDK client side to interact with Nest that had schemas shared between the two, but this is great. Also the contract file made me think of I can do a similar thing for Firestore collection references shared between admin and client sdk. Yes, to more on this! NextJs or React would be great, with SWR or something similar as well
Pls make more videos about this library. Its so good & your explanations are smooth & very clean.
Awesome! Thank you for such a fantastic tutorial. I was thinking about implementing nesttrpcnext in monorepo, and now I believe achieving it using ts rest will be easier. But the only drawback I see now in comparison with trpc is that in ts rest contract, you describe the route, what happens if you don't implement (e.g., forget) it on the server side (nest.js) and try to use it in front (next.js)? In trpc, this scenario cannot happen.
@mariusespejo
Жыл бұрын
If you’re doing the multi-handler syntax it should enforce also server-side if there are missing methods in the contract. I actually showed that briefly in the video but maybe I didn’t explain well. So at build-time you should discover that something’s missing server-side if the contract got updated
@geebrox
Жыл бұрын
@@mariusespejo, yes, but imagine several contracts for different route layers (nest module controllers). If you do not create a controller for one of the contracts and implement a multi-handler for that module, after which you import that contract in FE and use it, you will only know about it when you face it manually, not even in the build time. I may be talking about too particular a scenario, but it may happen.
@mariusespejo
Жыл бұрын
Yeah that can happen totally, but I feel like more likely than not your first step after creating the contract is the implementation. I find it hard to imagine that your first step would be the FE consumption, but even if it was you’re bound to realize during development the api returns unexpected 404. I would hope that you’re testing it works even pre-build
I am a new subscriber of your channel. I'm enjoying your Nest JS and Drizzle ORM videos. I have a request. Can you please make a video Implementing Drizzle ORM in Nest JS?
@foofighterdaz
9 ай бұрын
Would love to see this too, TypeORM doesn't compare
Thanks for your consistency, Marius. I have an off-topic question, I could've sworn there was a microservices nestjs tutorial on this channel but i can't seem to find it, or maybe I'm tripping? 😅
@mariusespejo
Жыл бұрын
Just to be clear In Nest, a microservice is an application that uses a different transport layer than HTTP. That specifically I have not covered in the channel
How is the performance in a large code base? I keep hearing that Zod can be painfully slow compared to alternatives like Typebox. I’m about to stand up a type safe backend and I’m leaning towards just sharing interfaces from a shared library to avoid ts language server overload.
@mariusespejo
Жыл бұрын
I would imagine that performance depends on your underlying framework (e.g. nest/fastify/express/next) not necessarily ts-rest itself. I also briefly mentioned that zod is optional (mostly if you want it to do the runtime validation for you), so you could strip that out and just use TS type/interface. The idea of sharing interfaces in a shared library totally works but that’s just one aspect of the full picture. You still need to make sure that you’re correctly typecasting your client-side api call responses. You’ll also notice with something like ts-rest it takes care of making your client dumb to what the api url paths are, what http verb to use, what http status codes can potentially return (something you’d usually have to assume client-side). You could also make an sdk in your shared library to handle all that, but then again you’re building all that manually vs just defining a simple contract
Love your content ! Thanks for the sharing =D
Can you please tell whts color theme u are using? Nice video
Have you come across the nestia library?
@mariusespejo
Жыл бұрын
I have not, what are the benefits? Looks like it makes you a client sdk?
@madonps
Жыл бұрын
@@mariusespejo Honestly, I have yet to use it myself as I just recently found out about it. However, I found the claims it makes very interesting. In my understanding, it lets you avoid doing the "vanilla" nestjs dance where you have to use a class instead of an interface, or use @Api* decorators to generate a more accurate swagger schema. Instead, it analyzes your nestjs code at build time to figure all that out automatically from your types. Then, you can generate a strictly typed client sdk client or swagger schema from that. As someone who likes using nestjs, that was the largest pain point for me. It is even illustrated by the author on the "pure typescript" section of the docs. But since I haven't had a chance to really use it yet, I was wondering if it does live up to all that. This why I was asking if you'd had a go at it.
@mariusespejo
Жыл бұрын
Looked at it briefly. So they are sort of trying to solve similar things just in a different way. E.g. they’re trying to reduce the amount of decorators when you have controller + swagger + class-validator… so they made their own decorators. But if you watched this video, you’ll notice ts-rest also indirectly solved that problem. Because you just define your schema in TS/Zod and you no longer need to use those decorators. Swagger docs is also auto generated off of that, you don’t even need to run any kind of generate command like with nestia. They (nestia) also generate an SDK for you it seems and that would help solve the similar type safety needs of a client. Still you need to run commands to generate it. Ts-rest is no codegen. It’s simple and it just works. Create a contract and import it on both server and client side and you’re done. No commands to run, no code you have to keep generating.
@mariusespejo
Жыл бұрын
Their claims of 20,000 times faster decorators for json parsing might be worth a try though… but I’ve never had a need to optimize even the nestjs default body parser.
@mariusespejo Could you please tell me how to enter sample field values in the contract? Because the automatic suggestions are providing nonsense as examples.
Monorepo with nextjs + nestjs using drizzle and next-auth with the drizzle adapter would be a cool video to watch. Where both next and nest use/share this drizzle db. That should be E2E typesafe as well
@mariusespejo
11 ай бұрын
I don’t really see the point there. Why not just build your api in next and just have one app? I guess unless you need the greater set of api features in nest
@waltervanwoudenberg6876
11 ай бұрын
@@mariusespejo correct me if im wrong but wouldnt it give a lot of flexibility to still be able to use drizzle in nextjs for simple things and use nestjs for the more complex api stuff. Especially when projects grow and become more complex i think maintaining api’s is easier in nestjs.
@mariusespejo
11 ай бұрын
Sure totally, I mean I think it boils down to what you need. No right or wrong answer here, my point was just think about YAGNI. Start simple and evolve when the need arises. But maybe that’s just me
This is a very cool way to create APIs. But I still prefer the "pure contract-first" where you basically define yourself an OpenAPI Spec/Swagger upstream (OpenAPI/JsonSchemas are easier to write as zod schemas imo, and it has the same features!). This way, you have only one source of truth, you design your API before coding it. Which is very similar to ts-rest's approach, except, all your API consumers can use your API with type-safety no matter the language they're using.
@mariusespejo
Жыл бұрын
But how would you get type-safety with just openapi? It’s not typescript, where do you get the types? I don’t think you can get type-safety “no matter the language” without having some kind of codegen for each language.
@frbloke
Жыл бұрын
@@mariusespejo zod is not typescript either. And yeah your clients will need typegen, or codegen. Just like ts-rest is doing.
@mariusespejo
Жыл бұрын
There is zero codegen here. Zod creates you typescript types via inference. It is all typescript without the need to generate anything.
@frbloke
Жыл бұрын
@@mariusespejo Oh yeah my bad I meant inference. So basically, I could write my contract in zod and expose my openapi spec to my clients that uses other things than JS
Does this only work if the backend is also in ts/js? Is there anything similar for backends in other languages?
@mariusespejo
5 ай бұрын
Yeah this is specifically for when you’re using TS in the entire stack. For other backend languages, assuming you’re targeting having types for a TS client, typically the only solution that would come close is perhaps if you have something that generates a typed-client, I don’t know any specific ones but I’m sure something like that exists
I would love this video with react, react native with expo, and nest js. I am curious to how UseGaurd will work on the endpoints in nest js with ts-rest.
@kaioneal6160
9 ай бұрын
Update!! thanks for the video. I got @ts-rest up and running for a react/angular app for the web, an expo react native app for mobile, and a nest js application for my backend. I plan on setting up typeorm and using my Data entities as types for my API contracts.
Fantastic as always.
When should one use GraphQL vs when should one use gRPC vs when should one use this? Great video, thank you!
@Nitr4Oo
Жыл бұрын
I would personally dont recommend learning / using graphQL for a new project as of 2023, grpc is used in micro service environnments where they must communicate between them, there is a chance that your micro services are written in different languages depending on the goal of that service, grpc makes an interface language-agnostic to communicate, on top of a lot of optimizations such as using protobuf, ts-rest is nice for any js/ts api small / mid sized project
@mariusespejo
Жыл бұрын
Yeah good notes about grpc above, that’s a totally different use case. As for GraphQL vs REST, I still think it really depends. REST is still the standard that almost everyone will know. GraphQL requires a little more learning and setup for most people but it does help with giving clients more control of the response that they’ll get back. Not easy to define a simple answer in a comment lol. As for ts-rest, I think of it as just a utility to add to an existing REST api and is totally optional, it’s mostly for dev ux benefits if you’re working with typescript.
Thanks for this great video, Marius! There is just one thing I didn't understand: Where does the client get the contract from in a non-monorepo project? Does it get automatically generated just by hitting a server endpoint?
@mariusespejo
6 ай бұрын
Depends on your requirements. If it’s a public API you could publish the contract as an npm package. You also could install as private package from a private github repository. Worst case if none of those are options you could simply copy paste the contract between projects but not the best solution. The point here btw is the types that you get during development time, so generating from the server at runtime doesn’t really make much sense
@dreamsachiever212
5 ай бұрын
@@mariusespejo Do you have any comprehensive course on building a graphql API with prisma and Nest JS? I have been watching your past videos and struggling to put eveything together with auth and consuming the api in an nextjs project...I checked your profile and couldn't see any link to your courses or website
@mariusespejo
5 ай бұрын
@ismaeltinta6118 it’s an older video but I did use Nest + graphql + prisma here: kzread.info/dash/bejne/npiYw7RxiZDNm9I.html I don’t have any more comprehensive courses at this time but hope to produce some in the future
@dreamsachiever212
5 ай бұрын
@@mariusespejo I watched that. I was looking for an updated paid course. I am confused with the dto and entity generated files especially when using code-first approach. I noticed some devs keep them and others remove them to only stick with prisma. what's the best practice in the industry?
Very interesting concept. Its similar to Remult.
metadata can be described in the contract (metadata: { role: 'guest' } as const). And how to get this metadata in the endpoint?
In your opinion, what is better to use, ts-rest/nest or nestjsx/crud ? And what is better for deployment? Thanks for great teaching
@mariusespejo
10 ай бұрын
Depends on what you’re looking for. Ts-rest is for type-safety even on the client. Nestjsx/crud is meant to help you reduce the crud boilerplate… so they’re solving different problems
But how this can effect the performance of our app , and in this case we can ude zod , what about the class validatir ? I think zod will be better and easier to work with
@mariusespejo
Жыл бұрын
Zod already will validate the request body, you don’t need class-validator. But you also don’t have to use zod, there’s just first class integration for it I don’t see how ts-rest would be any faster or slower than just a regular route controller. It’s just mapping a request to a handler.
do you think that using Nest for it is convenient? I just think that this approach can put me out and using just fastify with ts-rest is cleaner
@mariusespejo
Жыл бұрын
Nest still has a bunch of other features though, that you basically get for free. But yeah if you want to keep it simple you can’t go wrong with just using fastify directly
just use graphql that is part of the structure
@mariusespejo
Жыл бұрын
graphql on its own doesn’t solve type safety last I checked. You might use a codegen tool to generate types (similar to what prisma does), but you still have the overhead of importing those types and making sure to apply them in the right places on the client. Not to mention needing to make sure that you run codegen whenever the API changes. Server-side you also have a similar problem… you either have to write “code-first” using typescript so that you get types, or write “schema-first” and again generate the types. That seems like so much overhead compared to what I covered here. Correct me if I’m wrong.
@VEINbeats
Жыл бұрын
@@mariusespejo Thats actually the beauts of it in my opinion. Im using for example hotchocolate by Chillicream to create a graphql api and the creation of it is not thaaat far away from a standard rest api. Yes have to learn new fundemental things like dataloaders typedescriptors and so on but when you are already a well trained programmer yoj will learn quickly how to apply this new structures. You can create lazy loaded parameters, so you only fetch the information that you want and get relational data only if needed also from different services or databases. yes in overall its more on the server side but when you need more complexity it will pay of in the future. On the client side you can use like you mentioned codegens. So you dont have to write custom classes or types to deserialze your resulted json it will automaticly create that. Every graphql api has a schema file so you dont have to hope for a well made documentation. You will exactly know that you will get for each query. overall it is more complex in the initial setup but when your api grows you can reuse so much things and types
this is quite usefull
Interesting how it will work with class validator
@mariusespejo
Жыл бұрын
The zod schema would do the validation in this case, it also aligns better with type safety goals
i can't leave without subscribe
is it possible to provide a full fletched nestjs typeorm graphql project with proper error handling?
Anyone can share performance from dev perspective (how much the type resolutions take time). Does it scale well with even large APIs? Asking this because i used Zodios (very similar to this), but i am hitting a large performance wall with even a small application (
@mariusespejo
5 ай бұрын
I imagine zod is the bottleneck there. With ts-rest however it also allows you to use native TS types
Is create route body is automatically validated with zod schema?
@mariusespejo
Жыл бұрын
Good question, it does do the runtime validation for you. I probably should have had a response 400 in my example to make that clear
Not thinking in a monorepo scenario, can I expose the contract in some URL so other applications can download the schema and have access to the intellisense, similarly to how graphql clients do?
@mariusespejo
Жыл бұрын
The core benefits from this idea is type safety during development time. It sounds like you’re trying to get an api schema at runtime which is sort of a different thing. However if you were to generate swagger docs, that comes with json you can pull down, e.g. if you had swagger docs at /api, the underlying json for those docs are accessible on /api-json … but don’t know that would be useful to you. If you want the type safety benefits then you should place the contract somewhere central, like in a library, where the client can install from. Or literally just copy/paste the contract code to each client but that would be a pain if you have a lot of clients
Can we've a link to the repo?
@mariusespejo
Жыл бұрын
Not in a repo sorry, there’s really nothing worth cloning here, the official dos would be a better written resource if you need it
@TheDeprecatedLibrarian
Жыл бұрын
@@mariusespejo I understand. Thx anyway for the amazing content man!
I'd rather use tRPC with built in validation, I am familiar with it and it works well.
@mariusespejo
Жыл бұрын
Ts-rest also does runtime validation, that’s why we’re using zod. But trpc is just another flavor of the same thing, both are great! Only thing to watch out for is: last I checked trpc is not compatible with Next 13 app router
@FunctionGermany
Жыл бұрын
@@mariusespejo tRPC can be used with app router but there's no official integration/documentation. app router sucks anyway so whatever.
How to combine it with a mono repo? Would love to see a mini project with react na nest.js with this type-safe way.
@mariusespejo
6 ай бұрын
I was actually thinking of working on a video doing exactly that. I have made monorepo videos but not one with ts-rest combined
@belkocik
3 күн бұрын
@@mariusespejo any progress?
@mariusespejo
3 күн бұрын
Yup, I covered this 6months ago kzread.info/dash/bejne/k3mZxruFh5CtfLA.html
@belkocik
3 күн бұрын
@@mariusespejo Thank you! I didn't notice it.
Hi ! Thanks for your work 💪 Can you tell the advantage of ts-rest against class-validator for nest.js ?
@mariusespejo
9 ай бұрын
I mean those are two different things. Class-validator when used with nest is usually utilized for DTO validation via decorators in classes. With ts-rest you can get the same thing via zod, although you can turn that off if you prefer class-validator. So it’s up to your preference. Zod definitely is more popular in general, e.g. outside of Nest
@user-mq8wf9iy5l
8 ай бұрын
@@mariusespejo Thanks for your answer and again thank you for all your efforts for the community !
QQ: Would you wanna make a comparison maybe between this and GraphQL !?
@mariusespejo
11 ай бұрын
That’s sort of the same as making a comparison between REST vs graphql… which is a big topic that is filled with “it depends on need” If you’re purely just after type safety then I don’t see how graphql can achieve that without codegen, so that’s a bit more setup. But again if graphql is right for your need is an entirely different question
is that means we don't have to create entity and no need to use class-validator again?
@mariusespejo
9 ай бұрын
Not necessarily, I think it depends. The contract will be defined using zod (if you decide to do so) but in a nestjs app you might still have “entities” which represent database tables, for example if you were using typeorm. Ts-rest does however do request validation which can replace class-validator, however you have the option to turn it off if you’d like to do validation yourself
@dnm17_
9 ай бұрын
and should we create contract for each different route or just create a single contract for all routes?
@mariusespejo
9 ай бұрын
Contract is designed to represent your entire API but if you have a massive API you can probably break it up into multiple files, it is up to you
Does ts-rest work with non js backend languages(golang)? Can ts-rest be used with jsdoc?
@mariusespejo
7 ай бұрын
Well the point is to get type safety across your entire stack. If your backend is in a different language it kind of loses its purpose. As the name implies “TS”-rest is meant for typescript
@ghostlexly
7 ай бұрын
It’s works with non js backend, ts-rest can generate automatically a swagger for your golang
@mariusespejo
7 ай бұрын
but that’s not ideal, again the point is type safety for typescript apps. How would you know on the golang side if your API adheres correctly to the contract? You don’t have the luxury of having the type checker automatically tell you. So you basically lose half the benefit, you’d have to do that manually.
👍👍👍
Please make the FE with reaxt query
can you make a video on ts-rest/serverless aws
@mariusespejo
3 ай бұрын
I actually didn’t know they had support for serverless, yeah I’ll have to check that out but definitely could be an interesting video to make
@muhmmadabubakarijaz1811
3 ай бұрын
@@mariusespejo yes please i am stuck in between i had my contracts defined for all endpoints and put them all into one contract and also i have generated swagger json from it using ts-rest/opneapi but the problem is i am encountering some issues on the handlers end when i apply createlamdahandlers soo please check out the serverless area and thanks for replying looking forward to the video
How about making a video of using Nestjs with Firebase ?
@mariusespejo
10 ай бұрын
I feel like firebase is a very niche platform, I’d probably consider covering supabase though
@user-gu5ts5nx8r
10 ай бұрын
@@mariusespejo making it for both would also be appreciated if possible.
is it better than trpc ?
@mariusespejo
Жыл бұрын
That’s for you to decide! They solve the same problem space. Ts-rest supports nest better though
Can You start adding bookmarks to videos?
@mariusespejo
Жыл бұрын
I usually do on longer videos, but thanks for feedback! will try to remember to always add them
@kapiqu2709
Жыл бұрын
@@mariusespejo Thanks, but I think video time does not matter, bookmarks are meta now
While this pattern is great I've been stabbed in the back by similar tooling (openapi-generator) before, causing me to have to migrate massive amounts of code to avoid bugs. Nowadays I use protobuf directly as my ground truth format nearly 100% of the time, and the protobuf language is so simple that if I need to do some code gen to support JSON-over-HTTP, I can just do it myself.
@mariusespejo
Жыл бұрын
I’m not sure though that I would compare this to code generators though, (even though that sounds like a similar idea of contract-first). The idea here is if the contract changes then you should be able to catch that change at build time. Basically you get feedback if your code no longer adheres to the contract. Whereas a codegen might generate you an sdk for a snapshot of the contract, but it might not necessarily inform you when that contract changes that you need to regenerate
@BrunoBeltran
Жыл бұрын
@@mariusespejo Definitely see your point. At my day job, we actually live in a Bazel-based monorepo, so in practice due to Bazel's strict dependency management, I do always get an automatic update whenever the contract changes at HEAD (and LSP integration due to internal-only plugins for dynamically generating intermediate build steps). The real difference between the typical code gen-based solutions (once they're integrated into a reasonable build/CI/CD environment) really does feel like the fact that this is Typescript-native, which is amazing for sure! Love the video! I like to watch these so I can live vicariously through people that don't need to support Rust+Python+Javascript interop natively and simultaneously when choosing their tooling ☠
Welcome to serializers. Django has had it for literal decade now
@mariusespejo
Жыл бұрын
We’re talking typescript here not python. Django serializer converts things to native python data types. Serialization is a completely different concept to type safety
@jasonrooney1368
Жыл бұрын
Serialization is not the same concept at all. The only reason you might conflate the two in Python is that your serializer is creating a class out of json and therefore gives you type hints and runtime validation. This is compile time type safety. That’s a completely separate concept.
The only issue that I have is that when using ts-rest adding a customClient using axios and using it in the Front-end with @tanstack/react-query it does not pass the signal. even though signal is existing in the fetchApi inside ts-rest.
@mariusespejo
10 ай бұрын
But what’s the point of doing that? What did you get out of using axios? Also there already is a custom client made specifically for react-query, why not use the official integration?
@gmusic8812
10 ай бұрын
@@mariusespejo I finally made it work. but you know, Signals, or AbortSignals are really needed for large scale application, in my case it's a multitenancy webapp that has over 20 + reference datagrids.