Introduction to Node
Tags: javascript, beginners, node, codenewbie
Published: 2021-02-15 18:27:37

Over the last several years JavaScript has redefined the landscape of the internet, becoming a ubiquitous and essential language. Much of that proliferation was the result of runtime environments that aimed to take JavaScript (or JS) outside the confines of the browser. Many projects tried to accomplish this goal, but none caught on quite like NodeJS did when it arrived in 2009. 

With NodeJS, JavaScript can run both in the browser *and* the computer processor, allowing developers to build fully-functional single page applications that once were only possible with languages like Java, Ruby, C++, Python, and more. 

In this series we'll be taking a look at the NodeJS environment, discussing important paradigms and patterns crucial to understanding it. Later we'll use Express and Knex on top of Node to build a RESTful API with CRUD capabilities. 

👉 NodeJS is written in C, C++ and JavaScript, on top of the [V8](https://v8.dev/) JavaScript engine that powers JS in browsers like Google Chrome.

----

## Intro to NodeJS

NodeJS, or Node for simplicity, is a ***runtime environment***. This concept is hard to put into words, but I think of a runtime environment as a program like any other. When executed the program enters a "runtime state." In this active state it can execute other programs, all while having access to the computer's processor, RAM, and other resources. 

What Node is to JavaScript, our physical world is to us - the place we exist, where we can perform functions, and have access to various resources. 

Node is, logically, more intuitive if your background includes JS. By nature JS is an asynchronous language, and Node is built on a callback based system to accommodate that.

The choice to use any one environment, framework or library comes with the responsibility to weigh both the advantages and disadvantages. What makes a program a solid solution on one team, can be the same things that make it an obstacle on another. 

Let's look at some of the features of Node that make it a solution, and why those very same features can also be roadblocks. 

#### ✅ Pros:

- **Same Language:** Using JS on both the server and the client means we don't have to adapt to paradigm and syntax shifts, reducing complexity and confusion for developers. 
<br>

- **Asynchronous:** Takes full advantage of JavaScript's processor - supporting asynchronous operations to read/write, connect to database servers, handle user requests, etc.
<br>

- **Single-Threaded:** This isn't strictly true - the Node program, and its imported modules, will run on a single thread, while the engine and IO run on another. Either way, it reduces the complexity behind multiple threads in languages like Java.
<br>

- **NPM:** Access to the npm registry - a huge library of npm modules, that often make developer-life easier.

#### 📛 Cons: 

- **Same Language**: In programming we have various languages because each of them do *one thing* really well. Like the tools in a toolbox, they're all useful given the right job. Limiting ourselves to JS means using a tool that might not be right for the job. 
<br> 

- **Asynchronous:** If you, or your team, are unfamiliar with handling the wonky async activity of JS, there can be a steep learning curve. Especially those coming from languages that are built on a synchronous approach to operations.
<br>

- **Single-Threaded:** This comes back to the concept of the "right tool for the job." We lose the advantages of servers with multiple threads.
<br>

- **NPM:** The npm registry is *big*, perhaps too big. Using it has the potential to open a project up to vulnerabilities or future deprecations from poorly maintained libraries.

We're going to build a simple server to discuss the fundamentals of Node further, but for now it's important to understand that Node is an environment that allows JS to run outside of the browser. 

----

## Installing Node 

To continue, make sure that Node is installed on your machine and it's up-to-date. To check, open a terminal window and provide the following command: 

> node -v

If Node is installed this command will return the current version available. If you don't have Node, or its current version, head to the official [NodeJS](nodejs.org) site and download it from there.

❓ Confused about what version to download? You'll find two versions of Node available on the official site, an "LTS" and a "Current" version. LTS stands for "long-term support", meaning it's being actively maintained and upgraded - but experimental features that don't see full support are not included. For our purposes, we're going to want the LTS version of Node.

----

## Creating a Server

In the context of Node, a ***server*** is a place in a computer that listens for traffic. That traffic comes in the form of a user visiting a URL. 

When a user visits a website, they're making a request for a resource. It's up to the server to take that request, and decide what resource should be sent back. We as developers will be responsible for writing the code that gives a server the ability to make that decision. 

In a directory of your choosing create a new folder for this example project, I've named mine `node_server_ex`. Inside that folder create an `index.js` file. 

Inside `index.js` we only need to add these few lines and we're ready to get off the ground.  

```jsx
// index.js

// 1️⃣
const http = require('http'); 
const host = `127.0.0.1`; 
const port = 3000; 

// 2️⃣
const server = http.createServer((req, res) => {
	res.statusCode = 200; 
	res.setHeader("Content-TYPE", "text/plain"); 
	res.end("Hello World, from Node!"); 
}); 

// 3️⃣
server.listen(port, host, () => {
	console.log(`server listening on http://${host}:${port}`);
}); 
```
 
Let's step through the code line-by-line and learn how JS and Node work together.  

----

### 1️⃣ Variables `http`, `host` and `port` 

A server helps computers communicate - Node accomplishes communication using a built-in module called the ***HTTP Module***. The http module is expansive, offering a suite of available properties, classes and their bound methods. 

👉 If you're new to programming and are unclear about *what* a module is - a module is an object that contains a whole bunch of pre-built functions and classes we can choose to use. Pre-made functionality for the low-low price of free. 

To include the http module we need to use the `require` syntax.

```jsx
const http = require('http'); 
```

You may be used to importing modules in JS using the `import MODULE from PACKAGE` syntax - this is the same thing, though more antiquated. Import syntax happens to be an ES6 feature and because Node runs on the V8 JavaScript engine, which supports new features like ES6, the import syntax *will* work for newer modules but will not for the older, core ones. 

Providing the `host` and `port` variables allows us to set up constants that tell Node where to run, and where to listen. For the time being `host` directs Node to run on your local machine, and `port` is a number indicating the communication endpoint between the server and user.

----

### 2️⃣ `createServer` Function 

After requiring the http module, we first put it to use by creating an instance of a Server class. We know that a *class* in programming is an object built for a specific purpose - equipped with data and behavior presets designed to fulfill that purpose. 

If we had to build our own server class we would find it a monumental task - there's a lot to consider, and huge room for error. Thankfully for us, the talented and knowledgeable developers at Node did that for us and made it available to use on the http module. 

To create an instance of a Node server class, we simply call `http`, and the `.createServer()` method, storing it in local variable `server`: 

```jsx
const server = http.createServer((req, res) => {
        res.statusCode = 200; 
	res.setHeader("Content-TYPE", "tex/plain"); 
	res.end("Hello World, from Node!"); 
}); 
```

The `.createServer()` method takes a callback function that passes two parameters - the *request object* and the *response object*, `req` and `res`. 

As their names imply, these objects contain information about a user request, and the server's response to that request. They can contain hundreds of properties and complex data structures, or they can be nearly empty, sending simple pieces of information. 

📝 `req` and `res` are just implicit names we picked, they can be called anything, but they always map to the `http.IncomingMessage` and `http.ServerResponse` classes respectively. These classes were created as a result of instantiating a Server class with `http.createServer()`. 

In this example we're using the response object, and some its Node-provided methods, to send something to the user. The `.statusCode()` method sets the http status code to the "all clear!" code of `200`, indicating a successful connection. 

There are five classes of status codes, each intended to relay a different message. Using them correctly should be given special attention. 
- **1XX**: Informational - The *"We're all fine here now, thank you. How are you?"* of status codes.
- **2XX**: Success - The "happy path." These are the status codes indicate that the server and client are communicating as expected.
- **3XX**: Redirection - If a server needs to pass off a request for further action before it can be completed, then a 3XX status code is used.
- **4XX**: Client Error - These errors point to a problem with the client - it could be an incorrect URL, unauthorized request, and so on.
- **5XX**: Server Error - 5XX errors tell us that the client is successfully sending a request, but the server is unable to handle it for some reason.

👉 We won't see much of the 1XX or 3XX codes, but using the correct 2XX, 4XX and 5XX codes will be important later! 

In a perfect world the user won't be aware of these status codes, they're quietly hidden away in component of the request and response object known as the ***headers object***. For developers, the headers are like a reference - a place we can know to look for more information about a request or response - like the date and time, authorization and server status, along with other useful operating parameters. 

In the `.setHeader()` method we added an additional operating parameter to the response headers that will be tacked on with the status code we set above it. That parameter defines the `"Content-TYPE"` of the response to be `"text/plain"`. This lets the browser know what type of data it will be receiving, so it can prepare itself to display that while the rest of the response loads asynchronously. 

Maintaining well-informed headers only works to serve yourself and your fellow developers. Headers encourage meaningful communication between the front and backend, reduce errors and bugs, find and diagnose those bugs more quickly when they do arise, and improve performance.

Finally, the http transaction is terminated with the `.end()` method. This method ends the server function, passing in the resource that user originally asked for. That resource will be added to the response object along with the headers we constructed, where it will usually be consumed by the frontend in some way. 

--- 

### 3️⃣ `listen` Method 

Event handlers are a core feature of most programming languages, adding interactive features to a program through binding actions (what are commonly called "listeners") to elements. Or, as is the case in our example, to a port - a place in a computer. 

In JS, we're familiar with binding an action to an element, like a button, using `.addEventListener()`. When that button is later clicked (acted upon), something will happen. In Node, using the `.listen()` method is the loose equivalent. Loose because despite both using JS, the event model in the browser environment and the event model in the Node environment are not identical.  

This step is akin to turning the server on - we'll pass 3 of 4 optional arguments so that the server first knows where it will receive traffic, and second, will give us a message when the event listener is successfully bound - that is, it's listening! 

```jsx
server.listen(port, host, () => {
	console.log(`server listening on http://${host}:${port}`);
}
```

The `.listen()` method comes to us on the Server class of the http module. It takes up to four arguments - a port, a host, a backlog and a callback function. This callback function is kind of like a "listener for the listener." It only fires when the listener is successfully bound, meaning that the server was able to start watching for traffic at the port we gave it.

#### 📝 About Developer Style

In our example the `.listen()` method is called on its own line but you'll see this done differently, with other arguments passed, by other developers. Code is pliable, and methods are usually chainable. For example, we could have omitted the third argument and attached the event listener to the tail of the `createServer` function. 

```jsx
const server = http.createServer((req, res) => {
	res.statusCode = 200; 
	res.setHeader("Content-TYPE", "tex/plain"); 
	res.end("Hello World, from Node!"); 
}).listen(port, host); 
```

Both examples achieve the same result - letting the server know that we want it to start listening at port 3000 on our machine. The subtle differences in approach come down to developer style. Personally, I find the file easier to read from top to bottom when major actions, like turning the server on, get their own space in the document flow. Pay attention to these differences, reasoning about them and trying them out in your own projects can help you get better at reading code and develop your coding style.

----

## Interacting the Server 

With our simple server built, we'll see if it works by executing it inside of the Node environment. To do that make sure the `index.js` file is saved and open a terminal window. 

From there we need to navigate to the directory the server can be found in. The `cd` command stands for "change directory", use it to move through the directories and files of your machine. You can chain further directions by using a forward-slash, `/`. 

I've stored this project in a folder named `node_server_ex`, located on my desktop. I can navigate to it like so:

> cd desktop/node_server_ex

Once in the correct directory, use the "list files" command, `ls`, to make sure `index.js` is there. 

> ls

→ `index.js`

Now we call Node and tell it to run the server by giving its file name. 

> node index.js

Assuming everything goes as planned and there are no errors, the Node environment will execute the file, going through the code inside, turning on the server's event listener, and finally returning the message found in the `listen` method's callback function: `server listening on http://127.0.0.1:3000`

The terminal window is now devoted to propping the Node environment so the server can continue running, waiting for user traffic. We can't use this particular window for anything else right now - if you try to navigate to a different directory, or use the `ls` command, nothing will happen. But we need to keep it open or the Node environment will close, taking the server with it.

With the server running, we now just need to visit its port so we can see what it's sending! Open a browser window and navigate to `http://localhost:3000` - where you should see your server's welcome message - "Hello World, from Node!". 

--- 

With that, you've built a Node server! It can't do much right now, but this example helps conceptualize some of the fundamentals of Node. We learned that inside the Node environment we can use JS outside of the browser - on the backend - to process user requests, send responses and provide the functionality of a full-featured computer application.

Much of the work done in Node relies on its communication-obsessed http module, which gives us a robust Server class and a myriad of methods to receive and handle and manipulate requests, send detailed headers and more. 

In later installments of this series on Node and Express we'll discuss more about the asynchronous nature of Node and JS, cover some database fundamentals, and see how Node, Express and JS can be used to perform CRUD operations and build RESTful APIs. 

---
#### Resources: 

- [What is Node?](https://www.codecademy.com/articles/what-is-node) - codecademy
- [Hypertext Transfer Protocol](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) - w3schools
- [Node.js server.listen() Method](https://www.w3schools.com/nodejs/met_server_listen.asp) - w3schools
- [A Look at Server-Sent Events](https://medium.com/conectric-networks/a-look-at-server-sent-events-54a77f8d6ff7) - Simon Prickett
- [JavaScript Events](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events) - MDN
- [Node Official Site](https://nodejs.org/en/) - *highly* recommend the docs on the official site - they're well put together and exhaustive

I hope you enjoyed the first part of this series - if I got anything wrong, didn't explain it enough, or missed something important - please reach out and let me know! All feedback is welcome, and *thank you for reading* 🦄

----

#### Errors and Updates:

###### Update 3/10/21: I updated the section on http headers. I was erroneously referring to the "header" object, when I should have been referring to the plural "headers." This was a misstep I became aware of as I prepare to share the next part in the series.