Starting the App & Exploring Routes
Alright, so we're back with part two of our Nest tutorial. So in the last video, we went over all of the files, we went through the file structure of our project. So now what we're going to do is we're going to actually start up the application, because I actually didn't get a chance to do that, but we're going to start the application.
And I'm actually going to change this to port 4000. Actually, I'm going to change this to uh 8000. No, oh you can use any port you want. I'm just going to change this to port I'll do 5001. And I'm going to go ahead and just run yarn start:dev. So that will run this dev script. So pretty much just, we'll watch it, we'll just pretty much watch our files so whenever we make changes it will restart. So let's hit enter.
And you can see that we have our logs over here. And you can see over here that there is this router explorer and you can see that it literally mapped this route over here. So if we were to... so this is actually a good way to keep track of what is actually being picked up in your application. So in case if you ever are concerned if a controller is actually used or if it's actually mapped, you can tell by looking at the logs.
But if we go to our API, you can see localhost port 5001, we get 'Hello World!' and that is from the return, that is the return value of the method getHello from app service, and that is being returned when we call this.appService.getHello() for our getHello function inside the app controller.
Cleaning the Project & Generating a Module
So let's go ahead and actually delete everything. So what we're going to do is we're going to delete the app.service.ts file, the app.controller.ts file, and the app.controller.spec.ts file. So we're going to delete these three files and what we're going to do is we're going to go ahead and create our own module. Because we don't want to actually put everything, like we don't want to put individual controllers inside the app.module.ts, we should really create our own module that belongs to the correct domain, and then we can put everything in there and that will be imported into the app module. Before we do that though, let me actually go ahead and remove these two imports as well as this and this. Okay.
So what we're going to do is we're going to use the Nest CLI. So let me exit. I'm going to go ahead and type nest and I'm going to go ahead and type generate. So what we're going to do is we're going to go ahead and generate a module. And let's just say for example we're building an application that has customers, and customers might have products or they might have purchases or payments, right? So typically, we'd want to separate each module into its own domain. And in the documentation they actually do kind of, they actually do go in-depth about what modules are. And you can see that it's a way how we can organize our application.
So instead of putting everything inside of the root module, so that was the app.module.ts file, you can actually create your own module. And this becomes very useful because, like I said, you can keep everything encapsulated in its own module and it allows you to pretty much keep everything more organized so you don't have to put everything in just one single module. Okay and there's a lot of documentation that tells you on how to configure your modules to do literally whatever you want. But let's go ahead and just generate a module. So we'll generate a customer's module, so this will just be, this will represent the customer's domain. So you can think about every single endpoint for customers will pretty much be registered in a controller that belongs to this customer module. Okay.
So now that we have our module, you can see that this is what the module looks like. It looks very similar to how the app.module.ts file looks like, except it just doesn't have imports, controllers or providers. Not yet at least, we can always add them. Okay.
One more thing to mention is that when you use the CLI, it will automatically add the imports to the app module inside this imports array. So that's really nice. If you don't use the CLI, if you want to create your own module from scratch like this, you just have to import it manually.
Understanding and Generating Controllers
Okay, so let's go ahead and create the controllers. So we're going to create a Customer's controller. And remember the controller is actually going to be responsible for controlling the request and the response. So if you've gotten used to using Express before, you may have not really heard much about what a controller is. You're used to using the callback function and using the response object to send responses back.
So we have something called a controller, and what a controller is, is responsible for handling incoming requests and literally returning whatever response we need to return to whoever made that request. So typically the client. So let's say for example you have a front-end application that needs to make a request to some endpoint that returns a list of users. So let's say it returns five users, so you have a controller called UsersController that handles all of that logic. Okay, it's going to handle the request, it's going to control the request. By it could do things such as checking to see if the user is authenticated. It can check to see if the user had a correct query parameter etc etc. And once that's done, it can send back the response. Everything is done inside the controller level. Okay. So, and you'll see how easy it is to use controllers.
So let's go ahead and generate a controller. So you can actually just type in g for generate and we'll go ahead and type controller. And I want this controller to be inside the customers module. So I'm going to pass in customers/ so that's basically saying it's going to belong inside the customers folder, but I want it to be inside the controllers folder, and I'll call this customers. Okay, so what this will do is it'll generate a controllers folder inside the customers folder, and it'll create another customers folder inside controllers because we might have other controllers too inside the customers module, so that's why I'm creating its own folder over here. So for example, we may have something like customers-details or something, I don't know, just an example. So we want to keep everything as organized as possible.
So you can see when we generate a controller using the CLI tool, it creates two TS files. So it creates a spec file and it creates a controller file. So we're going to work primarily with the controller file. Okay, and you can see inside customers.module.ts it will add the CustomersController to the controllers property inside an array. Okay, so you need to make sure that your controller classes are actually inside this array, otherwise it will not map your controller routes. So your controller routes will not even be accessible.
Implementing a GET Route
Okay, so now we have a controller. Let's go ahead and get started with setting up a route. So what we're going to do is we're going to go ahead and use the get request annotation or decorator. And we can just leave this empty or we can specify a pair of empty strings or empty string. But if you want to specify an explicit route you can just provide the actual route value inside this, inside these parentheses. So what I'll do is I'll just simply say getCustomer, and I'll just return a customer. So let's just say email: '[email protected]', createdAt: new Date(), and we'll just say id: 1. Let me actually move the ID up here.
Okay, so let's go ahead and let's actually try to call this /customers route. So what I'm going to do is I'm going to go over here. If I refresh, you're going to see... actually I have to start the application up. So let's do that. Let me actually start the application in VS Code, so that way we can actually use this terminal that I have opened up to generate any files that I need to. Okay.
So you can see that right over here in the logs in router explorer, you can see that it mapped this /customers route. Okay. So let me leave the logs over here and let's go back to over here. If I refresh, you can see that it says status code 404 Cannot GET. So this is by default what NestJS will do for you. So let's go to /customers now, and you can see that we get the response back.
So what we did was we made a request to /customers and the corresponding controller that is responsible for handling all routes for /customers took care of this request, and it responded to us with this object. It has an ID, email and createdAt.
So that is what the controller is responsible for. It's literally responsible for controlling the incoming request and providing, returning back some kind of response. And that response could be anything. Okay, it can be a successful response, it can be a forbidden response, an unauthorized response, whatever it is.
The Role of Services for Business Logic
Now, one thing that I do also want to mention when you use a framework like NestJS is that you typically do not want to practice putting everything in one single file or one single function call. So NestJS, one of the reasons why I like it is because it introduces actual good practices and it enforces it. It actually teaches you how to practice certain concepts such as the DRY rule which stands for Don't Repeat Yourself. So essentially, we don't want to put everything in one single function call and we also want to separate concerns as much as we can because when you have a function that does so many things, and especially those things aren't even what it's mainly responsible for, it actually makes the function a lot harder to test.
So what we want to do is instead of actually putting everything inside the controller, instead of handling all the business logic in the control layer, what we can do instead is we can actually create a service. Okay, and the service what it will do is it will actually take care of handling our business logic. Okay. So when it comes to doing things such as, let's say you want to perform some kind of business logic. You want to check to see if the user is in the database, you want to check to see if the user has a certain field that is set to true, you want to set, you want to check to see what the user status is, etc, etc. And if the status is, you know, something like approved, then you want to perform some other logic, some other database call. Typically you do not want to do that at the controller layer, you want to do that at the service layer.
Another thing to mention is that if you think of it in MVC terms, the service layer essentially is a layer that can communicate between the controller as well as the repository layer. So when I say repository, typically the repository layer is what is responsible for interacting with the database. So performing reads, updates, or deletes or create, right, like if you're creating data, the repository would take care of that because it directly interacts with the database. Okay, for the service layer, that is what we are using the service for. So let's go ahead and create a service. And once we create it, it'll actually make a lot more sense.
So let's use the CLI tool. So we'll do nest g service and the service is going to be inside the customers module. So we'll do customers/services and then we'll just do customers. Like I said, we might have other services that belong to this customer's module, so that's why I'm creating a folder for them.
Connecting Components with Dependency Injection
So you can see right over here we have our service, CustomerService class. So now you can see over here that in the customers.module.ts file, we have a providers property and that's also an array, and you can see the CustomersService is a provider. Okay, and what that means is that we can actually use dependency injection to inject this customer service anywhere we want. So for example, if I were to create a constructor, I can follow the same example that we had saw from the app controller. So I can do private customerService: CustomerService. Okay, and now I can reference this customerService and call whatever methods it has.
So let's go ahead and let's move this return. We'll create a method inside CustomerService and let's pretend like this CustomerService class has like methods that it can that it can interact with the database. So for example, findCustomer will return a customer. Okay. And then what we'll do is we'll return this.customerService.findCustomer(). So what's going to happen is we're going to call the customerService instance's findCustomer class and it's going to return this this object over here, and that will be returned as a response. So if I refresh the page you're going to see that it's literally the same thing.
Now, one more thing that I do want to mention that I completely forgot to mention is that you'll notice that uh your files are actually conveniently named after whatever type of resource or schematic it is. So for example for your controllers by default they're going to be generated as, they're going to be generated with the .controller.ts extension. For services they are generated with service.ts and with modules they're generated with module.ts. Okay, so it's a really nice convention to help you keep track of what is what. So it's easier to navigate through your file system.
Recap & Next Steps
Okay. Um, so that is pretty much it when it comes to our controller layer as well as our service layer. Okay, we pretty much set up a custom controller and we have our own custom route, and that route pretty much will call the CustomerService findCustomer method and what happens is it returns an object. So what we did was we pretty much encapsulated the logic of returning a user from, we encapsulated that inside the CustomerService class. And now the controller can actually just communicate with the service layer and just get whatever it needs to get and we can return that as a response. Okay?
So that's going to be pretty much it for this second tutorial. Um, in the next tutorial, we're going to continue with more NestJS related stuff such as setting up POST requests, setting up requests and responses, and etc, etc. Like, so we're going to go fully in-depth with this tutorial. So I will see you guys in the next video. Peace out.