The Express. js Course - Module 2: Node Module System | Shivendra Raghuvanshi | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

The Express. js Course - Module 2: Node Module System

teacher avatar Shivendra Raghuvanshi, Lead Developer and Online Teacher

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Module System Essentials: An Overview

      2:13

    • 2.

      Inside Node.js: The Global Object

      3:26

    • 3.

      Modularization in Node.js: A Modular Approach

      3:50

    • 4.

      Crafting a Custom Node.js Module

      4:57

    • 5.

      Loading Modules in Node.js

      5:19

    • 6.

      Navigating Paths in Node.js

      4:10

    • 7.

      Interfacing with the OS: Node.js OS Module

      4:44

    • 8.

      Manipulating the File System with Node.js

      10:31

    • 9.

      Event-Driven Programming in Node.js

      7:25

    • 10.

      Event Arguments: Diving Deeper

      2:36

    • 11.

      Expanding EventEmitter: Advanced Event Handling

      8:09

    • 12.

      Handling HTTP Requests: Node.js Networking

      7:16

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

2

Students

--

Project

About This Class

  • The Node Module System class provides a comprehensive understanding of how modules work in Node.js. This class covers the core concepts, tools, and best practices for using the module system to create modular, efficient, and maintainable applications.

Class Objectives:

  • Understand the role of the Node.js module system in application architecture.
  • Learn to use built-in modules like fs, http, and path.
  • Explore how to create and use custom modules.
  • Understand the require function and module.exports for importing and exporting functionality.
  • Work with third-party modules via npm (Node Package Manager).
  • Learn how to manage dependencies and avoid common pitfalls.

Meet Your Teacher

Teacher Profile Image

Shivendra Raghuvanshi

Lead Developer and Online Teacher

