Introduction to Node.js
Published: 2021-11-22 07:49:45

#1. Introduction, Set up and Basics
![1](https://dev-to-uploads.s3.amazonaws.com/i/oab19bjta4rd873rr3i3.png)

To check node version in my computer: `node -v`
To start node console: `node`

Running a javascript file 'test.js'
```
//filename test.js
const name = 'rittwick'
console.log(name)
```
Command to run this file: `node test`

#2. Basics
##1. The **global** object
There is an object called *global* in node. The same object in browser console is called *window*.
Checkout `console.log(global);` in node console.
This object contains functions like `setInterval`, `setTimeout` etc.
File `globaltut.js`:
```
const interval = setInterval(() => {
    console.log('In the interval');
}, 1000);

setTimeout(() => {
    console.log("In the timeout")
    clearInterval(interval);
}, 5000);
```
The output will be:
```
In the interval
In the interval
In the interval
In the interval
In the timeout
```

### Finding the filename and directory name in node
```
console.log(__dirname);
console.log(__filename);
```

Some attributes are present in node and not in window and some are present in window and not in node global object.For example 'document' is present in window object and not in node.

##2. Modules and Require
We've two files: `people.js` and `data.js`
people.js contains:
```
const persons = ['arun', 'shankar', 'vinod', 'irfan'];
console.log(`From people.js: ${persons}`);
```
data.js contains:
```
const xyz = require('./people');
console.log(`From data.js: `, xyz);
```

```
From people.js: arun,shankar,vinod,irfan
From data.js:  {}
```
This way persons array is not available in data.js. We have to manually send from person.js to data.js. 

people.js have to contain a line:
``` 
module.export = persons;
```
Then only person is accessible to data.js.
Note: *In require statement the path should be a relative path not an absolute path*

### Exporting multiple things from person.js to data.js
people.js
```
const persons = ['arun', 'shankar', 'vinod', 'irfan'];
const ages = [12, 22, 44, 9];

module.exports = {
    personsList: persons,
    agesList: ages
}
```
data.js
```
const xyz = require('./people');
console.log(xyz.personsList);
console.log(xyz.agesList);
```
Output on running `node data`:
```
[ 'arun', 'shankar', 'vinod', 'irfan' ]
[ 12, 22, 44, 9 ]
```

`persons` array of people.js --> `personsList` array of data.js 

To call `persons` array of people.js as `persons` in data.js:
people.js: 
```
module.export = {
    persons: persons,
    ages: ages
}
```
There is a shortcut of these method:
```
module.export = {
    persons, ages
}
```

Now there are different types of accessing tricks:
Trick 1
```
//people.js
const persons = ['arun', 'shankar', 'vinod', 'irfan'];
const ages = [12, 22, 44, 9];

module.exports = {
    persons, ages
}


// data.js
const xyz = require('./path_of_people')
console.log(xyz.persons);
console.log(xyz.ages);
```

Trick 2
```
//people.js
const persons = ['arun', 'shankar', 'vinod', 'irfan'];
const ages = [12, 22, 44, 9];

module.exports = {
    persons, ages
}


// data.js
const { persons, ages } = require('./path_of_people')
```

Trick 3
```
//people.js
const persons = ['arun', 'shankar', 'vinod', 'irfan'];
const ages = [12, 22, 44, 9];

module.exports = {
    personsList: persons,
    agesList: ages
}


// data.js
const { personsList } = require('./path_of_people')
//agesList is not accessible now. Only personsList is imported here.
```

node also has some built in modules: For example:
```
// OS MODULE
const os = require('os');
const os = require('os');
console.log(os.platform());
console.log(os.homedir());
```

Another important built in module is filesystem module
##3. The filesystem
####Reading the file
```
const fs = require('fs');
fs.readFile('./textfile.txt', (err, data) => {
    if(err){
        console.log('Some error happened');
    }else{
        console.log(data);
    }
})
```
Output:
```
<Buffer 6c 6f 72 65 6d 20 69  ... 94 more bytes>
```
`data` is a package of objects. To read it we have to convert it into string.
```
console.log(data);
//Output: <Buffer 6c 6f 72 65 6d 20 94 more bytes>

console.log(data.toString());
// Output: This is a nice tutorial
```

Note: `readFile` is asynchronous function. Following code reveals that:
```
const fs = require('fs');
fs.readFile('./textfile.txt', (err, data) => {
        console.log(data.toString());
})
console.log('last line of the code')
```
The output will be: 
```
last line of the code
This is a nice tutorial
```



####Wirting the file
```
fs.writeFile('./new.txt', 'hello rittwick', () => {
    console.log('File was written');
}
```
`writeFile` is also a asynchronous function. This function overwrites the file if the file already exists and creates, writes the file if the file already not exists.


####4. Creating and Removing Directories
```
fs.mkdir('./assets', (err)=>{
        if(err){
            console.log('Some error happened 1');
        }else{
            console.log('Folder created');
        }
    })
```
`mkdir` creates the folder if does not exists. If exists then returns error.

Creating the folder if not exists and deleting otherwise:
```
if(!fs.existsSync('./assets')){
    fs.mkdir('./assets', (err)=>{
        if(err){
            console.log('Some error happened 1');
        }else{
            console.log('Folder created');
        }
    })
}else{
    fs.rmdir('./assets', (err) => {
        if(err){
            console.log('Some error happened 2');
        }else{
            console.log('Folder Deleted');
        }
    })
}
```

####5. Deleting Files
```
if(fs.existsSync('./deleteme.txt')){
    fs.unlink('./deleteme.txt', err => {
        if(err){
            console.log('Some error occurred ');
        }else{
            console.log('File deleted successful');
        }
    })
}
```
`unlink` deletes the file if exists otherwise returns an error.

##4. Streams and Buffers
Starts using data before it has finished loading completely. For example loading a chunk of data and watching the video before the video fully loads.
####Reading a stream
```
const readStream = fs.createReadStream('./docs/huge.txt');
readStream.on('data', (chunk)=>{
    console.log('-------NEW CHUNK---------');
    console.log(chunk);
})
```
This will output some buffers. To get a readable text:
`console.log(chunk.toString())`
OR there we can directly encode it to a readable string:
```
const readStream = fs.createReadStream('./docs/huge.txt', { encoding:'utf8' });
```

####Writing a Stream
```
const readStream = fs.createReadStream('./docs/huge.txt', { encoding:'utf8' });
const writeStream = fs.createWriteStream('./docs/newhuge.txt');

readStream.on('data', (chunk)=>{
    writeStream.write('\nNEW CHUNK\n');
    writeStream.write(chunk);
})
```

####Piping
Reading streams and writing it into a writestream.
```
const readStream = fs.createReadStream('./docs/huge.txt', { encoding:'utf8' });
const writeStream = fs.createWriteStream('./docs/newhuge.txt');

readStream.pipe(writeStream);
```


#3. Client and Servers
####Creating a server in node
```
const http = require('http');

const server = http.createServer((req, res)=>{
    console.log('Everytime a request is made, I pops up.');
})

```
The callback function in the above code block runs every time a request is made.
The arguments of the callback function are `req` and `res`. In `req`, the information about incoming request is present and through `req` the response is sent back.

This alone is not doing anything. The `server` have to actively listen to the requests.
`server.listen()`
```
server.listen(3000, 'localhost', ()=>{
    console.log('Listening to port number 3000')
});
```

#4. Requests & Responses
##1.The Request Object 
Getting the request url and request method: `req.url` & `req.method`
```
const server = http.createServer((req, res)=>{
    console.log(req.url, req.method);
})
```

##2. The Response Object 
Sending response is a three step process:
1. setting the response header
2. writing the response
3. sending the response
```
const server = http.createServer((req, res)=>{
    //Setting response header
    res.setHeader('Content-type', 'text/plain');

    //Writing the response
    res.write(`Hello, Rittwick!`);

    //Sending the response
    res.end();
})
```

In the above code we're just sending plain text. We can also send html.
```
const server = http.createServer((req, res)=>{
    console.log(req.url, req.method);
    //Setting response header to 'text/html'
    res.setHeader('Content-type', 'text/html');

    res.write('<h1>Hello! Rittwick</h1>');

    res.end();
})
```

The browse automatically adds the other tags body, html and head. We can overwrite them.
```
const server = http.createServer((req, res)=>{
    res.setHeader('Content-type', 'text/html');

    res.write('<head><title>Hello page </title></head>');
    res.write('<h1>Hello! Rittwick</h1>');

    res.end();
})
```

##3. Sending html files
```
const server = http.createServer((req, res)=>{
    res.setHeader('Content-type', 'text/html');

    fs.readFile('./views/index.html', (err, data) => {
        if(err){
            res.end();
        }else{
            res.write(data);
            res.end();
        }
    })
})
```

Instead of doing the following in two lines, we can do it in one line `res.end(data)`
```
res.write(data)
res.end()

Instead the shortcut
res.end(data)
```
When we are sending the only one data, like the above then only this shortcut can be applied.

##4. Basic Routing
```
const server = http.createServer((req, res)=>{
    res.setHeader('Content-type', 'text/html');
    let path = './views/';
    switch(req.url){
        case '/':
            path += 'index.html';
            break;
        case '/about':
            path += 'about.html';
            break;
        default:
            path += '404.html';
            break;
    }
    fs.readFile(path, (err, data) => {
        res.end(data);
    })
})
```

##5. Status Codes
Setting status codes is very easy.
`res.statusCode=<your_status_code>` for example `res.statusCode=200`

In the following code block example, status code is set according to need.
```
const server = http.createServer((req, res)=>{
    res.setHeader('Content-type', 'text/html');
    let path = './views/';
    switch(req.url){
        case '/':
            path += 'index.html';
            res.statusCode = 200;
            break;
        case '/about':
            path += 'about.html';
            res.statusCode = 200;
            break;
        default:
            path += '404.html';
            res.statusCode = 404;
            break;
    }
    fs.readFile(path, (err, data) => {
            res.end(data);
    })
})
```
Some more important points:
1. 100 range - Informative codes for browser
2. 200 range - Success codes
3. 300 range - redirection codes
4. 400 range - User side errors
5. 500 range - Server errors

Example:
* 200 - OK
* 301 - Resource moved
* 404 - Page not found
* 500 - Internal server error

##6. Redirects
Suppose my website has an established route '/about'. I wish someone who also visits to '/about-me' get redirected to '/about'. The below code does that:
* First set the statuscode to 301 `res.statusCode=301;`
* Then do `res.setHeader('Location', '/about');`
* Send the request `res.end()`
```
        case '/about':
            path += 'about.html';
            res.statusCode = 200;
            break;
        case '/about-me':
            res.statusCode = 301;
            res.setHeader('Location', '/about');
            res.end();
            break;
        default:
            path += '404.html';
            res.statusCode = 404;
            break;
```