3.8 Creating the Task Service
Now that you have your task repository implementation ready to go, you need something to call it. You could simply wire it up in the routes you already created, but what if you wanted to add additional logic for logging, validation, or any other business logic? We don't want all of that to clutter up our routes, so the best place to put it is in a service layer. Let's create that now.
1.Introduction2 lessons, 05:46
2.Getting Started4 lessons, 29:58
3.Building the API11 lessons, 1:16:10
4.Conclusion1 lesson, 01:37
3.8 Creating the Task Service
Now that we have our repository layer taken care of with the inmemorytask repository, we're gonna add one more layer on top of that as I mentioned before and that's gonna be our service layer. So what we're gonna do here is we're going to create a new folder within our source directory, and this is gonna be services. Now typically when we're dealing with services, what we want to do is we want to handle a lot of the logic in here. So if let's say I had a task service which I'm gonna create momentarily, and I have an operation in there of update task. What I'm gonna wanna do is I'm gonna wanna go in there and I wanna do whatever it is I need to do to update that task and then handle any other operations. Are there other things that I need to do? Is there logging I need to take care of? Is there error handling that I need to take care of? And this is usually a good layer to add in a lot of that logic. Now in this course, I'm really just gonna put in a little bit of logging in here but just to show you that there's additional things you can do in here. But you can obviously augment this and make it much, much larger and much richer of an implementation. So let's go ahead and add a new file, and this is going to be our taskservice.ts. So we're going to export a class once again, and this is going to be our task service. And within here, this is where we're gonna start to take advantage of the design decisions that we used for the repository in here by using the ITaskRepository interface. So what we're gonna do is we're actually going to create a private instance variable here that's going to be the TaskRepo, and this is going to be of type ITaskRepository. And then once I've done that, I'm going to also create a constructor that's going to take in a taskRepository of type ITaskRespository. And then all I'm gonna do in here is set the TaskRepo equal to that taskRepository. Now you may be saying, why are we going through all this trouble? Why are we doing this? Why do I even care? Well the reason that we're going to care right now is this is adding that added level of flexibility through what's known as dependency injection. So what we're doing here is we're saying any time something within our application uses the task service, it gets the opportunity to choose what type of implementation we're using of this task repository since this is an interface. So as long as I'm passing anything in here that implements that interface, I can use it here. So right now I only have the one. I'm going to be using the inmemorytask repository, but at some point maybe I have a MongoDB task repository, or maybe I have a SQL Server or Oracle, or any other database-type repository. Or maybe I have to get rid of the databases altogether and use a file-based implementation, or a web service-based implementation. As long as whatever I'm passing in here implements the ITaskRepository, I'm gonna be good to go. So we're gonna be able to see that in the upcoming lessons. But that's just a little bit of a taste of what that is for. So now what we're gonna do is we're gonna create a very simple implementation in here that's really just going to mirror what we did in the task repository. So let's go ahead and do a getAllTasks. And this is simply going to, once again, return a promise of an array of tasks. And then within here, once again because I'm doing a promise, I'm gonna wanna do an async. Now remember, our task repository that we're gonna be using in the in-memory version is asynchronous so what we're gonna actually do here is this is the first time we're going to take advantage of the await keyword. So since I am returning a promise, I wanna continue to pass that promise down through the layers of whoever's calling this. I am going to do a return of this.taskRepo.getAll. So what I'm actually gonna have to do here is I'm gonna have to say I want to await on this. Now typically, and you're gonna see this in the upcoming lesson when we wire this all into the routes is that this is really facilitating this ability for us to be able to do a lot of more inline coding instead of having to do all the callbacks when we start to wire this whole thing up. So now that we have getAllTasks, let's do getTasks, so we're gonna do an async getTasks. So once again remember this is going to get a specific task with an ID that's gonna have a number, this is going to return a promise once again of a task. And we're simply going to do a return, await this.taskRepo.get and we're gonna pass in that ID. And remember this is a good place to do any other logic that you might need to. So maybe in here, I'm simply gonna say, console.log, and maybe we'll say, Getting all tasks. And then in here we'll say, console.log getting task with id and we'll simply concatenate that on there like that. Okay, so now we have our two gets. Let's handle our create, so we'll we say createTask. And in this case remember we're passing in a task of type Task and we'll be returning a promise once again of type Task. And this is simply going to return the await. And once again, as you can see here, we're simply delegating all of these operations down the pipe as we go. And we'll go ahead and say that we are going to add this logging in here, and we're going to say Creating task with, we'll say, nameTask.name. Now this is also a good point where you might wanna do some validation if there are any properties in tasks or whatever your object is that are required. This would be a good spot to have those types of validations, you can also put that in here as well. All right, so let's do our update, so we'll say updateTask, we're gonna be passing in the id which is a number. And the actual task which is a Task and we'll go ahead and return this promise of a task. And then we'll simply say console, actually we can paste this in, paste and we'll say Updating task with id and then we'll return await this.taskRepo.update. And we'll simply pass in the id as well as the task. And then finally, we will handle the deleteTask and we're simply going to delete that task that has that number, returning a promise with that task. And we will go ahead and say we are deleting the task with that id and we will return await this.taskRepo.delete and we'll simple pass in that value. So let's go ahead and save that. So there we have it, this is a very thin layered service. Now obviously like I said, there's a lot of things you can do in here. You can add validation, error handling, additional logging, maybe you need to call out to additional services and do all sorts of other operations, but this is typically where you would do it. But the nice part about this, once again is this dependency injection concept where we're passing in an instance of the ITaskRepository. Which I'm gonna show you where it really comes into play in the next lesson when we wire up our service into our task route.