Loading
Lesson 14
Courses / Full Stack Web Dev Bootcamp (July 01 - July 12, 2024)
Backend for Messages - Full Stack Web Dev Bootcamp Day 7 (2024-07-10)

The lecture continues building the backend for the React app, the comment feature.

It leverages the messages table created with PostgreSQL.

You learn to build more endpoints, such as accessing a single message and creating a message.

You learn how to debug a Node.js Express app using Visual Studio Code debugger, using breakpoints.

You learn how to send back JSON responses, leverage middleware, etc.

Video Transcript

Let's get back. Now I want to show you a couple of things before I do the create message. And that's just to do here to get a single message. How would we do that? And keep in mind, I didn't tell you that obviously, you know, real scenario, we'd have probably millions of messages. So we don't want to be doing a query without limiting, right? So usually people would paginate. So they would add limit, you know, maybe 100 per page, and they would use offset to paginate, and skip the first 100, skip the second 200, and so on. Okay. Keep that in mind, because our data sets small, that's why it's okay. Anyway, what if I just want to get one single message? I know we don't have that functionality in the front end, but that would be interesting to do here just for the sake of example. And then I'll show you how to use the debugger and visual studio code. So let's do this to do. So basically, if the user go to slash messages slash the ID of the message, they can get the information object for that message. So app dot it's a get request, follow REST convention. Now the path is going to be slash message slash the ID. But how do we have, how can we do that? Because it could be varied, right? It could be one, two, three, so one is the one. That's when programs come in. So you have to put a colon, and then call it message ID or whatever. And that value will be available to you in rec.params. As you're going to see in the second function of rec res. If you want to access the whatever the user type there, it's rack params dot message ID. And this message is whatever you type here. Okay, so that's a dynamic pyramid. Start of the colon there. Okay, great. So what we got to do is first, okay, somebody's requesting to see message by its ID, we got to look up in the database to see if it exists, right? What's the query here, we're going to use pg client query, select star from messages where the ID is equal something. Well, somebody might be thinking, Hey, why not? I don't know, put a plus here, rack params message ID, or interpolate with like this. No, is that good? No, don't ever do this, because you expose yourself to SQL injection, because this remember, the user could come in and type whatever here, right? So they could type one like this and then somehow delete from messages, whatever, they do something malicious. And this something here would be going here. And you see what happening. It's like going to execute select and then delete it's going to delete all the messages. So don't ever do that. So you want to be using a placeholder here. So what you got to do is use single quotes. And you can use a placeholder $1. And then outside as a second argument to query an array with the placeholder values in sequence, if you had more than one, it'd be $1, $2, so on. And then you put them here in order. Okay, and then this returns a promise, we can do that then result. And because it's an array of things, we got to get the first one, right? Assume it exists. What if it doesn't, right? We got to check, right? So result dot rows. If, so this is an array, right? Array could be empty, or it could be something there. So how do we check the number of elements that's not length of an array? So you got to check if that is, you know, if that is zero, if you can use like this, if parenthesis, if this condition is true, do the following between the calibrations. Else, do otherwise, if this is false, do what's between the calibrations for else. Let's call the if else. Okay, so if it's not empty else, that means there's something and we could just return, right, the response. Sponses and result dot rows, the first element, bracket zero. Otherwise, okay, what do we do if we don't find anything usually 404. We send a status code 404, if you ever heard that 404 not found, it's basically a code that we set. They can do like res dot status 404. This is how you change the status code in your reply response. Just put a dot status and the name number here. We can do that. By the way, I always would return before my res send or whatever, because this could have kept going in the code, doing other stuff that I don't care about here, or elsewhere like here, for example, I had something doing there. For some reason, I left it without return. It would send the reply and do something afterwards, which might be undesirable. I always take care of that if somebody were to accidentally do something, write some code after this without being aware that this doesn't actually return or stop the function execution. Be careful of that. Anyway, here, just 404 and send nothing, I guess. You don't have to send anything, but much for their surprise. Okay, let's debug this. By the way, I want to debug and show you how to do it. So in Visual Studio Code, you can actually place breakpoints here in the line numbers. So I want to do a breakpoint inside here. How would it stop at that breakpoint? Well, first, we got to make sure we call node with an option to inspect. So kill this server, say no dash, dash inspect. Let's try that one first. And index.js. I see now the bugger is listening here. What we got to do is attach to that process with the command palette view command palette, and attach to node process. And you're going to pick the one that's running, make sure it's the one, it's the correct one. I think it's this one, right, the first inspect index. Now it's, you see the server is running, the code is already running, the server is running. All I got to do is trigger this endpoint here. How do I trigger that? Well, I just can go to the browser and try to get a message. Let's go, let's go. Share browser, localhost 3001 slash messages slash 123. This one doesn't exist, right? Let's see what we got. Enter. Now, you see it's hanging. It's hanging because the Visual Studio Code is waiting. It's paused right here so we can inspect things. For example, what's in result? Let's hover. Oh, that's what's in results. Oh, there's some rows, zero rows, length is zero. See that? Or you could type it here in the debug console rows. Oh, that one doesn't work. Is it result? Yeah, sorry, result dot rows. Like that and length. You see it's zero. And you can see rows. Sorry, result. And you can expand and see what's inside and so on, right? So to move to the next breakpoint, you press F5 or continue here with display. If you want to go to the next line, it's going to be step over with F10. We see here that rows length is zero, right? So it's going to go to line 33. Now it's in 33. Now it's going to send back a response, the status 404. So let's press play. And that's it. Let's go back to the browser. And it just took too long. That's why it crashed because we paused for too long. But if you try it again and click play, I'm clicking play and that's code. Let me refresh all them. See what's going on. There you go. Last play and visitors to their code. You got a response. Let me put it again here. Network all. And you can see I got here 404. See the status code? Now let's try something that exists. I think if I look at PG admin ID one exists, let's type that and debug. Now it's here. What's in result? We got result of rows one. And that's that one, right? So if I go F10, it's going to go to else. And else because result rows, right, has an array, the first one is sub zero is going to give back this object, which seems to be okay. Play, go back. You should see it here. And if I pretty print is like that. There you go. By default, it's 200. Okay, the status always when you don't specify dot status. Okay. Nice. So that's the debugger. Let's stop. Let's stop the debugger going back to VS code. So you want to detach from the process by clicking disconnect here. If you don't want a breakpoint anymore, can remove it by clicking again. And the terminal you want to kill that and not use inspect anymore can go back to run that. Okay, so that's nice. We saw that this is what the user typed. We changed status with that. We learned breakpoint through VS code. And let's do the creation of messages. So usually to create messages, we use post instead of get. So even though they can have the same path, the verb is different. Therefore, it's going to be a different path of the request coming in coming. So app dot post instead of get the path slash messages. And then you have a handler function the same way, solve it the same way. Okay. Now we got to think the user is going to use a text area and submit that where comment rate. How do I access that? Well, the request has a body. In that body, there will be a string or a text in format JSON with the comment property. How do we extract that in express? Well, we can use a middleware for that instead of us doing from scratch, we can use what's called the express dot JSON middleware. So you can use app dot use here to use that middleware and it's called express.json like this. So when you call this function, it returns another function definition with remember rack resident next, and it's going to do some work to extract from the body of the response, the data and convert that to a JavaScript object. Okay, and then it's accessible in rack dot body. That's how you get that. Okay, not a way of debugging as you can console log this here. Put some identifier so you know where exactly you are. Maybe a post slash message is rack body. Let's send something right now. Return rest and by the way, I can also use JSON. That's fine as well. Same thing. We'll actually call JSON behind the scenes. Rest. Let's see the log. So you're going to watch the console as I'm making the request here. But actually, we have no way of making a post request through the browser because by default is get. So the only way would be either we use a rest client like postman or an extension of VS code. Or I can go to the front end here and try to submit this. But to do that, we got to change this form where it's going, right? Let's go back to the VS code. If you recall from the front end, web client messages, JS, when we click to add a message, it calls this function add message. And it calls fetch with method post. Instead of this, we're going to do HTTP slash slash co co host three thousand one slash messages. And it's going to be post. We got everything. So it's basically just change this. Now let's go back. Try. I just want to watch the network tab. XHR, clear everything. And this is what we got the response to be the test, right? But I want to watch the console. What's in the console? Do you see the console here? Remember, we wrote this so we know where we are in the console log. And this is the logging of that rec dot body. It has the comment. So we have access to that. Anyway, with that in mind, going back here to the post messages, we got us do first, you know, it's a bit more involved here. Basically, rec dot body, the user could send pretty much anything they want. So first, we got to make sure to remove anything undesired. So one thing you would do is filter out undesired properties. For example, the user could be sending comments 123 and then do something bad 123 another. It's nothing to do that. I don't know. They're trying to hack into the system. Uh, doing something trying to get something malicious going on. I don't know. So usually want to eliminate these and remove from the thing. Okay. So that's what it's doing there. I'm going to leave that as exercise. And after you do that, you would validate maybe, okay, to do validation. Example was comment provided. Maybe they just passed nothing, or they passed comments empty, or they passed something else, right? Something else. So we need a comment, right? So you can add something there to validate. Maybe you could do, for example, simple thing. If you're going to look first, look direct of body comment. So if this is either no, it could be like undefined, no empty string. So any of those cases would be falsely. So if you say this with a quote, exclamation before, it's meaning if they're not comment, right? Meaning if the comment is a falsely value, meaning it could, it could be undefined, it could be no, it could be empty string, any of those cases. This falsely value would be turned into true by that exclamation. Therefore, this, this block would be executed. And what we do is pretty much return arrest status, I don't know, maybe four to two, unprocessable entity, and then send an error object or something. Comment must be provided, something like that. That's one way of doing validation. And you would do it, the similar thing for all the others. And the reason we do this here instead of leveraging the database is usually database could also have validation there. But we want to avoid doing any operation on the database if we can. You know, we are on overload database with somebody trying to do some weird stuff. Maybe they're intentionally not providing comment, just to overload your system. So it's best we check in the application logic with the programming language instead of database level here. Anyway, that's validation. And then obviously, I didn't, like I said, way before, usually there's a middleware for authentication, there's a middleware for authorization, and those are run on every single request, basically would go here, app.use and create your own or use somebody else's. And first of all, check, hey, let's see if the user is logged in. If the user is logged in, we set rack.user. And then go to the next middleware. Next, authorize authorization. Okay, is the user authorized to do this operation on the resource? For example, create a message. If not, just deny, send back an error. Hey, you can't do that. Otherwise, go next, which would eventually hit this. And then we assume there's a user with rack.user. We assume there is authorization, right, the user's permitted to create a message. We don't have any of that, but that's what would usually take place. Okay, once that's all out of the way, we can finally run a query. Okay, let's do it. pgclient.query. And this is what inserting to right inserting to what's the messages values. And then if you want to be explicit here, you could adding all the columns here. Let's see, we got ID comment. By the way, I closed the side with control B on Windows. Comment created at author ID. Okay, I think that's it. I think here we'll use the fault. Comment would be $1 placeholder created at $2 author ID $3 and then outside as a second argument to query an array of all those definitions. Okay, what's the comment that's from rack.body.com and right? When is it created at? Well, we can use our current date and to do that in JavaScript, to create a new instance of a date, we can use new space date parentheses. I think it accepts date object. I think that's fine. And for author, we don't have a user system, right? We can create a fake user, I don't know, current user, fake since no off system yet. And we're going to assume it's always user of ID one, something like that. Okay. And we use current user.id. And this, if you run this, it doesn't return you the thing back. What usually happens when you create a resource, you ask the server to create a resource, it usually gives you back that resource object, including an ID. So that way, you know, oh, it's in a database with this ID. So if you run the square, you don't get access to that object back. So what people usually do is returning the columns, all the columns, something like this. Okay, that way you get the object back from the result. And now I'm going to show you how to handle a promise using a single weight, because you could have done dot then here, and then do the result and blah, blah, blah, rows. Let me show you a single way. So we want to do what the following make the function handler here to handle function async. Now we can finally use a weight here, when we use a weight, what happens is it takes this promise, the value that's fulfilled by that promise, and returns back here, once it's been fulfilled, it doesn't execute the code afterwards, until that is done. It's like a like dot then pretty much, except all these other stuff from the dot then is kept in the same level here. And you take that value and putting a variable, let's call the result like this. And then we can use result dot rows. And I assume there's always going to be one right so it's an array. So we take the first object of the array with square brackets zero. Let's see if that works. Okay, go here. This is a test. Let's check it out. Go. Oh, oh, oh, what happened? Something happened. Let's look at the terminal. Something crashed. What was it? Did I miss my query syntax? Oh, let's read the error. Client. Okay, it crashed in the client syntax error, serving x 59. Okay, something's wrong here. Column 20. If you see there's column here and VS code in the bottom. Yeah, something's going wrong inserting to what did I do wrong? Hmm. What do you think I did wrong? Maybe let's see. If I remove this, let me test it out. By the way, I didn't tell you how to handle errors. You notice it crashed the server, right? We don't want that to happen. Usually we want to send back the error to the user. So what you do is whenever you do a wait, you want to put that inside a try and catch block, try catch the error like this. Basically, anything you want to wait, you put it inside the try block. And if there is a problem here, an error is raised, it would go stop what it's doing here and skip to the catch block. Okay, let me move this up here. So if there's a crash here, instead of going to the next line, it goes to catch block. And here, we would say like, I don't know, return rest status 500 internal server error, internal server error. And then obviously you would report to logging monitoring systems somehow, so that you know that something happened bad. For now, just put a console error here. Yeah, so that's how you do it. Let's try again. Just want to show you how it's going to handle a not crash. Let's try again. Clear. This is a test. And you see I got a 500 now. Internal server error. By the way, the front end should show a message here of error, by the way. Let me show you how to add an error message there in the front end, since we got some time there. So in the front end, if you recall message JS here on the right hand side, we try to fetch to create a message then and then but we don't have a dot catch. So we can put a dot catch block like this. So basically along the way, if this promise is rejected, it would go and jump to the catch callback function here. If this at this point, as well, if this promise rejects, it would go here if this one same, so on if an error is thrown in any of these then blocks, it would go to catch. So I think the one that happens for the fetch, right? So in that case, we would get the error. Oh, actually the error be here. This error is only when you have examples like for some reason, we are offline and we cannot reach the server for a response. So in that case would be this one. And then the other case is okay, we got a response, but it's 500 something. In that case, I would check the response okay here. If it's okay, it's 200 range, right? 2xx. Otherwise, 500 usually means something bad on server happened. So here would check okay, if response dot okay is false, right? Like this, or like that, you have to do something okay. In that case, I'm going to throw a new error. And then you can put response dot. I think there's remember we got we got this error, so we would have to parse that. But in this case, you could just throw okay, there was a problem with the response or whatever. Okay, we don't have much time to extract this and other stuff. And because I throw a new error here, it would jump to the catch block, and in this catch block, I can set an error message. But to do that, I got to do a couple things. Okay, I'm going to go to JSX here. Where do I want to show an error message? Maybe after the button here, I want to show an error here. So let's suppose there's a variable called submission error. And if that value is set, I want a short circuit with double ampersand to show a div with the submission error itself, that's going to be a string. Okay. Now we got to define that and we use the state for that. So go up here, we can use state, react use state initially could be either no undefined or empty string, it doesn't matter, let's do empty string. And this is going to be the submission error set submission error. So we can change it. Okay, equals sign. So when we reach the catch block here, when adding a message, we want to set submission error to the error dot message. Error is an object. And the message is whatever's passed here in this argument. Now you want to take care to clear this later, I'm going to show you, but let me just try like that. Hello, comment. You see the div is here, right there. Now if I click comment again, you see it's kind of lingering. I don't want this to linger. So every time I click comment, I want to clear this first before making the request. So you want to make sure to go here, when you add message, set submission error to empty string to clear any lingering one. And I think it was setting you comment here. I don't want to do that always only when it's successful. So I moved that inside this successful block here. All right, otherwise, always going to clear. I don't want that. And if you want to add some style, go ahead, class, submission error message, whatever, okay, and define that here, that submission error message, maybe some padding, color white, background color red, and whatever, whatever, border, one pixel solid black, border radius, four pixels, do whatever you want. Okay. And then refresh, see what's going on here. Let's check my, I made a mistake. I forgot a colon line 15. There you go. Test, comment, there was a problem. Oh, no, red. If I click again, you see it in, I don't know if you noticed, but it clears briefly clears and come back again. Okay, now let's fix the problem with the back end finally. Let me try removing this. I think there's something wrong with here, right? I forgot to say what insert where the table name messages. There you go. Let's try again. Notice still there the error lingering comment. Oops. What's going on still bad? Oh, let's check the Oh, my gosh. Did you notice I put in the wrong place here? Sorry. It's before the parentheses, not after this. My bad, my bad. Let's go back. There you go. Finally, you see the error went, went away when you click comment. That's why you gotta clear before anything. Now it's here. And let's check PG admin. Is it really there or just an illusion? Check PG admin, PG admin, execute the square. Remember, full stack to be schema public tables, messages, right click, view added data all rows, or you can write the query manually. You see it here? It's there. And if you go back to the browser, why did I send back the same thing if you notice we got back from the server, the object that was created with the ID and the created at and the author ID. All of those we didn't have it before, right? Okay. Nice. Now, if I refresh, will it go away? It didn't. It's actually here at the bottom because of the order when we add a comment, it goes to the top. But when we reload them, there's no particular order. I think it's ordered by ID. Okay. You could change that. By the way, if you want to change to always show the latest comments first, let's let's do that. Let me show you. Basically, you would go to get messages. In the query, you're going to add order by ID descending the ESC like this. That way, though, the ones of the latest ID go on first, and then the oldest at the bottom. If you do it that way, save it and refresh, you should see the task is not at the top. And if I do another one, it's going to the top. And then when I refresh, it's still going to be there because the order on the back end is a descending ID. Okay. What else we got to do? Well, you could try to build the endpoint to create a user. We got to sign that page, follow the same pattern. You could build an endpoint to delete the message. Like an admin usually would be the only one. Maybe edit the message, right? So basically, let me put here the restful endpoints. Restful naming convention. Retrieve all resources. Retrieve all is like slash the resource name. Get request. And then if you want to do retrieve one, only one, it's a get slash resource slash colon resource ID, which varies. If you want to create one, right? That's post slash resource name. If you want to delete one, you would do delete. Notice I didn't show you, there's also delete as well, for the verb, slash resource slash the resource ID. If you want to update one, it's put slash resource, the resource ID. And if you want a partial update, it's kind of, usually people use put. This one's called patch. But basically, put is basically replacing a whole object and patch would be just a partial one property, something like that. But pretty much people always use them in the wrong way. These are just conventions. They don't have to be strictly followed, but that's what people usually use. And the put in patch is a little bit weird. Some people would not follow it strictly. But yeah, if you want to follow rest, rest, representational state transfer, that's what it means, I guess. Somebody wrote a university thesis on that. And that's basically the verb and the name and the very simple form that people most of the time use it for. Yeah, so we already got all, we got one and create one. So the exercise for you is to do the others. And you always got to be thinking like, for example, if I want to delete, first I got to check, hey, somebody's trying to delete, obviously, you would have your metalware authenticate, authorize, and then you would check, hey, I want to delete resource, whatever, does it even exist? First you check in the database, retrieve the database, does the resource exist? If so, keep going, otherwise send back a response, hey, not found. And then for the update, same thing, does the resource that you want to update exist? If not, not found is send back, otherwise keep going update, send back the response with the updated object. And same for the patch, pretty much kind of the same for put. Yeah. Let's see. What else can we do here? If you have any questions, let me know. Usually, for the case of users, I guess creator uses more like registering on account, right? You could create that one. But when you create a user, you would have to do a couple more things, not so simple. Besides filtering out on desired properties, validation, you also got to check, okay. Does the user already exist in the system? And when you have the password given to you, you have to take the password and encrypt it one way with a hash algorithm. You can use bcrypt and then start the encrypted version of database, follow. As for endpoint to get all users, that's not, we shouldn't have that to the public, right? The public should not be allowed to retrieve all the users. Usually that endpoint is reserved for administration only. So you got to be careful about creating routes or endpoints to sensitive resources like accounts or users. So you got to think about security. For the case of messages, there's something else I didn't mention. Notice how we comment here. This comment could be potential vector for an attack. Why? Because people might be injecting script tags into the comment. This used to be very common back when we didn't have much protection by default from the browser. Somebody could go here and say, hey, why not comment like this? Do some malicious stuff. Alert. Obviously, I'm going to do some alert. Hey, that's not malicious, but somebody could try to steal information. By the way, alert is just this pop up. I don't know if you can see the pop up. It says, hey. Basically, I can do whatever malicious stuff I have here and comment. And then when somebody else would open the browser and refresh and see the message, this script would execute and run the, you know, some commands, JavaScript code to steal information from the current page of the logged in user. Something like that. It's called XSS, cross-site scripting. XSS. This is the attack if you want to read about it. These days, it's much more difficult to do because the browser, by default, will block it. So you notice it didn't alert anything at all because the browser already integrates some prevention. But you always want to be, just in case, you always want to store in the database. You want to strip all of these tags and store them encoded in different values. For example, instead of storing like a script like this, maybe you could either remove the script altogether or you could just do like this less than, oops, script. And then just coding to prevent it from running as, you know, HTML and JavaScript. Stuff like that. There's a library to do that. If you want to look more to it, you can go to npmjs.com. I think sanitize. Yeah, this one could be the one or sanitize something like that. Let me check this one out. There's so many people already wrote this. They don't have to write it again. Let's see if this one works. Thinks HTML, sanitize, DOM purified. There's this one. And it tells you how to use it. Sanitize HTML. You see this one, examples, people are trying to run an attack. And it takes this and strips them of the stuff. Anyway, you basically call it like this or you import it or require after installing it. And then you can call it like that with the whatever and it would strip it. Okay. Yeah. And what else? You would add a middleware for errors in case something happened and report to your login system like we did here. Because you never know what's going to happen. Usually there's something like, you know, sentry.com, if you ever heard of it, whenever an error is raised in your app, the front end, for example, it would track that. And you could have other monitoring solutions. You could have dashboards with like, that's tracking your requests and responses. So every time you get a request, you record to that dashboard. And if we're getting a lot of 500 responses, which is like error, that means something's terribly wrong. Maybe somebody deployed a new feature that's breaking the application and all that kind of stuff. You could also be monitoring for possible, you know, suddenly you've got a lot of requests, right? What is going on? Do we really have not lots of new customers? Or is just somebody trying to make our system overloaded to make a crash? So we could also monitor that. And maybe you could add middleware to prevent somebody from spamming, right? Maybe you want to create your creating messages right here. What if somebody is constantly creating messages, for example, I go here and I try to create messages all the time, blah, blah, blah, blah, blah, say message, hey, hey, hey, hey, you know, it's spam, right? We want to prevent that. So in the back end, you would go here, okay, let's check. Has this person been sending messages constantly over the past 24 hours? If you can put a limit, right? If the person sent more than 10 messages within 24 hours, they're going to block them. They're not going to be able to create it. Or you could maybe check, hey, this person, have they wrote the same thing? Have they written the same thing in the past 24 hours? If so, we're going to block it. So you can do all sort of things, right? And to do what I just said, the example of spam the same message, I could just go here, okay, let's check the database, pgclient query. And you're going to select start from messages, where author ID, dollar, and the comment is like comment is equal. Let me make it very simple, right? Dollar. Pretty much, okay, let's say current user, right? Let me put this up here. Let me show you how to make a fake simple spam check. Basically, here, what's dollar one, that's to be current user dot ID in an array, forget an array. And then this one here would be a comment, right, which is rack body comment. So this way, we're trying to check, okay, let's look in the database. Do we have the same person making the comment, the same comment? Obviously, I would have to check the date as well, right? To do check for a current day, otherwise would go for all time. Obviously, this is not a very robust, I would have to check, hey, I want to check only for the day, right, last 24 hours. I can still let the user say a tomorrow, and then the day after and the day after. But this one is going to assume the person can only say only a once, ever, never again, okay? So it's very simplistic. Anyway, you can do that query, do a wait result. Oh, we already have the result, right? Let's say existing message result about that. And I put it in the wrong place. A wait is after, sorry, constant and no wait there. And then you can check, okay, if existing message result dot rows, right, the length is greater than zero, there's at least one message, right? If that is the case, I'm going to block the user, hey, return rest status. I don't know, what do you want to say, four to two? Let's four to two. We got to look up some status to know what they mean, what's the most appropriate for this case. And you can say error and you are messaging too much. Same thing, whatever, something to flag the spammer. And then ultimately, if you want to build a whole spam system, you would have tables to mark people as spammer and track them over time, all the fancy stuff, which we don't have. So let's see if this is working. So it's going to go and check for the message. If the same person comment the same thing, it's going to block them. Let's check it out. Let's try to say A again. That was a problem with the response. Yeah, it's working, okay? Okay. It's just that this thing here is giving the wrong error, right? See, we're messaging too much. Since I didn't extract the exact error message here, it's just saying that random there was problem with the response, but you can see from the response here, it's you're messaging too much. And if I put B, it's going to work. And if I put B again, doesn't work. Right? Same thing, you're messaging too much. So that's like a very raw then prototype of a spam system. Okay, I hope that was interesting to you. And yeah, you can go on and try to build the other routes, the other endpoints for the resources, add new tables if you see fit. Yeah, and build from there. And with that, I finish this lecture.
No comments yet (loading...)
No comments yet (loading...)
Did you like the lesson? 😆👍
Consider a donation to support our work: