What is Node.js?
Node.js is a platform that allows coders to use Javascript to work both the front and backend of web applications. One of the benefits of using Node.js is that it is non-blocking. For example, when using Apache, each client is assigned a dedicated thread that facilitates all transactions. However, when the thread is given a request, it will ignore all other requests until that request has been fulfilled, even if it is just waiting for data on the server-end of things. In contrast, a non-blocking model like Node.js assigns one thread for all users but this thread is able to perform tasks asynchronously. If its current request requires some data to be retrieved from the server, it simply moves on to the next request rather than idly wait for that data to be ready.
Running Node.js
To run Node, you'll first need to install it. Now you can use Node to run JS files. You can do so by navigating to the files in your command line and writing node filename
. You don't need to add the extension at the end because Node automatically assumes it will be a JS file.
The Global Object
Node has access to a global
object which contains some stuff Node can parse and use without having to import any other modules. One of these is the very familiar console
object, which is used to generate output to the console. We can also use the global to return the directory name and filename via the variables __dirname
and __filename
respectively.
Global Objects
process
object
The process
object is useful for finding out information on the current process as well as interacting with that process by accessing command-line arguments.
process.pid
process.versions.node
process.argv
node cats
. The resulting argv
array would have two elements: the file path to wherever Node is installed, and the path to whereever the cats module is. You can extend this function to pass arguments to your modules.process.stdout.write("some output")
process.stdin.on("data", do something with data)
data
. The second argument (commonly a function), does something with that data. For example, the following codes takes the data input and repeats it back to the user:
Note that the recorded data is stored as a binary so we need to use the toString()
function to change it to a String.
process.exit()
process.on("exit", do something)
A full list of other Globals can be found here.
Modules
To add functionality beyond the global, we'll need to add modules. Modules are essentially Node.js files written to do specific things. Node comes with its own set of modules and we can also use modules that we install with NPM or modules we've written ourselves. To import a module, we'll need to use the global object's require
function.
require("modulePath")
For example, we can import the path
object and use its basename()
function to return the filename of a given path.
Core Modules
As said before, there are modules that come shipped with Node. These are called Core Modules. Here's a compendium of major global modules.
readline
Module
The readline
module works with standard input and output and makes it easy to create an app that responds to user input. First we'll need to import the mdodule.
Now we need to create an interface for readline
using its createInterface
function. We're simply specifying what our current process will use as input and output.
Now we're free to use any of the readline
functions to gather user data and generate output.
interfaceVar.question("a question", do something with the data)
Events
The Events
module allows you to generate custom events, allowing you to wire listeners and handlers for those events.
After importing, you construct a new event emitter object using the EventEmitter()
constructor
Now we can start raising events wherever we want.
emitterVar.emit("eventName",data1,data2,...)
emitterVar.on("eventName", callback handler)
.emit()
function.Using Custom Modules
Sometimes when we're writing modules, we want to incorporate things from past modules we've created. To grab them, we'll first need to make them exportable. We do this by going to the module we want to export, using the module.exports
method and putting all our functions we want to export into a comma-separated list.
Now when we import our custom module using the requires
function, we'll have access to all module methods we chose to export. Note: if we want to access the values of variables local to the modules we import, we'll need to have getter and setter functions defined within our imported module and use those to retrieve the values.
Interacting with Files
Node is also capable of messing around with the file system with a handy module called fs
. Like any module, we'll need to import it first before we can use it.
fsVar.readdirSync("path")
fsVar.readdir("path", (err,files)=>{do something})
fsVar.readFileSync("path", "text encoding")
fsVar.readFile("path", (err,text)=>{do something})
fsVar.writeFile("path",text you want to use, err=>{ error handler})
fsVar.mkdir("directory name", err=>{ error handler})
existsSync()
function.fsVar.existsSync("path")
fsVar.appendFile("path",text you want to use, err=>{ error handler})
fsVar.renameSync("path","new filename")
fsVar.rename("path","new filename", err=>{error handler})
fsVar.unlinkSync("path")
fsVar.rmdir("path",err=>{ error handler})
fsVar.createReadStream("path","text encoding")
.on("data"...)
, or .once("data",...)
fsVar.createWriteStream("path","text encoding")
.write("text")
function to write that text to the file as a stream. Can combine with the read stream to copy contents of one file into another. Can also try the pipe
keyword which directly hooks the output of one object as the arguments of another. Child Processes
Node also lets you create and handle child processes, which are other applications that your app can communicate with. To start, we import the child_process
module.
cpVar.exec("open path or url of resource to open")
cpVar.exec("command",(err, data)=>{})
. If you want to use a child process that is asynchronous, use the .spawn()
function.cpVar.spawn("node",["module file path"])
The HTTP and HTTPS Module
The HTTP
and HTTPS
modules allow you to access and deploy resources on the internet. Before we do anything, we'll first need to import the appropiate module. If the target site is http, we'll need to use the http
module; the same logic applies for https sites.
Creating a GET request
For a GET request, we'll first need to build an object that will contain all of our properties for our request. We'll need to supply:
- hostname
- port number
- path
- method
Once we have our options, we can use the request()
function to make our request. This function takes two arguments. The first is the object containing all our connection properties. The second is a callback function that will allow us to work with the resource when it is retrieved.
The optional setEncoding()
allows us to format the stream that it comes back as a string instead of just bits.
Not bad, but the HTTP modules provide an even easier way to make GET requests, through the get
method. Instead of plugging in an object with all of our paramters, we just type in the URL. The get
method will automatically retrieve the rest of the parameters for us!
Regardless of which method is used, remember to call .end()
on your request object to end the connection after you're done.
Creating a Web Server
We can use the createServer()
function to create a web server. Before we put any arguments in, we'll set the port that our server will listen to (in this case 3000).
Now for our argument. We'll use a callback handler that will be passed two objects that are returned for every request to our chosen port: a request and a response object. First we'll focus on the response, i.e. what is sent back to users who make a request. We use response.writeHead()
to send a header to the browser with a code (200 for success) as well as the encoding of our response. We use response.end()
to end the response and return some content to the clients browser. In this case, just a simple "Hello World" string. Finally we set a log message to let us know that the Web Server is active.
Now when we navigate to port 3000 on our browser, we'll see our response we just created.
Rather than send text, its more likely we'll want to deliver web pages to our clients. To send HTML instead, just change the Content-type
to "text/html"
. Now instead of a string, you can put in full HTML into the resouce.end()
function.
So if thats the response object, then what is the request object for? Well the request object has a few property values that we can grab to use. For example, calling request.method
returns the method used in the request i.e. a GET or a POST. If you call request.url
, you get the URL that was used to make the request. These properties are important for deciding what should get sent out in the response.
Creating a File Server
Now that we know how to serve up single pages, we can use our knowledge of the filesystem to generate a fileserver to serve multiple files.
As you can see, the request object becomes handy in determining what page is sent as a response to the user, based on the URL they entered.
Third-party File Servers
Instead of coding it ourselves, we can actually set up servers by simply using a prebuilt package. One of these is the serve
package. It's a global package which means we can use this anywhere, in any folder to start a file server. Another good tool is express
package which provides a nice framework for creating file servers.
Creating Files Server with Express
The basic framework for building file servers with Express is as follows.
We import the express
module and create an instance of the app
object using the express()
function. We use app.use(express.static("directory location"))
to serve our static webpages which are all stored in that directory. Finally we set up our listener on port 3000 with app.listen()
which contains a callback function that will load a message to console when our webpage is up and running.
Collecting POST Data
Forms are a good way of collecting data from your users. When creating web forms in HTML, we can set a property to have the form POST the data back to the server when the form is complete.
Then, when users fill out a form on your site, a POST request is sent to the server where it can be managed in the createServer()
function.
The POST data that comes back arrived enocded in a URL format which makes it slightly hard to use. Luckily, Node.js has a core module called querystring
that will help us decode URL data.
First we'll destructure the decode
method out from the querystring
module
Then, we'll use the decoder to decode the data once we've finished collecting it from the stream.
What are packages?
In Node.js, whenever we start a project, we typically want to create a new package. We do so with in the commandline with NPM.
This starts a walkthrough where we get asked what we want our package to be called, the author, a description and so on. Upon completion, we get a package.json file, that has all the parameters and values we provided.
Now we can create our module, which must be named the same as the answer we provided in the main
section of the JSON. When we install and use new modules from NPM, the package.json will automatically update itself, listing each new package we've installed as a dependency. These external modules are installed in a folder called node_modules. If at some point this folder is deleted, our module won't run anymore! Luckily, all we need to do is run npm install
from the command line and NPM will go to our package.json folder, find the dependencies, and install them automatically. Another useful command is NPM outdated
which checks whether any of the dependencies in the project have newer versions available.
Global packages
If we want to make our modules runnable from anywhere, not just the project folder there are a couple steps:
- Add the following line to the top of the package.json:
#!/usr/bin/env node
. This tells Bash to use Node when running this file. - Also in the package.json, add the property
"bin:"
and put any keywords you want to use to activate your module globally, followed by the filename of the module. It should look something like this: - In the project folder, enter the keywords
npm link
in the command line. This links the project to the list of global commands.