Modules and Networking

Modules and Networking

Modules

Exporting

So we can treat the attribute exports as an object and pass it whatever values we would like to show to other app that import our module:

module.exports = { value1: "value1", value2: "value2" };

Where value1 is the key of the attribute and 'value1' is its value, e.g.:

const name = "John";
const surname = "Tuckey";

module.exports = { Name: name, Surname: surname };

Also, if we only export one object it is sufficient to type:

const name = "John";

module.exports = name;

Another way to export is to define explicitly the name of the attributes to export:

module.exports.items = ["item1", "item2"];

const person = {
  name: "bob",
};
module.exports.singlePerson = person;

Importing

Now, a module can be imported with the keyword require as follows:

const externalModule = require('./module')
console.log(externalModule)

{ Name: 'John', Surname: 'Tukey' }

Another type of syntax could be unrolling the attributes of the export object:

const { Name, Surname } = require("./module");

Built-in Modules

Some built-in modules are:

  • OS
  • PATH
  • FS (Filesystem)
  • HTTP

Even though there are several more built-in modules.

OS

To import the OS built-in module we do:

const os = require("os");

And we call it by:

console.log(`The system uptime is ${os.uptime()} seconds`);

FS

We can also interact with the file system via the FS module. There are two ways to do so:

  1. Asynchronously, which is non-blocking
  2. Synchronously, that is blocking

Synchronous

To exemply both setups, we first de-structure the read and write synchronous methods from the FS module, and then we read and write files.

const { readFileSync, writeFileSync } = require("fs");

// Read file with a given path and the corresponding encoding
const first = readFileSync("./file.txt", "utf8");
const second = readFileSync("./file2.txt", "utf8");

// Write to a file given a path, the content is overwritten
writeFileSync("./writeFile", "This content will be written");

// Write to a file given a path, the content is appended
writeFileSync("./writeFile", "This content will be written", { flag: "a" });

Asynchronous

Now, in order to access the file system asynchronously, we need a callback, and so we do:

const { readFileSync, writeFileSync } = require("fs");

readFile("./file", "utf8", (error, result) => {
  if (error) {
    console.log(error);
    return;
  } else {
    console.log(result);
    const first = result;
    // Here we can add another read call
  }
});

writeFile("./file", "This is the content", (error, result) => {
  if (error) {
    console.log(error);
    return;
  } else {
    console.log(result);
  }
});

Where we specify a callback function with the ES6 syntax. Its first parameter is the error parameter and the second is the result of the operation.

The problem with synchronous calls is that they can be very time consuming and they halt the execution, which can be critical when working on time sensitive tasks or when several user call upon these type of functions at a time.

HTTP

To show the bare basics, we will set up a server:

const http = require("http");

const server = http.createServer((request, response) => {
  response.write("This is the index!");
  response.end();
});

// Define the port
server.listen(5000);

That can be accessed on localhost:5000. Next, we can code something a little more complex, where the content handed as a response depends on the request:

const http = require("http");

const server = http.createServer((request, response) => {
  if (request.url === "/") {
    response.end("This is the index");
  } else if (request.url === "/about") {
    response.end("This is the about");
  } else {
    response.end("404");
  }
});

// Define the port
server.listen(5000);

NPM

Installing packages

You can install a package locally within your project as a local dependency:

$ nmp i <packageName>

Or you can install the package globally, so it can be accessed from any project:

$ npm install -g <packageName>

If you want to specify a version for the package:

$ npm install <packageName>@1.0.0

Package.json

This file stores important information about the project and the packages, it can be conceived as a manifest file. There are two ways to create it:

  • Manually: create package.json in the root folder of the project and define the properties of the project/packages.
  • Using npm following the guide (add -y to skip the questions of the guide):
$ npm init

When the project is initialized, the package.json file is as follows:


{
  "name": "08_project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Where all those properties are set up during the guide of npm init or set as default with the flag -y.

After installing a dependency

$ npm i lodash

The following property is added:

  "dependencies": {
    "lodash": "^4.17.21"
  }

And npm creates the folder node_modules, if it does not already exist, which stores the dependencies code. Also, in case of wanting to install dependencies needed only during the development process:

$ npm i <package> -D
$ npm i <package> --save-dev

And so, the property devDependencies is created in pakage.json.

Scripts

The object scripts, which is a property of package.json, can contain the definition of different actions, for example:

"scripts": {
  "start": "node app.js"
}

So when running npm start our app.js will be executed. For some commands you will need to specify run and the command name as follows:

$ npm run dev
Nodemon

This is a package that lets you hot reload your project without having to execute your app constantly. For that, after installing nodemon as a local or global dependency, we specify on package.json:

"scripts": {
  "dev": "nodemon app.js"
}

If we want to run it:

$ npm run dev

Package-lock.json

This file stores the dependencies version of the packages installed as dependencies, as to avoid installing newer version that can be the cause of bugs. Because within the package.json only our project’s dependencies’ versions are specified.

Uninstalling packages

In order to uninstall the package we have a command, that follows the syntax:

$ npm uninstall <package>

We can also remove it from the dependencies object within package.json. So when you remove package-lock.json and the node_modules folder if you run

$ npm install

The package that was removed will not be installed.

Git

When using git or other version control tool, it is desirable to create a .gitignore and to specify to avoid the node_modules folder, since its size can get big very easily.

So, by just pushing the source code, including package.json, if we want to install all of the project’s dependencies’ again, on the root folder we run:

$ npm install

HTTP

HTTP Messages

  • Request Message: what the user sends
  • Response Message: what the server sends

HTTP Response Request

The messages have the following parts:

  • Info about the request: Request URL, Request Method (GET is the default method), Status Code, etc.
    • Headers: meta information about the request/response, (e.g. “Content type: application/json” tells the browser that the body is json)
    • Body: which is the request payload, or the content of the response.