🔴 LIVE CODING: Let's Build a To-Do List App | BACK END PT1 | (React, Vite, MongoDB and Molecular JS)

Live coding session building a to-do app backend with Molecular JS and MongoDB. The presenter sets up REST endpoints for create, read, update, and delete operations, validates inputs, and tests everything with Insomnia and Mongo Express.
Chapters
Today we're working on a to do app. It's going to be a full stack, front end and back end. Just simple full stack to do app person will be able to add todo item to do Item will be ID, that'll be auto generated by MongoDB. A task that's a string created and updated at and deleted at and deletedat will start as null. And all these will be strings, date strings, new date, isostring to isostring. And front end will have button to add to do list item. It'll display the to do list to do's in a list format and then you can update or delete that item. Backend will have a crud, that's for todo. That's a create, read, update, delete. So the endpoints will be API v1, todos and it'll have add task, get tasks, update task and delete task. And the front end will use Axios for HTTP requests. And the back end will be molecular JS and that's going to be the link will be molecular services. We'll be using Mongo and Mongo Express and Docker. Oh, and nats inside of Docker compose and then use Docker to run those. Hey, what's up? Minsu. Oh, okay, you're muted. All right, well, let's get started. So I started the to do backend and the to do front end folders. So the front end was using byte. I'll show you the commands. So I think the to do back end was. Let me just look at my history real quick. History. Let me see here. So it was. So I installed molecular CLI globally and then molecular init project to do backend. And for the front end it was npm create fight @ latest. So those bring up prompts to bring up the projects with the, with the, with the files included. I like to use molecular because they give you a lot of boilerplate code and it's very simple to structure. You just put up your services inside of this folder with the service js. So I'll explain that in a second. And then in the front end this is just straight up, just straight out of the box using byte with react and typescript. And I just deleted everything in the app tsx. So let me see, let me show you how that looks. Right now it's just to do front end. I mean if I add another one of these ones or something, it should say to do front end two times. Yeah. And it has some built in CSS from here that I'm not going to mess with for now. And in the molecular. This is the website. Oh, that's the Docker hub. This is the website. So this is the NPM cli. So I'm using the CLI to edit the project. And I just added a couple things in the docker compose, which was Mongo Express. And then I just opened up the port 27017 for that's the default Mongo. So that's on the port. And then I just added the Mongo Express configurations and I think that's about it. And I'm using the Alpine image for nat. So let's get started on the back end. So let's just clear that out. Maybe I can just make this little bit bigger, but then it's kind of hard for me. I think this is a good size. All right, so what we're, what we'll do now is we'll start the. We'll go into the to do back end and we'll do. Oh, and then in the environment folder file I put the Mongo URI which is going to be needed for the mixins and the DB mixin. So it's looking for process m Mongo URI and then it'll stick the Mongo adapter into the there with the Mongo adapter with the Mongo uri. So the first thing I would like to do is inside of the molecular config file at top of file I'd like to say oh, and I installed ENV for the to use the environment file environment variables. So that's going to be inside of the dev dependencies dev env. So in the molecular config I'll just put require ENV config and that should just make it. Make it so that we can use the env file. So then if I just do docker compose up D nat Mongo Mongo Express, it should be able to run those images, run those from the docker compose. And then from here I will get rid of the greeter service and the product service. I'll just delete these guys. I will keep the greeter, I'll copy paste, I'll copy the greeter service and then I'll just make something called v1todos service js paste him. We'll call this guy to doods and I think we got version one. Let's look at this guy. Dependencies, actions don't need any of this. So get rid of all these guys. All right, so let's just look at here, get here services. So just read settings product Service real quick. So we need to add the mixins to do service. So name like this and we'll say const DB mixin equals require at dot slash mixin slash dbmixin and this will be to do's. All right, let me delete this guy now from products, we also need settings and then fields. So these are the available fields inside of our to do in inside of our API. So we said in our readme that we'll have ID task created at and updated at and all this stuff. So let's put that stuff in Oops ID task whoops created that, updated at, deleted at. Cool. And I think that should be good for now. And then I think we do need const Molecular client error equals higher equals at molecular errors. Okay, so where I like to use it is we'll just make a nice little health check. Action rust get ping async handler handler return at pong try catch throw New molecular pioneer. I don't think it'll ever get in there. So we don't need the try catch. So let's give it. Let's run our backend, send the package JSON. Let's close all these files real quick. There's NPM run dev. So that's going to run the molecular runner and then it's going to have the repl. I'll explain that maybe later and then the hot refresh. So if I save it'll refresh the file. So NPM run dev. So whoops. I have actually run the product service which has a cdb, so I'm going to remove that real quick. And now that we run everything, we can go local host 8081. That's going to be the Mongo Express. This is the to do backend this CDV ran. I'll just delete it real quick and delete that and then let's just run this real quick and in the todo service, stop the server. Cool. Oh crap. Let's do that real quick. NPM run dev and local local host 3000 API v1 to dos/ping it should say pong. So that, that's our endpoint working. So the way that molecular works in this service, file actions will be your HTTP requests and your methods will help, will help, you know, be your helper functions. Like I said, it looks kind of like Vuex if you've ever used Vue. Like I used to use Vue 2.0 and Vuex used to kind of be structured like this. So I like the way it looks. And you have a couple Other things like events. So when an action gets called, you can automatically run this. And when it's created, it's kind of like a hook when it started. So this is like service created, lifecycle, event handler when it's created service when it started and when it stopped. So I don't really use those that much. So let's go here, let's stop the server. Whoops. Stop the server. And then in the actions here, just put a little comment here. This is description D1 Todo Service. All right, and then we'll just do here we said we're going to make add task, get tasks, update. Let's look at the review real quick. Update task and delete task. Update task and delete task. All right, so these are the what we said we're going to make. So I think first we'll say add task. So let's call it add task. That's the action. And by this name you can call them with the broker from the other files, other services. But we won't do that for now. So we'll do rest at a post add task. And in the params I think all we need to do is say we need a task. It's going to be a string and it's going to be optional false and async handler ctx. So that's our context. We're going to say try catch, throw new molecular client error error to string. So first thing we want to do is want to grab task from CTX params. There you go. Now with that task, maybe you want to make some kind of method here called like to do to do todo item and then say this takes a task and we'll say return. It'll be an object, it'll be the task, it'll be const. Now equals new date to ISO string. I'm going to say created at now, updated at now and then we'll say deletedat equals null. So now we can call that here you can say if. Now let's just do. All right, const const item to do equals this dot to do to do item and then we'll add the task here and cool. So now if we just return to do. Let's try that out. So all right, now let's open up my insomnia here and just do something here for the personal project insomnia. Let fill. You can add to do this guy delete. And then we'll just right click we'll add something HTTP request, bring it into delete and we'll add an HTTP request here and we'll say post here. Let's say v1 to DOS add task there we are. Now just to name it and all right, so HTTP/local host 3000 API v1 to do's add task so that's what we need to do. We need to send a body JSON task test task. Let's see if it works. So we get back a a task created at, updated at and then deleted at as you can see. So that's the functions working for the to do item. Now we need to add it into MongoDB so we can say const insert to do item equals await this. Adapter. Insert and then we'll say on the to do and then if something happens here, right? If, if it returns null or something, we can just say throw item did not get added or we can just say something went wrong. Something went wrong. All right now, now if it's all good we can say hey, we want to, we want to return that. So right now in our there's no database yet because there's no data. So if I run the insomnia one more time here, let's actually put this here so we can have our code open, we can close, we can minimize that and we'll go back here, we'll send it. So now an ID is auto generated test task and then we'll say we'll look here, we'll refresh. Our todo backend is here and our TODOS collection is added with an ID 669D whatever 565C. Alright so now if we wanted to get that. So let's just add another one real quick. Test task to send. Now we get it. Now we have two items in our database. There we are. All right, so now we got to get those guys. All right, so oh you know what else we also need? We also need a status, right? And then status will always. We can kind of say this is not started in progress and completed that let's add those and then it'll start it not started yet. So here we'll say status and then not started will be how it starts. So let's delete these guys real quick. All right, so whoops. Test task send. So now we have status here and it's saved inside of our db. Not started. And let's just send one more test. Two send. Now we have two cool. Test task and then we have a status. Coolio. Now if we want to get those guys we can say make something called get tasks and we'll say rest get get tasks. But then if we want to send. I think it's like this, it's optional task id. Let's look it up. Molecular optional path param. Is it possible to have path parameters do optional path parameter node js okay, so it's a question mark afterwards. Okay, so there we go. All right, so now you can say params and task ID can sometimes come. That's going to be a type of string and optional and that's going to be true. So those are the two so far and async handler CTX and you can say try catch and so if, wait, if CTX params task ID, we want to just return one so we can say return this adapter.find find one. No, no, you can say this.getbyID and that will be at the CTX params dot task ID. All right now and I would like to a wait on that as well. All right, so and then if it's not, we can just return this. Adapter. Find at and that's going to be. And we just want all of them. So let's just do that and then maybe we'll add a sort later. Let us for now sort created at. I think this is how you do it. All right, all right, so now if we go to local host 3000 API v1 todos get tasks. So now we see the two tasks here. If you want to see how this one's working. I think I use a Chrome extension called JSON view and cool. So now if I want to just get one, let's say I take this ID and I stick it in the back here. I get that one task, which is pretty cool. So now get tasks is pretty much done. We'll do update task. So update task and then rest on a put at update task@task ID. So we're going to need to send task ID there and then in the params task ID will be. Will be type string and optional false. And so what do we have? We have. We have the task that we can update, right? So we have type and then task that needs to be updated and then optional say true. No, no, I want to do like this. Update task and then optional false and then async handler tx because I'm going to make a separate endpoint to update status. It'll be a little bit like cleaner in my mind because I don't want this update task to do two jobs, I guess. And we need to call UpdateStatusScot. There you are. And then const task ID and task from CTX params and then so first now we need to do const. Update task task to update maybe. All right, whatever. I don't care anyway. This. Adapter.update by ID and that's going to take the ID and then we'll take the task ID in there and then we'll put set which is the update command. And then we'll say task that's sent and then updated at at the new date to isostring and then we'll just do the same thing. If task to update. Let's just call it task. Oh, update it. Update. We'll just call it update. All right, there we go. All right, Update. And then if update something goes wrong here, which is something wrong. There you go. And then it's all good. We'll just return the update. Update. Just return update. All right, cool. So we'll bring up the insomnia. Let's go here HTTP request v1todos update task and put HTTP localhost 3000 API v1 to DOS update task and then we would like to update like let's say this one, it says, it says test task. It's the first task. Right? So we'll do, we'll put that ID there and then we'll put the body of Jason and I'm expecting task and updated task. All right, so if we send that over date to isostring is not a constructor. Oops, one second, forgot. So like that I like to use the molecular client error error to string because it kind of tells you a good error message. So if I save here now. Whoops, I don't know. Cancel. Alright, so now it's updated task not started. So if I go back here, I refresh, it'll be updated task. If you check the Mongo express it's going to say updated task on task one. And if I just go and get all the tasks now it'll get task two and updated task and for some reason the sort is not working. Oh no, no, it is working because you want the newer ones up top. Right? So if you want it just to create it at, it'll be like this. But we want it. We want the newer ones on top and the older ones. Yeah, I think so. All right. Oops. All right, cool. So now we need a delete task. All right, but we also need to update status. So let's just copy paste this guy and we'll call this update status status and then task ID optional false and then status type string optional false and Then in the fastest validators, there's something called enums. It takes only these values are allowed to come. Fastest validator, then come here enums. Fastest validator, then come here enums. Enum. So type array items and then enum. And it's only allowed to take. Not started in progress and completed. I think that's what I said. Yeah. Save this guy. So then let's go back to our insomnia and let's go v1v1todo/updatestatus. Let's just click to do. To do ID. I think that's what I called it. Task ID. Why didn't I call it to do ID? All right, whatever. Let's go with that task ID, just so I know. And then task ID here, that'll be HTTP localhost 3000 API v1todos update status. And we'll take this, this ID here. We'll put it at the end here and then go JSON Anyway, all right, if I'm here, I don't know, and then say status. And then what if we put something wrong? Let's go like this. Whoops. Oh, put not resolve host name. Well, let's just do like this. And let's just return true really quick, just so I can see. Oh, there were two slashes. All right, so if I do like this, it's going to say parameter validation error status field does not match any of the allowed values and it's expecting not started, in progress, or completed. So if I say now I change this to in progress, it'll say it'll. It'll pass the validation. And so let's work on the API real quick. Uncomment this task ID and then we're going to ask for status from the params. Status will be updated. And then if something went wrong. So that's pretty much the same thing. Maybe we could, you could kind of refactor this out into a method. But let's just chill up off it for now. So now if I change this, it'll say, hey, this guy's in progress. And that'll be reflected here in progress. And it will be reflected here. So in progress. Cool. So maybe in the get tasks I want to send a status and then type string and it can be optional. Optional. True. And this is going to have the same enum. So I'll copy paste that enum here, here. All right, so we can do something like this. Let Q equal empty object. I'm going to say query equals Q. And then if CTX params status, we can Just add Q status will equal CTX params status quo. Cool. What's that doing is if the, if, if I want a status, add it to the query object and then it sends it out to the query. So let's check that out. So we have get tasks. So if I send you something like status and I only want the in progress ones, that'll only give me the in progress ones because it send it off the query and then if I accidentally put 2s, it's going to give me a validation error. So molecular is pretty cool with this. It has everything built in, batteries are included. So get tasks. Cool. So now we just need to do a delete task. All right, so I'm just going to put a delete task and rest delete on delete task and then that's going to have a task ID and params task ID will be a type string, optional false and that's going to say async handler ctx. So there's two type of things. There's a soft delete and a hard delete, right? And a hard delete is kind of like it really removes it from the database. And the soft is you just set the deleted at to null and then up in the get we'll just make it so that whenever you get something from here you don't. You only get the ones that are null. So let me set that up here. So in the get tasks I will just set this and I only want the deletedat where it's null. So if it has so if it has a value at deletedat I don't want those because those are deleted. So in a soft delete case you can actually undelete, right? And then we'll actually make a hard delete later. So this will just be a try catch const update equals await this adapter.updatebyid and then that'll take the CTX params task id and then atomic identifier set and then delete it at will be now equals new date to isostring and that's going to be now. And then it's actually updated at. And then for some reason if this does not work, we can say throw something wrong. Whoops. And then all is good. Return update. Okay, cool. And I feel like these, these three endpoints kind of have the same logic. So maybe we'll refactor that out so we can add a method and we could kind of call it update to do task. Update task to do item. I don't know why. Okay, Update to do item and Then we'll say something like async and we can say if it's. We'll say something like. So we're just adding a different field, right? Status or task. It's task status or deleted at, right? So we can say field and value. And I think we can just say so the const. If field thinking. So the field will either be updated at. No, no, it'll be status. So just put a comment. Field will be status, task or deleted at. Right, As a variable. So let's do it up here. So it'll be a string. It's going to be task, status or deleted at. And the value value only comes in for task or status. All right, let me think here. So const update equals await this adapter.updatebyid so we do need the ID. Just put that up here. ID. I like to put an underscore. So ID and then get to set. And then no matter what, we're going to do the now thing, right? Const. Now equals new date to ISO string. And then updated at is always getting called here. And then for here we can take the field, right? And then if field equals deletedat, then we just want null else we want value. I think that could work. But value is going to be sent anyways. So we can do like this. And if you put the brackets, square brackets in the key of an object, it'll equal out to the field that you're sending. All right, so let's. I think we've just. This will work a little bit better. So return update. I'm in some kind of. All right, here. Return update. And then maybe here update to do item. Now kind of just remove here. And then we can say. And then we can take this out too. Oh, wait, wait, wait, wait, wait, wait, wait. Yes, yes. Cool. And since we're already doing here, we can do. We can do something like this. No, never mind. It's getting too crazy. So in the delete task we can do now and then const update equals await this dot update. I think that's what I called it. Update task update to do item item and then that takes an id. So that's going to take the CTX params task id and then that's going to take deletedat and that's going to take a now. And then we can just return update and let's try it out. So now we have deleted that here. That's the updated task. Whoops. All right, now v1todos delete task task ID and then I'll just make it A delete even though to put localhost 3000 API v1 delete todos, delete task and then I'll just take the task ID from here, there and then if I delete it. Cool. It adds the deleted app and now if we get it. Now if we get tasks, this guy won't show up because the it has it deleted at. Alright, cool. So let's make an undelete too. So recover task and rest and let's get post at recover task at. Let's make it a get whatever. All right, and then we'll just make a task ID there and then params task id and then that's going to be type string and optional false. All right, and then async handler cta and then what do I want to do here? I want to. So I would like to do the const get task equals await this getbyid. So these are all like methods and things inside of molecular or the DB adapter. So you can look through the documentation. It's all there. You can look through the node module, it's all there. So disk getbyID on the CTX params on task ID and then if get task if it doesn't come back we can say throw not found task not found and then if get task dot deleted at, that's still null, right? If it's null, throw task is not deleted. And okay, so if it's all good, we can say const recover equals await this adapter dot updatebyid and we can say on the ctx.passams task ID set and then update it at and we'll say due date to ISO string and we'll update the deleted at to null. All right, coolio. And we'll return the recover. All right, cool. So just open one more. This guy's not working right now. Okay, let's actually let's do one more. In the get tasks, if recover get deleted like this and that's true. And that'll be a type boolean and that would be an op. Wait, no, no, let's just do a get. Ah, forget it. Let's not do it here. We'll make another one there. Alright, so I think our recover function is finished. So let's just go here. Then get tasks. We want something called like recover task and then at the id. So we'll go back to the insomnia, we'll get the id, do that one, delete it as back to null and we get both the tasks back. Cool. So we can delete it. So. So far. What do we have? We have, we have add task, get tasks, which has a get task update, task update status, delete task. And then we have recover task. And molecular is really cool because it has a built in kind of postman thing. We go to localhost 3000 so the rest APIs and then in our to DOS we have the add task, get task update, task update status, delete task, recover task. Cool and cool. And now we'll connect it to the front end. Thank you.
More from Phil

day in the life of a software engineer | 5 hour productivity | building my dev agency 🔥

day in the life of a software engineer | 3 hour productivity | coding my 6-figure community startup

day in the life of a software engineer | 5 hour productivity | coding our sns startup app LFG

day in the life of a software engineer | 5 hour productivity | creating apps that makes big money






