API Design in Node.js, v4 Defining Routes
Transcript from the "Defining Routes" Lesson
>> So the next thing is basically, we wanna start hooking things up to the routes and getting everything configured. I typically like to start with the route and then work on the handlers. I think some people start with the handlers and work back to the routes. I'm just gonna go through the routes of the handlers, it's a lot easier for me to think.
[00:00:14] So let's start thinking about the routes. Who here has ever heard of the word like, or the term CRUD, C-R-U-D? Yeah, you've heard, what's CRUD?
>> It's an acronym that I actually find to be confusing because I think it makes more sense just call it what it is but what create update or create read update
>> And delete.
>> Yeah, it stands for create, read, update, and delete. And that's basically if you think about any app you've ever used in your life other than some weird. For most part, most apps are just, you're either creating something, you're reading something, you're updating something, or you're deleting somehing.
[00:01:01] Pretty much every software you've ever interacted with does those four things, some do them all, some only do some. But, that's basically what an API is for is to enable, some type of UI to be able to do CRUD. So, we're gonna write the routes, for our CRUD against the different resources that we created.
[00:01:21] The resources in this case are the things like the models that we made, the products, the updates, the users, those are resources. And we wanna be able to do CRUD operations on them. So we wanna create products. We wanna update products. We wanna read products. We wanna delete products.
[00:01:36] We wanna create updates. We wanna update updates. We wanna read updates. We wanna delete updates, right? So we wanna do CRUD on the resources that we create it. And for each one of those operations, we need a different route. So we need a different method, path combination for each one of those CRUD operations for every single resource, right.
[00:01:57] So an example of that would be, if I wanted to get one product by a given ID, I would have a get request. For whatever my URL is slash product slash the ID of that product, or if I wanted to get all products, it would just be a GET request to slash product.
[00:02:15] Or maybe I wanna create a product, it would be a post request to product. Or if I wanna update a product, it'd be a PUT request for product/ID, right. If I wanna delete one, it would be a DELETE request to product ID. And I would do the same thing for all other resources I would expose on my API.
[00:02:32] And that's all the CRUD operations. Any questions on that? This is following something called REST. I talked about REST before. That's what REST is. REST is, you have these resources, you gotta be able to operate on them using CRUD. We say if you use this method like get, post, put, delete with this way of making URLs the name of the resource slash some ID if you have to find the specific one.
[00:03:01] Then everyone should know how to use your API. It never works out that way because relationships just kills this. As soon as you have one resource that needs another resource like we do in our app, then it's, well, if someone asks for a product, but a product has updates too, we send the updates back to.
[00:03:20] Well, yeah, then it's, well, let them ask for it on a query string. And then you're just creating your own query language at that point. So it was, REST works up until 2005 and then it doesn't work anymore. So, but we're still gonna use it because mostly everything is based of REST anyway.
[00:03:39] So, it's nice to know it. Okay, so let's create some routes. First thing we're gonna do, is we're gonna create a new file router.ts, right. Beside a source, so, let's do that. And then what we're gonna do, is we're gonna create a new router, we'll talk about that.
[00:03:53] And we're pretty much, if you see I have all the routes here for all the CRUD operations that we're gonna do for all of our resources, so, let's do that. So, I'm gonna go in here, I'm going to say router.ts like that, I'm gonna import express from express I can actually just do, I'm just gonna do a named import for Router, but a capital R like that.
[00:04:25] And I was gonna say const. Let's just say router, lowercase = Router, uppercase, like that. So espresso was made a while ago when people were just still trying to figure out how they wanted to make libraries. So this might seem kinda weird to have something with a capital letter in it and then also not see the word new in front of it.
[00:04:44] It's not a constructor function it's just a regular function, but they decided to make it capitalized. People were weird back then. They didn't know what they were doing. But ,yeah, so we're gonna make a new router, okay. A router in express is this, so up until now we've used app, right.
[00:05:03] So, where were we? We did like app.get, okay. The difference between app and a router is one thing. The app is the entire API. A router is just like a sub part of it. So you can have different branches in your API that have their own configuration, their own options, their own stack that merges with the global one.
[00:05:28] So the app will always be the global one, but the routers can be sub routers, sub apps that have their own configuration. So we're gonna make an app or we're gonna make a router here called router and that's gonna be our API. And the reason we're doing that is we're gonna have one or two routes that don't share the same configuration is this.
[00:05:47] For instance, everything that's gonna be here is probably gonna be authenticated. You're gonna need to pass me a token to use it. We're going to lock these routes down. But, we still need to allow users to be able to sign up and sign in. Imagine an app saying you can't sign up unless you're already signed in.
[00:06:03] That wouldn't make any sense. But that what would happen if we added those routes here, so we're gonna make a separate sub router for everything that needs to be authenticated. And it will have something else for things that don't need to be authenticated. That way we don't have to do if statements in our code somewhere like, if it's this route, don't check for auth, that will be gross.
[00:06:21] So we need to separate them out. Okay, so let's make the stuff our resources. So I'm gonna say router and let's start talking about CRUD. So I'm gonna say get, request for /product. So this means I wanna get all the products, so I'm just gonna do that. And I'm not gonna put anything in these handlers, we're gonna come back to these handlers soon.
[00:06:45] Wanna copy that? So that's for the get all the products. Now I wanna be able to get one product so I can say id and express when you do something like this like :id. First, I can put colon whatever the hell I want it doesn't matter. This just means that this is a variable.
[00:07:04] This means that, I don't know what the value of this is gonna be and it doesn't matter I'm making a route for a get request/product / anything else that comes after it. I don't care what it is, I'm calling it id, so when I reference it later in my code I know that it's called id, and I'll show you where we're gonna reference it, but you can call this whatever you want.
[00:07:28] It's just saying like, this is what's called a route parameter. It's a parameter, it's dynamic. We don't know what it's gonna. We just wanna catch everything that looks like this. It's a URL that has something after product. So we got that. Now we wanna be able to update a product by given id.
[00:07:48] We can't update a product unless we know what products update so we need an id. We also want to be able to create a product, you don't need an id to create a product because you don't have the id yet, you're creating it so that doesn't need an id.
[00:08:05] You just post to products to create an id or to create a product. And then lastly, we can delete a products and we will need an id for that because how do you know what products to delete if you don't have the id for it? All right, so those are all the products stuff.
[00:08:33] And then it's mostly the same for everything else, right. So I can just copy all these. And let's do the one for updates. Paste that down here and I'm just gonna change all this to update, like that. I say mostly the same because it is until it isn't.
[00:08:55] We'll probably have to go back and like, that doesn't make sense. We don't want people to, I don't know, delete updates for some reason. I don't know, some things won't make sense depending on whatever experience you're trying to enable. And then for the last one, we have the Update Points, Update Points I guess.
[00:09:14] And same thing, now replace all the products with updatepoints all lowercase intentionally. I typically don't like camel case in URLs because I think it's just so annoying to write that in the URL in my opinion, so obviously it's keep them all lowercase. I also don't do underscores in my URL because I also think it's annoying to write.
[00:09:36] So I'll just keep them all lowercase. I don't mind writing and administering. I just hate writing them in the URL. To me it seems junky, I'll use someone's URL for the API and there's a lowercase in it or a camel case I'm like, I don't wanna use it now, I don't know it's kinda.
>> When would you use patch versus put?
>> Yeah, that's a great question. When would we use patch versus put? So technically, well first of all, you can just use Git for anything, you don't have to use any of this stuff. This is just what's recommended if you following REST.
[00:10:15] But technically, if you're following REST, put and patch the difference is put, for instance, if I was going to make a put request to update. Whatever I sent up on that request, whatever data I sent up would replace the entire update in a database with whatever I sent up, it will get completely replaced.
[00:10:34] The only thing that will stay the same would be the id. Everything else will get replaced. Patch doesn't do that, it will just only update the properties that you sent up and keep everything else the same, so that's the differences. Put completely replaces patches, but I just use almost never replace anything.
[00:10:58] So I'll just use put as patch and I just don't use patch because I don't wanna replace all that stuff. I didn't have the clients and all that stuff up I don't know and then validate all that stuff I don't wanna do that. So, I actually just don't use patch, I just put as patch I just never replace anything.
>> Would you recommend gRPC over REST?
>> Actually do like gRPC it's pretty clean. I would recommend using gRPC if your API was serving the purposes this one. As in, it's only gonna be used internally, for a client that you also work on. So if it's, we're making an API for this front end app that we're making.
[00:11:39] We're making an API for this mobile app that we're making. Yeah, gRPC all the way. I don't think I would use REST for that, it doesn't make sense. I don't need it to be broken up per resource like this because what happens is, if you do it the way that we're doing it out with REST.
[00:11:52] And then you go build out your dashboard that's using this, there's gonna be a page on it that needs updates, it also needs update points, it also needs products and it also needs users. And because the way that we designed this, there'll be five different API calls, right.
[00:12:09] Whereas gRPC would be, no I'm just gonna just call this one function that gets every single thing in the exact way that I need it for this page, because it's never going to change. Because it's for the app and if it does change, I can change it, because I also build the front of that.
[00:12:25] So, I think gRPC is great for that, but it's not great for this is an external API that developers are gonna consume inside their app. Okay, yeah, maybe gRPC is not it for them because it's too specialized, you don't know what their use cases are for consuming your API.
[00:12:39] So you have to be generic like this with REST and if you're gonna monetize your API kinda benefits you to make them make more API calls, I guess. Yeah, good question. Yeah, [INAUDIBLE].
>> Well, I've heard of tRPC, is that just the type-safe version of gRPC?
>> Yeah, tRPC is something new.
[00:12:57] It's yeah, it's just like the TypeScript version. It kind of basically does what Prisma does with the generation of the client except for it doesn't need to generate it, it just does it automatically using the power of TypeScript. So there's no step in between of a command you have to run to get the type checking, it just works out of the box and you can get the same thing with GraphQL.
[00:13:19] But you have to run a command, you have to take my GraphQL schema and output these TypeScript types that I can import into my react app and get those type check data. TRPC is like we just do that for you without having to type anything through the magical powers of TypeScript.
[00:13:36] It's actually be on me. I don't know how they do that in TypeScript, so, but it is pretty powerful. I've tried it before, I think they had to sacrifice a lot of developer experience in order to enable that. So I like that it works magically, but I don't like using it it's not pleasant to use.
[00:13:53] Is like using RxJS it's like I like it, it's cool but it's so hard to use, why would I use this? So, yeah, but maybe it'll come along.