Teacher
Level: All Levels

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Module System Essentials: An Overview: Hi, and welcome to the Express Chairs course. Module two, nod Module system. My name is Shevin agonci. I'm a full sech developer and instructor with years of experience building scalable APIs and real time systems. I'm super excited to be your instructor for this course. If you have ever wondered how Nojs handles events so efficiently, this class is for you. So this class is a continuation of the ExpressJcurs series, and you may also view its previous class titled The ExpressJScurse, Module one, getting started with NodeJS. In this section, we are going to look at the module system in Node. You'll learn what modules are, why we need them, and how they work. Throughout this section, we will explore several modules built into the core of node, such as operating system, file system, events, and GTP. You will also learn how to create your own modules and finally, apply these skills to create a live GTP server that handles real world networking task. Who is this class for? This class is designed for bigner and intermediate NerdJs developers. If you already know JavaScript and have Nerd Js installed, you are all set to get started. You're not just learning concepts, you're building practical skills. By the end of this class, you will have the tools to create reusable modules, understand advance event handling, and confidently handle NRGS networking. These are game changing skills for backend developers. And finally, our hands on project includes creating a fully functional event emitter with advanced features like priority listeners and error handling. And then you will integrate it into a NRGs GDP server handling dynamic G and post requests. I can't wait to see what you build with these skills. Let's just start it, and I will see you in the first lecture. 2. Inside Node.js: The Global Object: In the last section, we use this console that log function to log something on the console. Now, this console object is what we call a global object. That means it's part of the global scope, which we can access anywhere in any file. We have a bunch of other objects, for instance, that are also globally available in node. For example, we have set timeout, which we have probably seen before. We use this to call a function after a delay like 1 second, 2 seconds, and so on. So this is just a part of the standard JavaScript. We can use this on the client. We can use this inside of a browser or even in node. We also have clear timeout. Similarly, we have set interval, which we repeatedly call a function after a given delay. We also have clear interval, which we use to stop a function from being called repeatedly. These are the global objects in JavaScript. Now in node, we have a couple of other global objects that you're going to learn about later in this lecture. In browsers, we have this Window object that represents our global scope. It means all the variables and functions that are defined globally can be accessed via this Window object. We can call window dot console dot log or simply just console dot log. The Java Strip engine will prefix this statement with Window because that's where this object is defined. Similarly, all these functions that you see here belongs to the Window object. So we can call window dot setTimeout or call it directly. By the same token, if we declare a variable, let's say message, that variable is also available via the Window object. All right. However, in the last section, I told you that in node, we don't have the Window object. Instead, we have another object called Global. So all these functions and objects that we have here can be accessed via the global object. It means we can do global dot console dot log or global Set Time out and so on. Of course, it's easier to use a shorthand instead of prefixing them with global. But one thing you need to know about node is that these variables that we define here are not added to the global object. In other words, if we do a console dot log of global dot message, we are going to see undefined on the console. Let me show you. Now open the shell or terminal and run node app dot js. See, we get undefined. As you can see, the variables and functions that we define here, they are not added to the global object. They are only scoped to this file, app Js, and this is because of the node module system that you're going to learn about in the next lecture. 3. Modularization in Node.js: A Modular Approach: The last section, you have learned that in the lien side JavaScript that we run inside of a browser, when you declare a variable or a function, it is added to the global scope. For example, when we define a function like say hello, that function is added to the global scope, and it's available via the window object. There is a problem with this behavior. In a real world application, we often split our Java strip code into multiple files. So it is possible that we have two files, and in both files, we define this function, say hello with the exact name. Because this function is added to the global scope, when we define this function in another file, that new definition is going to override the previous definition, and that's a problem with global scope. In order to build maintainable and reliable applications, we should avoid defining variables and functions in the global scope. Instead, we need modularity. We need to create small building blocks or modules where we define our variables and functions. That means if you define a variable or a function with the exact name in different files or modules, they are not going to override each other because they are encapsulated inside of their respective modules. Now, at the core of the node, we have this concept called module. So every file in a node application is considered as a module. The variables and functions that we define in that file or that module are scope to that particular file. In object oriented programming terms, we say they are private. They are not available outside the container or outside that module. If you want to use a variable or function in a module outside that module, you need to explicitly export it and make it public. And we are going to look at that in the next lecture. What I want you to take away from this lecture is that every node application has at least one file or one module, which we call the main module. So in this case, this app Js is our main module. Now, let me show you this module. I'm going to delete all this code here and do a Console dot log of module. This module object here may appear to be global and you may think we can access it via global object like global dot console. But this is not a global object. It appears to be global, but it's not global and you will find out why very soon. Let's see the log in Console. Open your terminal again, node app dot JS. As you can see, we have an object module. It's Adjacent object with these key value pairs. So we have ID. Every module has an ID or unique identifier. We have exports, path, file name, loaded, churn, and PATs. For now, don't worry about these properties. As we go through this section, you will gradually become familiar with these properties. So in node, every file is a module and the variables and functions defined in that file is scoped to that module. They are not available outside of that module. In the next lecture, we're going to learn how to create and load a module. 4. Crafting a Custom Node.js Module: All right. Now let's add a new module to this application. So I'm going to create a new file, logger dot js. Let's assume we are going to create a new module for logging messages, and we're going to use this module in various parts of this application or potentially in other applications. So logger dot js. Now in this module, let's assume that we are going to use one of those remote logging services for logging our messages. So there are websites out there which provides logging as a service. They give us a URL, and we can send an TDP request to that URL to log messages in the cloud. So here, I'm going to declare a variable like URL and set it to something like this. HTTP suo oger dot slash Log. And of course, I'm making this up it may not be a true service out there, but let's imagine in its implementation, we are going to send an HTTP request to this endpoint. Now, we also need a function called Milob that takes message. And in this function, we are going to send an HTTP request. However, to keep things simple, we just want to focus on modularity. We don't want to get distracted from all the details of sending HGTV request. So for now, I just want to log this message on the console, so console dot log message, okay? Now this variable and this function, Milog are both scoped to this module. They are private. They are not visible from the outside. However, in app Js, which is our main module, we want to use this logger module. So we should be able to access this Milog function. We should be able to call it from the app module. So we need to make this public. We need to make it visible from the outside. Now, in the last lecture, you saw this module object. One of the properties here is the export. You can see this property is set to an empty object. Anything that we add to this object will be exported from this module and will be available outside of this module. So back in our logger module, I'm going to set module dot exports dot log. So I'm adding a method for rock to this exports object and simply setting it to this MLOpFunction, defined here. Okay? In other words, the object that we are exporting here has a single method, log. Similarly, if you want to export this URL, we could do something like this module dot exports dot URL. We set this to URL. And of course, we can change the name that is exported to the outside. For example, internally, we call this variable URL, but when we export it, we may call it endpoint. Okay? Now, in this case, we don't need to export this URL variable because this is purely implementation detail. So in real world applications, every module might have several variables and functions. We only want to export a subset of these members to the outside because we want to keep this module easy to use. Let me give you a metaphor. Think of a laptop. A laptop has a screen and a keypad on the outside, and these are the buttons or objects that we interact with. So these objects represent the public interface of a laptop, right? But inside the laptop, there are a lot of other objects. We don't need to know anything about those objects. They are implementation detail and they can significantly change from one model to another. But what we see on the outside is almost stable or static across different models. So in our logger module, this URL is implementation detail. Other modules don't need to know anything about it. They only need to call the log function. So we export this and make it public and keep the URL private. So I'm going to delete this last line, okay? So we are done with our logger module. Now we need to load this module and use it inside app dot JS. 5. Loading Modules in Node.js: To load a module, we use the required function. This is one of the functions in node. We don't have this in browsers. This function takes one argument, and that's a name or path of the target module we want to load. So here we want to load the logger module. Now you can see both the app module and logger module are in the same folder. So we use period slash to indicate the current folder, and then we add the name of our module that is logger dot js. Or we can make it shorter and just use logger because node assumes this is a Ja Scrap file, and it automatically adds the Js extension. Now, if this logger was in a sub folder, we could add that subfolder here, or if it was in the parent folder, we could use dot dot slash. So here we are using the relative path to the target module. In this case, that module is in the same folder. Now, this required function returns the object that is exported from this target module. So this exports object here, this is what we get when we call the required function. Let me show you. So I'm going to declare a variable, call it logger, the name of the module, and set it to the return value of the required function. Now, let's love this logger and see what we get. So node app dot Js. Look, we get an object. This object has a single method called log. You can see that's a function. So we can call this function for this method in app that Js. So back here, we call logger dot. And look, here we have intelligence in VS code, so we call Log and pass a message. Now, back in terminal, and we get message on the console. So this is how we work with modules in node. When we define a module, we export one or more members, and then to load the module, we use the required function. Now, in the recent versions of JavaScript, we have the ability to define constants. So as a best practice, when loading a module, it's better to store the result in a constant like this. The reason for this is because we don't want to accidentally override the value of logger like this here. If we set this to one, then we call log method. We're going to get an exception. Let me show you. So one more time. Look, we got logger that log is not a function. Now, in contrast, let's say we define this as a constant. So back in the terminal, let's run this program one more time. Look, we got a different kind of error, assignment to constant variable. Now, there are tools out there that check our JavaScript code for errors like that. So by using these constructs properly, we can prevent these errors from happening at runtime. And one of these popular tools is Jent. If you have never used it before, don't worry. I'm just going to show you a quick demo. So if you run Jsent app dot JS we get this error attempting to override logger, which is a constant. So with tools like JSN, we can scan our JavaStro code for errors like that. And that's the benefit of using a constant as opposed to a variable here. If we accidentally reset this object, then we're going to get an error at compile time instead of at runtime, okay? And one last thing before we finish this lecture. Sometimes, instead of exporting an object from a module, you will want to export only a single function. For example, here in our logger module, we don't necessarily need an object because we have a single method. An object would be useful if we had multiple methods or properties here. But in this case, instead of exporting an object, we can export a single funtion. So we can reset this exports to the log function. So initially, it was an empty object, but we reset it to just a fenton. With that, back in app or Js, logger is no longer an object. It's a function that we can call directly like this. So Logger recall it and give it an argument. Now, a better name for this function is log. So I'm going to press F two to rename this Log like this. Now, back in termino, let's run node app Js and we get the same result. So in your modules, you can export a single function or an object. 6. Navigating Paths in Node.js: In the previous lectures, I told you that in node, we have some useful modules built into the core of node. With these modules, we can work with the files, with the operating system, with the network, and so on. So let's take a quick look at this module. Head over to nods.org, then click on DCS. On the left hand side, you can see the latest stable version, which is 18.16 0.1 at the time of recording this video. By the time you watch this video, it could be possible that it is upgraded to a newer version, although it doesn't matter, so click on this. Here you can see a list of items. Now, this is a nod documentation. It is not necessary that all of the items here are modules. Some of these are also objects like this console object or this buffer object, which is also a global object, and we will learn more about this in the future videos. However, this is a fairly short list. Now, let me give you a quick overview of the modules that we are going to learn. First, we have the file system, which is very useful module to work with files. Another is the SGTB module, which is very useful to build services for networking and for HTP request. Scroll down and you will find the OS module, which is very useful to work with the operating system. Then we have the path module, which has a bunch of useful methods to work with different tats. Then we have the process module through which we will know about the current process. We have query strings, which is very useful when you work with SGTBRquest, and then we have the stream module, which is useful to work with the streams of data and a bunch of other modules. So in this lecture, we are going to look at this path module. Click on this. As you can see in the documentation, we have different functions defined here. In this lecture, I'm going to use the parse method. If you scroll down, you will see how to use this path module. Here, we have the required function we have seen before, and it takes an argument, which is the path module. It says node, and then it is defined as path. Then we store it in a constant to the object path. So I will just copy it and back to VSCO. In the app that JS, I'll just page the line and it is ready to use. So we can use Path dot ps and it takes an argument. So I will write, underscore, underscore, file name. It's an argument that you can see in the module wrapper function, but we'll talk about it later. So I'll store it in a constant and call it path object. And then we'll just simply log it to the console. Path object. Save it. Now back to the terminal. In the terminal, we'll just run the code, node app dot js. And we can see we have an object with a bunch of elements like root, DIR, which is the complete path to the folder which contains the file. Then we have the base app dot js, the extension, and the name of the file. In the next lecture, we'll learn about the operating system module. 7. Interfacing with the OS: Node.js OS Module: In this lecture, I'm going to show you how to get information about the current operating system. Go back to the nod documentation, scroll down the page, and you will see the operating system module. Here, Os click on it, and you will see the methods defined in this module, like we have free MM to get the free memory of our system. We also have total MM to get the total memory of the system. We can also find about the user information, and we can also know about the uptime and so on. So scroll down, and you'll see how to use this module like any other module. So we have the required function. We'll define the node OS here and store it in a constant OS. So I'll just copy it and back to OS code. Here, let me delete all the code and simply paste it here. So now operating system module is ready to use. I'm going to use s dot fremm to get the free memory of my system and Total Mm to get the total memory of my system. And I'm going to quickly store them in a variable total memory. And cons free memory. Now just simply log them to the console. So console dot lag, total Memory and simply append total memory variable here. That's it. But there is a better way to do it. We can use the template literal feature of ECMAScript. So for those who don't know, ECMAScript is a specification used for JavaScript. Every year, there are new features that are being added to JavaScript, and that is being maintained by ECMAScript. So this template literal feature is available in ES six or Abo specifications. And the latest version of ECMAScript is ES 14 or ES 2023. Let me show you how to use template literal. So console dot log, and instead of single quotes, we will use the BTI character. You will find the BTI character just below the escape button on your keypad. So let's add some static text here like Total memory. And I want to add something dynamically. So I'll use the dollar sign followed by curly braces. And inside this, it requires an argument. In this case, the argument is our variable, which is total memory. So in this way, you don't have to concatenate the variable with the static text. So I'll just copy this and change the total memory to re memory. Here, also, I'll change the variable to re memory. Now let's save it and quickly check on the terminal. Before that, here we don't need this first console. So I'll just commend this out back to the terminal, and let's run the code. Node app dot js. As you can see, the total memory and free memory of my system is displayed here. What is interesting here is that before node, we couldn't use JavaScript to find this kind of information. After node, it is pretty much simple using the OS module and other built in modules of node. For example, we can build a web server which will stend to the SDTPRquest on a port, and I'm going to show you all this later in the section. 8. Manipulating the File System with Node.js: In this lecture, I'm going to show you how to work with files in node. Scroll down and you will see the file system module here. Click on it. So here on this page, you will see a comprehensive set of methods to work with files. However, I'm not going to waste your time and show you each and every method. Instead, I will show you an example of a particular operation that is to read the directory in different ways to perform that operation. So let's move on to the file system here. So we have two different ways to use a file system module, and we'll look it into shortly. Before that, let me show you two different syntaxes that we can use to load the FS module. You can either use the import functionality of the ESX modules or you can just use the common JavaScript syntax, which uses the required function where you have to provide the namespace node fs Promises or just node FS. And all you need to do is store it in a constant called FS. So either way, you are going to use the or load the FS module, the File system module. Now, let us understand the basic difference between the promise based APIs, callback APIs, and synchronous APIs. So the file system operations can be performed synchronously and asynchronously. And furthermore, asynchronous operations can be performed using the callback API or the promise based API. All the operations are accessible using both the common JavaScript syntax and the ES six modules. Now, let us understand the basic difference between all these APIs. Synchronous APIs perform all operations synchronously, blocking the event loop until the operation completes or fails. So as I told you before, nor is a single threaded operation. It does not execute another request until the current operation completes or fails. Moving on to the callback APIs. These APIs perform all operations asynchronously without blocking the event loop. Then invoke a callback function upon completion or error. That means asynchronous operations can be performed using the single thread because it's non blocking. So do you remember the example of the restaurant that I gave you? A waiter can take the order and give it back to the kitchen. Then take the order from another table and go back to the kitchen again. In this way, we can serve as many clients as possible. And lastly, we have Promises API. This provides asynchronous file system methods that return promises. So it is something that is added to node Version ten. Before that, all the asynchronous operations were performed using the callback API. Finally, as I told you before, both the callback and promise based APIs uses the underlying node thread pool to perform file system operations of the event loop thread. Now, let us look at the example using the promises API, callback API, and the synchronous API. So first of all, let me show you an example of the synchronous operation using the common JavaScript syntax. So we load the FS module using the required function like this. Once the function is loaded, we can access the read DIR sync from here. Now we will have to mention the path here, so period slash because we are looking at the current directory. Now, let me save this in a constant call files. Now, all we need to do is to log the files to the console. So console dot log files. Here, the synchronous operation will complete, but let me encapsulate all the code here in the trikt statement. So try to get the files here and handle the error, something like this, console dot log error, C error. However, this is not the ideal way to handle an error, but this will be it for now. We can also rectify the code a bit more like this for const file of files. So I'm using the four loop to log in individual file of the array files. Save it and pack through the terminal. Run node app dot JS. So here you can see all the files that we have in the current folder. Check this from here, Nord modules, app dot js, logy dot js, package lag dot JCN, package dot JSN. And here, all the same. Back to ES code. Now let me show you the asynchronous examples using the ESX modules. So I'm going to delete all this from here. Before that, let me tell you that to use the ESX modules, you have to declare its type in the package dot JSNFle. So you have to go to Packs dot Jason and declare the type as module. So remember, once you declare the type as module, you will not be able to use the required function. Once declared, you'll only be able to use the ES six modes. So I'll close this and remember to load the ES six modules, we will use Import. Import astric as FS from node column FS. That's it. To use the callback API, we will usefsRdDR. We will have to include the path here period. And now the second argument will be a callback function. So, now the callback function will take two parameters. First, the error and second is the files. So I'm using the arrow function here, ERR for error then files, and this goes to a code block. We are going to use IL statement here. So I ER error, then you will have to log it to the console. So error, Column ERRElse you can simply log the files like this. So let's see what happens. Save it and back to the terminal. Run nod at Js. So as you can see, the files array, which includes the name of the files. Now, back to VS code, we can also rectify the code as we did earlier. So we will use the four loop again for const file of files. And instead of files, it should be file. Back to the terminal again, node app dot js. C, the same result. Trigger this and back to VS code, and let me show you the last example for the promises API. To use the promises API, we have to use slash Promises here. Now, promises APIs has the file system methods that return promises. So as you know, if you are familiar with Asynchronous JavaScript, if you're returning a promise, then you have to decorate the function with await. So let me quickly write await here. Then you don't have to use the Callbek function here. So I'll just move it here and that's it. Now, we will have to store this in a constant. So I'll store this in files const files. And then we can simply take this code from here and move it here. Finally, we don't need this function, so I'm going to delete this. Remember, this is a synchronous function. It would also return an error. So we will have to make sure that we handle this error with the help of tr cache block. So I will encapsulate this in a tri cachblock tryCatch, and I will move all this code in the tri block and to log error, I will do something like this error column error. Save this and back to dot terminal one more time. Node app dot js, and the same result. 9. Event-Driven Programming in Node.js: One of the core concepts in node is the concept of events. In fact, a lot of nodes core functionality is based on this concept of events. An event is basically a signal that indicates that something has happened in our application. For example, in node, we have a class called STTB that we can use to build a web server. So we'll listen on a given pot, and every time we receive a request on that port, that STDP class raises an event. Now our job is to respond to that event, which basically involves reading that request and returning the right response. As you go through node documentation, you can see that several classes in node raises different kinds of events. And in your code, you might be interested to respond to those events. So in this lecture, I'm going to show you how to work with the events module. Now, back in the note documentation, once again, in the list of modules, you can see here we have this events module. In this module, we have one class that is called event emitter. It's one of the core building blocks of node, and a lot of classes are based on this event emitter. Let's see how we can work with this event emitter. Where in VS code? First, let's load the events module. So require node column events. Now here, when we call the required function, we get the event emitter class. So constant event emitter. You may also use ESX modules to import the Evenimter class from the events module like this. Import event emitter from node events. Do make sure to update the package or JCNFle to indicate the type a module as it did in the last lecture. So let's come in this out for now. Note that here in terms of naming, the first letter of every word is uppercase. This is a convention that indicates that this event emitter is a class. It's not a function. It's not a simple value, it's a class. A class is a type of container for properties and functions, which we call methods. So in this event emitter class, we have these methods that you see here in the documentation. So a class is a container or a bunch of related methods and properties. Now here, in order to use this event emitter, first, we need to create an instance of this class. So constant emitter, we set this two new event emeter. So here, this emiter is an object. In case you don't know the difference between a class and an object, let me give you a metaphor. A class is like human and an object is like an actual person like you and me. So a class defines the properties and behaviors of a concept like a human, but an object is an actual instance of that class. Okay? So here, this first event emitter is a class. It's a blueprint. It defines what an event emitter can do, but the second emitter is an actual object. This is the one that we are going to use in our application. So this emeter has a bunch of methods. And these are all the methods that you saw in the documentation. Now, even though here we have more than ten methods, most of the time you use only two of these methods. One is MT that we use to raise an event. ET basically means making a noise or produce something. In this case, we are making a noise. In our application, we are signaling that an event has happened. Okay? So that's the meaning of M. Now here, we pass an argument that is the name of the event let's say message log. In the future, we are going to extend our logger module, and every time we log a message, we are going to raise an event called message log. Now, if you run this application, nothing is going to happen. Let me show you. Back in the terminal. Node app Js. Look, nothing happens. Because we have raised an event here, but nowhere in our application, we have registered a listener that is interested in that event. A listener is a function that will be called when that event is raised, okay? So let's register a listener that will be called when the message logged event is raised. You register a listener and then write emitter. Look, here we have this method, add listener. But we have an alias for this method that we use more often. That is on. If you have worked with JQuery, you have seen this before. So on or add listener, they are exactly the same. But quite often, we use the on method. Now this method takes two arguments. First one is the name of the event. In this case, message log, and the second one is a callback function or the actual listener. So here we pass a function and this function will be called when that event is raised. All right. For now, I just want to log a message on the console. So console dot log. Let's say listener call. Now let's run this application. So node at the Js and we got this message, listener call. So this indicates that when we raise this event, the callback function or the listener was called. And of course, the order is important here. If we registered this listener after calling the EMT method, nothing would have happened because when we call the EMT method, this emitter, it reads for all the registered listeners and calls them synchronously. So this is the basic of raising events and handling them using the event emitter class. 10. Event Arguments: Diving Deeper: Quite often when we want to raise an event, we also want to send some data about that event. For example, in our lager module, when we log a message, perhaps our remote login service will generate an ID for that message. Perhaps you want to return that ID to the coin, or it may give us a URL to access that log message directly. So here, when raising an event, we can add additional arguments which we refer to as event arguments. So we can add an ID like one and we can add a URL. But as you can see, these magic values here are a little bit confusing. If you want to send multiple values about an event, it's a better practice to encapsulate those values inside an object. So here we add an object. We get a couple of properties like ID. We set it to ID of this message that is locked, and another property URL like this. Okay, so we refer to this object as event argument. Now, when registering a listener here this callback function, this actual listener can also receive this event argument. So here we add a parameter called Rc. You can call it anything. The name doesn't matter, but by convention, we often use arc or some people use E to refer to the event or event arc. Whatever you prefer is perfectly fine. So here we have R. Now let's log it on the console. Very simple. Let's run this application. The note abjso, look, listener called, and here's our event argument. And with this technique, we can pass data about the event that just happened. Now here's a simple exercise for you. Let's imagine in our logger module, just before calling our remote service to log the message, we're going to raise an event called logging. And while raising this event, we also want to send some data. That is a message that we are going to log. So what I want you to do is to use what you have learned in this lecture and raise and handle this logging event. It's a very simple exercise. I just want you to get used to this syntax. 11. Expanding EventEmitter: Advanced Event Handling: Now in the real world, it's quite rare that you would work with this event emitter object directly. Instead, you want to create a class that has all the capabilities of the event emitter, and then you will use that class in your code. Let me explain what I mean by that and why. So let's open up our logger module. And in this module, we're exporting a simple function Milo right? And here, we log that message on the console. Now, this is the common Javascript syntax. Let us change it. As we are now using the ES six modules, we need to write export default, Milog. After this, we want to raise an event, and then later in app module, we will listen for that event and do something. So let's go back to our app module and copy some code in the logger module. From the top, I'm going to copy these two lines to bring the event emitter in this module. Okay? Now, back in app module, I'm also going to move these two lines for raising an event into the logger module because this code should not be here. It's a logger module that emits or signals event saying the message is log. So cut here, after we log the message, we raise an event like this. Okay? Now, back in app module, we don't need this command. Here we need to log the logger module and call the MogFunction. So to load the logger module, we'll use the import functionality of the Six modules. So import log, I renamed it to log from slash logger dot Gs. Very easy. And here we simply call the log function with a message. Okay? Now when we run this application, we are only going to see this message on the console. In other words, this event listener will not be called. Let's verify that, and then I will explain why that happens. Back in terminal node, app Jas, look, we only got the message on the console. So our event listener was not called. The reason for this is because here we are working with two different event emiters. In App Js, we have this event emitter object, and in lower module, we have another event emitter object. So earlier, I told you that a class is like a blueprint and an object is an actual instance. As a metaphor, I said we could have a class called human or person, but the objects could be Eric, Steve, David, Maria, whatever. But in this case, we have two different objects. In the logger module, we're using this emitter object to emit an event, whereas in app module, we are using another entemeter object to handle that event. These are completely different. When we register a listener here, that listener is only registered with this event emeter which is completely different from the other event emitter. So that's why I told you in your applications, it's very rare that you would want to work with this event emitter directly. Instead, you want to create a class that has all the capabilities of this event emitter, but it has additional capabilities. In this case, you want to create a class called logger that has this additional method, log. Okay? So the first thing we want to do here is define a class. In ES six, we have this keyword class, which is a syntactical sugar for creating a constructor function. With this, we can define a class, logger. Note that the first letter of every word in a class should be uppercase. This is a pascal case convention that we use for naming classes. Class logger, we have a code block, we need to move this log function inside this logger class. So cat past it here. Now we have an error because we define a function inside a class. We don't need this error function from now on, we refer to this function as a method. So when a funtion is inside a class, we say that's a method in that class, okay? So here, we have this lager class. Now at the end, instead of exporting the Mel of pointie we are going to export the larger class. Okay. Now we want this lower class to have all the capabilities of this event emitter. The way we do that is by using the extents keyword that comes in ES six, so extends. And here we add the name of the parent or the base class, so event emitter. And with this simple change, this lower class will have all the functionality that is defined in event emeter. So here, when raising this event, instead of using this emitter object, we are going to use this so in this class, we can directly emit or raise events. Okay? Now we no longer need this actual emitter object because we have not used it anywhere in this code. So delete. We're done with the logger module. Now, back in the app module, so here, when importing the logger module, we get a class. So I'm going to rename this logger with L. That's a class. Now we create an object, so new logger, and then to log a message, we call logger dot log. Now, similar to the change that we made in Lager module, we no longer need this event dimeter object. Here, we want to work directly with this lower object. So we are going to register this listener on this lober object. Okay? So I'm going to move this code. After creating the logger, we say, Hey logger, when you raise this message locked event, I want to execute this code. And finally, you can see we no longer need this event emitter object. It's not used anywhere, the late now when we run this application, we are going to see this message on the console. But also because we are using the same lo or object for registering an event listener and also raising an event, we are going to see this message on the console. So note app Jazz look, this is a message on the console, and you see our listener was successfully call. So let's quickly recap. If you want to raise events in your application to signal that something has happened, you need to create a class that extends event emeter. With this, that class will have all the functionality defined in event emitter. But you can also add additional functionality. In this case, we have the ability to log a message. And then inside that class, whenever you want to raise an event, you use this dot met because this references the logger class itself, which extends event emitter. So all the methods defined in event emitter will also be part of this class. And finally, in app module, again, instead of using an instance of event emitter, you will use an instance of the custom class that you have defined that extends event emeter. 12. Handling HTTP Requests: Node.js Networking: One of the powerful building blocks of node is the STDP module that we use for creating network applications. For example, we can create a web server that listens for STDPRquest on a given port. And with this, we can easily create a backend service for our client applications, like a web application that we built with react or angular or a mobile application running on a mobile device. So once again, back in the node documentation, the list of modules, you can find this TDP module. In this module, you can see various classes like tt dot agent, http dot client request, and so on. Each of these classes has a bunch of properties, methods, and events. So back in VS code, let's load the SGTP module. So import ASTC as HTTP from node STT. Okay. Now here we can call db dot, create server. This is one of the functions defined in this module. And with this, we can create a web server. So let's store the result in a server object. Now what is interesting is that this server is an event emitter. So it has all the capabilities of event emitter that is so earlier in this section. So look, server dot we have the on method. Or add listener or M and song. Also, if you look at the documentation of the SGTP modo, on this page, you can see http dot server class. Here, the documentation says that this class inherits from net dot SAR. So this is another class defined in the net module. Let's have a look. Now, here in the documentation says that Net dot server is an event emitter. But that's why I said a bunch of nodes, core functionality is based on event emitter. So back to our server object. Now we can call server dot LISN and give it a port. Let's say port 3,000. Now, following that, I'm going to add console dot log saying listening on port 3,000. Okay? Now when we run this application, the server will listen on port 3,000. As I told you before, every time there is a new connection or new request, the server raises an event. So we can use the on method to handle that event. So before listening, we want to register a listener or a handler. So server on the name of the event is connection that you can find in the documentation. You don't have to memorize any of this stuff. And the second argument is a callback function or the actual listener. As you can see in the tool tip here, this listener is a function with one argument that is socket of type socket class, and it turns Y. So here we have the arrow function syntax in ES six. So let's add an arrow function that takes a socket and goes to this code block. Now here we can simply lock something on the console name connection. Now back in a terminal, let's run this application. You can see we are listening on port 3,000. Back in the browser, let's head over to local host port 3,000. Now if you look in the terminal, you can see we have a new connection here. So you can see this SR object raises different kinds of events that you can respond to. Now in real world applications, we are not going to respond to the connection event bill HTTP service. This is very low level. So let's delete this. What we commonly do is we pass a callback function which creates method. This function takes two parameters request and response. Now in this function, instead of working with a socket, we can work with the actual request or response objects. So we can check if request URL equals slash, then we can send something to the client. For example, response stat, write, hello world, and then we end the response. Okay. In the terminal, we can exit here by pressing Control C and then run the application again. We are still listening on port 3,000. Let's refresh the page. So we got hello on the homepage. Now we want to build a backend service for a web or mobile application, we need to handle various routes here. For example, we can have another I block if request URL equals API slash courses. Perhaps here we want to return the list of courses from the database. So we would do something like this, response dot right. Now here we want to return an array of objects using JCN. So we use cn dot stringify and give it an array of objects. Now for simplicity, here we don't have to worry about the database or complex objects. Let's just return an array of numbers one, two, and three. So we pass this to JCN stringifi which will convert this array into a string using JSN syntax. And then we'll write it to the response. Now back in the terminal, we need to stop this process again and run it one more time. Now in the future, I will show you how we can automate this. So every time we make a simple change to our application, we don't have to restart. So now back in the browser, if we go slash API slash courses, we get an array with three numbers. So as you see, building a web server with node is very easy. Now in the real world, we are not going to use this SDDP module to build a backend service for our application. The reason for this is because as you can see here, as we add more outs, this code gets more complex because we add all of them in a linear way inside this callback function. So instead, we use a framework called Express, which gives our application a clean structure to handle various routes. Internally, the express framework is built on top of the STDP module in note.