Instructor: In this video, we're gonna learn
about debugging Node.JS because, let's face it,
there will always be some bugs in our code no matter
how careful we are.
And so it's good to have a tool to help us
with debugging our code.
Now this is not really about error handling with Express,
but I thought this was a good point in the course
to introduce you to a debugging tool
which we might then use throughout the rest of the course.
And there are different ways of debugging Node.JS code.
For example, we could use VS code for that.
But, actually, Google very recently released an amazing tool
which we can use to debug which is called NDB, all right?
So let's move over to our other terminal here
and then install NDB.
And NDB, which stands for Node debugger,
is actually just an NPM package.
So NPM install NDB.
All right, and you should then install it
as a global package, all right?
And if you're on a Mac, you might need global permissions.
So just write sudo here in front.
Or if you're not at all able to install it globally,
you can always just install it locally
as a death dependency.
So just like this, all right?
Anyway, please go ahead and install this tool now.
I'm not going to do it
because it can be quite a heavy download, and
that takes a bit too long now.
Anyway, as soon as you have the tool installed,
then let's head over to package.jason
and add a new script here, all right?
And I'm gonna call that one debug.
Okay?
And so the command that we want to run here
is simply NDB, so the note debugger
and then again our entry point,
So, server.js
Okay?
And now this is gonna work no matter if you installed
NDB locally or globally.
All right, so let's now run the script.
And in order for this to work
we actually need to finish this process
because it's basically gonna start
the server as well and so it will then
try to do it on the same port
and that's of course not gonna work.
So we need to finish the one that's currently running
and then from here we can run NPM
run
debug
All right, and so now
a new Chrome window should open
so what's called a headless Chrome,
but it's not a real Chrome.
So you will see the Chrome icon down here
and also here in the menu bar
but really this is just the note debugger.
So what do we have here?
Well on the left side, we have our complete file system.
We also have access to our NPM scripts here
which we can actually run from here.
We also have a console
and so here we have our usual outputs with the app running
and the database connection
and we also have the performance and memory tabs,
which we're not gonna use.
All right, now if you're familiar
with the general debugging process
then all of this gonna be kinda familiar to you.
All right, but if not don't worry
I will show you a couple of techniques
throughout this video.
All right, anyway let's now open up our server.js.
And one thing that's really amazing
is that we can actually edit our files in here,
so right in this debugger.
So, for example let's say that we find a bug
and we then want to fix it right away.
We can do that right here in the debugger
and it will then update the original code.
So just to test it,
let's just add a comment down here.
So, test then hit command or control s to save
and then when we go back to our code
and open up server.js
there you will see that the comment is actually here.
Okay?
And if we now delete it from here,
give it a save,
and back to the debugger,
then it is gonna be gone from here as well.
Okay, but now about the debugging itself.
I would say that the fundamental aspect
of the debugging is to set break points.
So break points are basically points in our code
that we can define here in the debugger,
where our code will then stop running.
It will basically freeze in time
and we can then take a look at all our variables.
Okay, so that will then be extremely useful
to find some bugs.
Now, right now there's not any bug in here,
but let's still add a break point.
And I'm going to add that break point here in this line 21.
So I click here on this line
and then you see this green marker, okay?
And so that means that the code will stop at this point
when we execute it, okay?
And you actually can see it here on the right side
on the break points tab here as well.
Now, our application is actually
already running at this point
and basically waiting requests to come in.
And so what we need to do here
is to right click and then click on run this script.
Okay, and so that will then basically
run the script here again.
All right?
And so here we go.
So you see here on the right side,
that that it says paused on break point
and so all the code that is above this break point here
has already executed at this point.
And so we can now take a look at the variables.
For example, we can hover this port variable
and we see that it's set to 3,000.
And also actually hit this place here
in the code here, all right.
And then the third way of seeing it
is here on the right side.
So we have a couple of basically tabs here
so node processes, the watch, the call stack,
which is not really important for now.
The scope, and so the scope is where all our
variables are, okay?
And so here again, you have the port set to 3,000.
Okay, and here you also can see
the five variables that we have access to
in all modules.
Remember that from the models lecture?
So we have the directory name,
we have the file name, we have the require function,
we have module, and we have export.
So remember, these are the five variables
that are available in each and every module.
And actually when we execute a code like this
in the debugger, we can see that our entire code
is in fact wrapped into this function.
Right?
So this wrapper function that gives us access
to these five variables.
All right, next I also want to take a look at
our app variable, so basically the Express application
that we export from app.js, remember that.
And here is really a ton of stuff
but what I find interesting
is to take a look at this router here.
Okay, and so in router we then have stack.
Okay, and so let's open this up a little bit
and so this stack here is basically
the middleware stack that we have in our application.
Okay, for example we have our jsonParser here,
we have the code that serves the static files.
Take a look at that here in app.js
so this express.static.
We also have the logger here
which comes here from using Morgan.
Then you have these next two middleware functions,
so these two here,
which are anonymous, so this one and this one
and maybe we can take a look at them.
But not really.
Okay, it doesn't matter.
So this is really just for curiosity
and showing you that we actually
can take a look at our middleware stack, okay?
Then finally we have our two routers.
Okay?
So, we have the router, and you see here actually
the route for which it applies.
So api/v1/tours right and so I find this really interesting.
Of course we still have the users here as well.
And so with this really can take a look at how the
Express application works behind the scenes.
Okay?
So let's close up all of this.
And the other thing that I wanted to show you
is here in the global variables
because here we have the process variable
or at least we should have it somewhere here.
Yeah, so indeed here it is.
So here we have the process variable
that is remember, available everywhere.
And so that's why it's called here a global variable.
Then in there we have process.env
and to remember that this where
all our environment variables are stored.
And so indeed here we have our database string,
we have the local database, the password,
and really all the other environment variables
that we defined in our config.n file.
All right?
So really interesting stuff that we can take a look at here.
But now let's continue with our debugging.
Okay?
So we stopped the code, we froze it in time
here at this point, so at line 21.
Okay, and so now we can click here on this button,
in order to actually continue to running the code.
And since we have no more break points,
the code will then break no more,
and basically finish running.
So let's do that.
And so now our application is really running.
Let's take a look at that.
In Console, okay?
So app running on port 3,000
and DB connection successful, of course.
What's happened here?
Now, all right,
so let's now quickly do a request here.
So simply one for /tours
and now we have all this junk here
and I'm gonna take care of that in a second.
All right, and if you now come back to our Console here
then of course we have all the code that we had before.
Hello from the middleware and then
how the long query actually took.
All right, and now before we do anything else
let's actually get rid of these junk tours.
So I'm gonna reload it here,
and I guess it will be somewhere here at the end.
So, test whatever here.
So let's get rid of it.
This is the secret tour and I actually want to keep it here.
But everything from here on we no longer want.
And so
so yeah, so now we're back to having just 10 tours,
just as before.
Anyway let's now actually set a break point
in the function that handles this route.
Okay, and so we come to our controllers folder
and there we have the tour controller.
Okay?
And then the handler function is this get all tours.
So for now all I wanted to do
is to just set a break point here
so that we can take a look at what these variables
look like after the query is already done.
So this code here will get our tours
and we will then stop the code
basically before actually sending it as a response.
Okay, and so all we need to do is to actually do the request
because that will then trigger that function.
Right?
And so since we have a break point, we automatically move
back to this window here, and to the point
where the code has stopped.
So, what kind of variables do we have here?
So you see that we have the request and a response,
and we also have the features variable,
and the tours, of course.
So let's first take a look at the request.
And here again, you see that we have all kinds
of stuff really.
So we have, baseurl, we have the method,
we have for example, request.query,
which right now is empty because we didn't pass
any query string,
but you see that it's really already here.
Okay, and so you start seeing now how handy
this can be in order to debug our code.
So basically to freeze our code in time instead of
having to do all these console.logs that we used to do
up until this point.
So usually when we wanted to take a look at
the query for example, we would do a bunch of console.logs
and use that to figure out a bug in case that something
was not working.
Right, but now we have this amazing tool
which can help us avoid all these console.logs
for example.
Then we also have the response of course.
And again you see all of these properties and methods
that are on there, and they are not really interesting
for us now.
What I wanted to show you is of course at this point
we already have the tours, okay?
So we have nine tours, so let's take a look at them.
And it looks kind of weird here, so in order to get access
to the actual values, we need to click here, okay,
so that's a bit weird.
But it works of course.
And so you see that in fact our tours are already here
and of course the features as well.
So you see here that the features are an instance of
the API features class just as we defined it.
And in there we have the query and the query string.
Great, so this is how we take a look at all the variables.
And this is how the most important parts of
the debugger work.
Now in order to learn a bit about the debugging process
itself, let's introduce a very small bug into our code,
and then take a look at how we can use these tools
that we have here to basically take a deeper look
at our code.
So I'm not gonna resume the skipped execution
in order to run basically the rest of the code, okay?
So that should be done now.
So now here we have all response.
So you see that it took all this time here,
so three minutes and 29 seconds,
but that's just because we paused the execution
for so long.
Okay.
Now let's come to our code here.
Let's close what we no longer need.
So actually in our API features file,
I want to introduce a small bug here in the limit fields.
So let's say that we were trying to implement
this method here, but instead of joining with a space here,
we forgot to put it here.
And so let's just say that we joined without any space,
and so this would then give us a weird result, right?
So let's actually test it out.
So let's say
fields and that we wanted only the name
and the duration, right?
Now before I can actually send that request,
let's remove the breakpoint here.
Okay?
Sent the request, and now we actually do not get
the name and the duration.
So let's pretend that is our bug now
and we're now trying to figure out why this is not working.
Okay?
So let's go to our debugger.
And we know that the error must probably be
somewhere in our limit fields method.
And so let's basically stop the code from executing
at this point, okay?
Because this is where this method will actually be called
and so from here we can enter that function
for that method.
Okay?
So then let's fire off that request now,
and so now we go back to our debugger automatically.
So at this point this line and this line and this line
of code have already executed, and so let's now use
the step tool, okay?
What step will do is that it will basically execute
the next line of code.
And in this case that will be inside of
the limit fields method.
So step, and it will then move right into that function.
Okay so let's take a look at what we have here.
For example this .query string is name comma duration,
so that is correct, right?
Okay so let's step to the next line.
All right and so this is where this operation
is actually happening.
Then next up.
Let's take a look at our variables here.
And so here we now see field, and so here we have our bug.
Okay?
So the problem is, of course, that we have no space
between name and duration.
And so that's why it's not working.
So fields is of course defined here, and so like this
we can find our bug and correct it right away.
So remember that the added step we do here
are reflected immediately in the code.
So give it a save,
and then it will do it again.
So I can keep stepping.
And so now fields is correct.
So name space duration.
Then the next line of code.
And now we enter into the select method on the query.
But we're not interested in that at all,
so we can say "step out of current function."
Okay?
So that select that we just thought was running
this function here, okay?
But of course we were not interested in that
so we just quit it and moved on to the next line.
So now we have return this,
next line, and again.
So now we're back to where we were but in the next line.
So let's keep doing that.
So now we're into page eight,
but we're not really interested in this one,
and so let's again step out of the current function.
And now we're here at the tours definition.
Which at this point is not yet done.
And so let's again say step.
And so now at this point our tours should be defined.
All right so we have our nine tours over here.
Let's take a look at them,
and here they are.
And actually they have all the data,
so not just the one we defined but in fact,
actually it doesn't.
So we really only have the name and duration,
so duration, name, and all the other ones
are undefined.
So that's just because we limited a query to only
these two fields, remember?
Now what I also wanted to show you is here in the features,
we can take a look at our query and here we have
the fields property for example where we see duration
set to one and name set to one.
And so that's exactly the two names that we selected.
We also have these options here,
which is at this point set to create it minus one.
And so that's coming from here.
So this here.
So basically what this method here, this sort method
is gonna do is that it will add this sort property here
to these options, all right?
And then we also have limit and skip which of course
come here from page eight.
Okay?
So I thought that this also kind of interesting
and yeah, so our code is now actually fixed and let's keep
running this.
And so we now should have our correct result.
Now here it says we could not get any response,
and that's because we took too long fixing our code.
So we got an error connecting.
But if we now send it again,
and now we do it quicker.
Or actually we could remove our breakpoint entirely.
So let's keep it running,
let's go back and now indeed we get the duration
and the name as well.
So that's because we just fixed our code
using the NDB debugger.
So great.
That's a really amazing and helpful tool
that we're gonna keep using throughout the rest
of the course.
Maybe not always, sometimes it's quicker to just
throw in a console out log.
But really, in some more complicated cases,
I like to use this kind of tool.