Categories
Node.js Tips

Node.js Tips — Closing Sockets, Writing Responses, and Parsing HTML

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Log the Output of the npm install Command

To log the output of the npm install command, we can route stderr to stdout.

For example, we can write:

npm install 2>&1 | tee log.txt

2>&1 routes stderr to stdout.

tee reads the standard output and writes it to both standard out and one or more files.

We write to log.txt as specified in the command.

Parsing of Pages with Node.js and XPath

To parse HTML with XPaths, we parse the HTML with parse5 .

It doesn’t parse it into a DOM object but it’s fast and W3C compliant.

We can serialize it to XHTML with xmlserializer ,

Then can use the xmldom to get the DOM.

And we use the xpath library to make our XPath queries.

For instance, we can write:

const fs = require('mz/fs');
const xpath = require('xpath');
const parse5 = require('parse5');
const xmlSer = require('xmlserializer');
const DOMParser = require('xmldom').DOMParser;

(async () => {
  const html = await fs.readFile('./foo.html');
  const document = parse5.parse(html.toString());
  const xhtml = xmlSer.serializeToString(document);
  const doc = new DOMParser().parseFromString(xhtml);
  const select = xpath.useNamespaces({
    x: "http://www.w3.org/1999/xhtml"
  });
  const nodes = select("/html/body/header/div/div[1]/a[2]", doc);
  console.log(nodes);
})();

We import the fs library to read the foo.htmk file.

Then we parse the document with parse5 to a document object.

Then we transform the HTML to XHTML with the xmlserializer ‘s serializeToString method.

Then we create a new DOMParser instance by parsing the transformed string.

Next, we create a select object with the userNamespace method to let us select DOM elements by XPath.

Then we call select to select elements by XPath.

doc is the DOM object returned from DOMParser .

nodes has the returned nodes.

Also, we can use the libxmljs library to get nodes by XPath.

For instance, we can write:

const libxmljs = require("libxmljs");
const xml =  `
<?xml version="1.0" encoding="UTF-8"?>'
<root>
  <child foo="bar">
    <grandchild baz="foo">some content</grandchild>
  </child>
  <sibling>with content!</sibling>
</root>`;

const xmlDoc = libxmljs.parseXml(xml);
const gchild = xmlDoc.get('//grandchild');
console.log(gchild.text())

We use the libxmljs by passing in an XML string to the parsXml method.

Then we cal pass in an XPath string to the get method to get the item.

And the text will have the text for the selected node, which is some content .

Write After End Error in Node.js Webserver

If we’re using the net module to create a web server, then when we write a message, we’ve to pass in a callback as the 2nd argument to call end on it.

For example, we can write:

const netSocket = require('net').Socket();
netSocket.connect(9090);
netSocket.write('hello', err => netSocket.end());

We call netSocket.end() in the callback of the 2nd argument to close the socket after the message is written.

We’ve to do that because write is async. There’s no guarantee that write is done before end is we don’t pass it into the callback.

So something like:

const netSocket = require('net').Socket();
netSocket.connect(9090);
netSocket.write('hello');
netSocket.end();

will get us the ‘write after end’ error.

Difference Between response.setHeader and response.writeHead

response.setHeader lets us set a single header for implicit headers.

If the header already exists, then its value will be replaced.

We can use an array of strings to send multiple headers with the same name.

response.writeHead sends a response header to the request.

One method takes an object with the status code and the response headers.

To use setHeader , we can write:

const body = "hello world";
response.setHeader("Content-Length", body.length);
response.setHeader("Content-Type", "text/plain");
response.setHeader("Set-Cookie", "type=foo");
response.status(200);

We set one response header with one setHeader call.

The status code is set separately with response.status .

On the other hand, with writeHead , we set the response status codes and headers all at once.

For example, we can write:

const body = "hello world";
response.writeHead(200, {
  "Content-Length": body.length,
  "Content-Type": "text/plain",
  "Set-Cookie": "type=foo"
});

We set the response status code in the first argument and all the response headers in the object in the 2nd argument.

Conclusion

response.setHeader and response.writeHead are different.

We can parse HTML or XML and use XPath to query the nodes.

To end a socket created with net , we’ve to call it in the callback that’s passed into the 2nd argument of write .

We can log npm install errors to a file by redirecting the output.

Categories
Node.js Tips

Node.js Tips — Test Apps, Retries, and Logging Objects

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

How to Check if a Path is Absolute or Relative

We can check if a path is absolute with the path module’s isAbsolute method.

For instance, we can write:

const path = require('path');
//...

if (path.isAbsolute(somePath)) {
  //...
}

We pass in somePath to the method to check it.

It returns true if it’s an absolute path and false otherwise.

Log JavaScript Objects and Arrays in Winston

We can pretty-print objects with Winston by setting the prettyPrint property.

For instance, we can write:

const level = 'debug';

const logger = new winston.Logger({
  transports: [
    new winston.transports.Console({
      name: 'debug-console',
      level,
      prettyPrint(object) {
        return JSON.stringify(object);
      },
      handleExceptions: true,
      json: false,
      colorize: true
    })
  ],
  exitOnError: false
});

We set the prettyPrint to a function that returns the stringified object to print the object content.

Also, we can log JSON with the %j tag.

For instance, we can write:

logger.log("info", "an object %j", obj);

where obj is an object.

Detecting Test Failures from Within afterEach Hooks in Mocha

We can check the this.currentTest.state property in the afterEach hook to check the status of the test that just runs.

For instance, we can write:

afterEach(function() {
  if (this.currentTest.state === 'failed') {
    // ...
  }
});

If the state is 'failed' , then it failed.

Set a Cookie Value in Node.js

We can set a cookie in the response with the res.cookie method.

For example, we can write:

const cookieParser = require('cookie-parser');
//...

app.use(cookieParser());

app.get('/foo', (req, res) => {
  res.cookie('foo', 'baz');
});

The first argument is the key and the 2nd is the value.

We also include the cookieParser .

Then we can pass in a secret as the argument to sign the cookie.

For instance, we can write:

const cookieParser = require('cookie-parser');
//...

app.use(cookieParser('secret'));

app.get('/foo', (req, res) => {
  res.cookie('foo', 'baz');
});

We pass in a secret key string to sign a cookie.

How to Unit Test Express Router Routes

We can unit test Express router routes by exporting our Express app.

Then we can use Supertest by passing in the exported app to the request function of Supertest.

For instance, if we have the following Express app:

app.js

const app = express();
// ...
const router = require('../app/router')(app);

module.exports = app;

Then we can write our test by writing:

const chai = require('chai');
const should = chai.should();
const sinon = require('sinon');
const request = require('supertest');
const app = require('app');

describe('person route', () => {
  request(app)
    .get('/api/persons')
    .expect('Content-Type', /json/)
    .expect('Content-Length', '4')
    .expect(200, "ok")
    .end((err, res) => {
      if (err) throw err;
    });
});

We pass in the app imported from app.js .

Then we make a GET request by call get .

We use expect to check the response headers and status code.

Then we call end to finish the request and get the response with res in the callback.

Do Repeated Requests Until one Succeeds without Blocking

To make requests repeatedly until it’s successful, we can use the async.retry method.

For instance, we can write:

const async = require('async');
const axios = require('axios');

const makeRequest = async (uri, callback) => {
  try {
    const result = await axios.get(uri);
    callback(null, result);
  } catch (err) {
    callback(err);
  }
};

const uri = 'http://www.test.com/api';

async.retry({
    times: 5,
    interval: 200
  },
  (callback) => {
    return makeRequest(uri, callback)
  },
  (err, result) => {
    if (err) {
      throw err;
    }
  });

We created the makeRequest function that calls the callback with it’s done.

Then we pass that into the async.retry method with the options.

times is the number of times to try.

interval has the retry interval in milliseconds.

The 2nd argument is the async function to call.

The last argument is the callback when the request succeeds or the retries are exhausted.

result has the result. err has the error.

Conclusion

We can use the async.retry method to retry async functions.

We can pretty-print JavaScript objects we log with Winston.

To test an Express app with Supertest, we’ve to export the Express app and use it with Supertest.

Express can set cookies in responses.

Categories
Node.js Tips

Node.js Tips — Send Emails, Hashing, Promises, and Express Project Structure

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

async/await Implicitly Returns Promise

Async functions implicitly return promises.

For instance, if we have:

`const` increment = `async (num) => {
  return num + 1;
}`

Then that returns a promise with num increased by 1.

This means that we can use it by writing:

increment(2)
  .then(num => console.log(num))

If we pass in 2 to increment then num in the callback should be 3.

Get the SHA1 Hash of a String in Node.js

We can get the SHA1 hash of a string by using the crypto module.

For instance, we can write:

const crypto = require('crypto');
const sha = crypto.createHash('sha1');
sha.update('foo');
sha.digest('hex');

We call update with the text that we want to hash.

And call digest to return the hashed hex string.

However, since SHA1 isn’t very secure, we should create SHA256 hashes instead:

const crypto = require('crypto');
crypto.createHash('sha256').update('foo').digest('hex');

We call createHash with 'sha256' to create the SHA256 hash.

The rest is the same.

Make Axios Send Cookies in its Requests Automatically

We can make Axios send cookies in its requests with the withCredentials option.

For instance, we can write:

axios.get('/api/url', { withCredentials: true });

We just set it to true so that we can send the cookie.

Nodemailer with Gmail

We can send emails with Nodemailer with a Gmail SMTP server.

For instance, we can write:

const nodemailer = require('nodemailer');
const smtpTransport = require('nodemailer-smtp-transport');

const transporter = nodemailer.createTransport(smtpTransport({
  service: 'gmail',
  host: 'smtp.gmail.com',
  auth: {
    user: 'email@gmail.com',
    pass: 'password'
  }
}));

const mailOptions = {
  from: 'email@gmail.com',
  to: 'friend@example.com',
  subject: 'Hello Email',
  text: 'hello friend'
};

transporter.sendMail(mailOptions, (error, info) => {
  if (error) {
    console.log(error);
  }
  else {
    console.log(info.response);
  }
});

We call the createTransport method to create a transporter object to let us send emails.

We pass in the SMTP server address, set the server to 'gmail' , and pass in the user name and address of our Gmail account.

Then we can set out mail options by setting the from and to emails, subject, and text , which is the content.

Finally, we call sendMail on transporter with the mailOptions to send the email.

The callback is called when it’s done.

error has the error and info has the result of sending the email.

Swap Key with Value JSON

We can swap the key with the value of an object.

To do that, we can use the Object.keys and the for-of loop.

For instance, we can write:

const result = {};
for (const key of `Object.keys(obj)`){
   result[`obj`[key]] = key;
}

We get the keys with Object.keys and then put the values of obj as the key of result and put the key as their values.

Structure an Express Application

To structure an Express app, we can put our production code in the app folder in the root level.

Then inside it, we have the controllers folder for the controllers.

models folder can have the models.

views foder have the views.

test folder is in the root and have the tests.

Inside it, we have the models and views folders for the tests of each kind of code.

Node.js ES6 Classes with require

We can export the class that we want to require by exporting it:

animal.js

class Animal {
  //...
}
module.exports = Animal;

Then we can write:

app.js

const Animal = require('./Animal');
const animal = new Anima();

We require the animal module and use the class.

Placement of catch Before or After then in a Promise Chain

If we have a chain of promises, then we can place the catch method anywhere we want to catch rejected promises.

However, if we place them earlier, then if the promises that come after it are rejected, then it the error won’t be caught by catch .

However, if we put catch earlier, then the later promises can continue until one of the ones that come later are rejected.

Conclusion

We can place the catch method anywhere we want, but they may catch different errors depending on location.

Axios can send cookies with the withCredentials option.

We can swap keys and values of an object by getting the keys and values and swap them.

Nodemailer can be used to send emails.

Categories
Node.js Tips

Node.js Tips — HTTP Proxies, Mongoose Schemas, Read Files, and More

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Create a Simple HTTP Proxy in Node.js

To create a simple HTTP proxy with Node.js, we can use the node-http-proxy library.

We can install it by running:

npm install http-proxy --save

Then we can write:

const http = require('http');
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer({});

http.createServer((req, res) => {
  proxy.web(req, res, { target: 'http://www.example.com' });
}).listen(3000);

We call createProxyServer to create the proxy server.

Then we call proxy.web to redirect our request to http://example.com .

fs.createReadStream vs fs.readFile in Node.js

We should use fs.createReadStream to read a file one chunk at a time.

This means that we can read big files without loading all of the content into memory.

fs.readFile is good for reading the entire file. This means it’s good for reading small files.

Read stream can accept data in a way that doesn’t overwhelm the host system.

Get the Domain Originating the Request in Express.js

We can get the domain of the originating request with Express.

All we have to do is to use req.get('host') to get the HOST header.

This works for a non-cross-origin request.

For a cross-origin request, we can use req.get('origin') instead.

Also, we can use req.headers.host and req.headers.origin to do the same thing.

If we want to get a client’s IP address, we can use req.socket.remoteAddress .

Create Mongoose Schema with an Array of Object IDs

To create a Mongoose schema with an array of object IDs, we can just pass in a constructor or schema to an array.

For instance, we can write:

const userSchema = mongoose.Schema({
  lists: [listSchema],
  friends: [{ type : ObjectId, ref: 'User' }]
});

exports.User = mongoose.model('User', userSchema);

We pass in listSchema to use an existing schema for a schema with an array.

listSchema is an existing Mongoose schema.

We can also pass in an object as we did with friends .

We make friends reference itself.

Listen to All Emitted Events in Node.js

To listen to all emitted events, we can use a wildcard to do it.

We can do that with the eventemitter2 package.

It supports namespacing and wildcards.

For instance, we can write:

const EventEmitter2 = require('eventemitter2');
const emitter = new EventEmitter2({
  wildcard: false,
  delimiter: '.',
  newListener: false,
  removeListener: false,
  maxListeners: 10,
  verboseMemoryLeak: false,
  ignoreErrors: false
});

emitter.on('bar.*', (val) => {
  console.log(this.event, valu);
});

We listen to all events with names starting with bar.

Also, we can listen to multiple events and events with identifiers denoted with symbols.

Accessing Express.js Local Variables in Client-Side JavaScript

We can access Express local variables in client-side JavaScript.

All we have to do is to pass in an object as the 2nd argument of res.render .

Then we can access the variable by the key names.

For instance, we can write:

res.render('index', {
  title: 'page title',
  urls: JSON.stringify(urls),
});

Then we can access them by writing:

const urls = !{urls};

in our Jad template

We’ve to stringify urls since the variables are added with string interpolation.

How to Check if Headers have Already Sent with Express

We can check if headers are already sent with the res.headerSent property.

For instance, we can write:

if (res.headersSent) {
  //...
}

Convert Timestamp to Human Date

We can convert a timestamp to a human date by using the Date constructor.

For example, we can write:

const date = new Date(1591399037536);

Then we can call toDateString , toTimeString , or toLocaleDateString to format the string the way we like.

Measuring Timing of Code in a Node App

To measure the timing of Node apps, we can use the performance.now() method to do that.

For example, we can write:

const {
  performance
} = require('perf_hooks');

console.log(performance.now());

We just import the performance object from perf_hooks and then call the now method on it.

Conclusion

We can use the performance.now() method to measure performance.

To create an HTTP proxy, we can use a 3rd party package to do it.

Mongoose schemas can have arrays in it.

We can get the request’s hostname from the headers in Express.

Read streams are good for reading big files, readFile is good for reading small files.

Categories
Node.js Tips

Node.js Tips — Start Scripts, Object IDs, and Logging

As with many types of apps, there are difficult issues to solve when we write Node apps. In this article, we’ll look at some solutions to common problems when writing Node apps.

npm start vs node app.js

npm start can be run when we put a start script in the package.json .

In package.json , we’ve to add a script like:

{
  ...
  `"scripts": {
    "start": "node index.js"
  }
  ...
}`

Then we can run npm start , which runs node index.js .

npm start can run any script.

On the other hand, node app.js just runs app.js with node .

It’s always the same.

Convert a String to ObjectId in Node.js MongoDB Native Driver

We can convert a string to an object ID with the Node MongoDB driver by using the ObjectId function from the mongodb package.

For instance, we can write:

const {ObjectId} = require('mongodb');

const updateStuff = (id, doc) => {
  if (!ObjectId.isValid(s)) {
    return Promise.reject(new Error('invalid id'));
  }
  return collection.findOneAndUpdate(
    { _id: ObjectId(id) },
    { $set: doc },
    { returnOriginal: false }
  );
};

We check if the string is a valid object ID with the ObjectId.isValid method. If it is, then we call findOneAndUpdate to do the update. We’ve to convert the id string to an object ID with the ObjectId function.

Create a Sleep or Delay Function in Node.js that is Blocking

If we want a synchronous sleep or delay function in Node, we can create a loop that runs until a given the time span has elapsed.

For instance, we can write:

const sleep = (time) => {
  const stop = new Date().getTime();
  while(new Date().getTime() < stop + time) {

  }
}

We just create a while loop with an empty body that runs until the timestamp is stop + time .

This is a synchronous sleep function that blocks the rest of the app from running. Therefore, we probably shouldn’t use it in most apps.

Global Modules

We can require a module and set it to a global variable.

For instance, we can write:

global.util = require('util');

We can set the util module as a global variable, but we probably shouldn’t do that since it doesn’t bring any advantages over importing modules. And we don’t know what’s in the global object if we do that a lot.

How to Generate Timestamp UNIX epoch format Node.js

To generate timestamp as a UNIX epoch, we can use the Date constructor.

For instance, we can write:

const timestamp = Math.floor(new Date() / 1000);

new Date() returns the UNIX epoch in milliseconds.

We can divide it by 1000 to get the epoch in seconds.

And we use Math.floor to round it down to the nearest integer.

Asynchronous Module Loading with Node.js

We can make require asynchronous by creating our own module that can load asynchronously.

For instance, we can write:

bar.js

const fs = require('fs');
module.exports = (callback) => {
  fs.readFile('/foo/bar', (err, data) => {
    callback(err, data);
  });
};

We call readFile to read the content of /foo/bar and calls the callback which has the data read from the file.

We call callback inside it so that we can use it outside of the readFile callback.

Then we can use bar.js by writing:

require('./bar')((err, bar) => {
  // ...
});

We require bar.js with require .

Then we call the required function with our own callback to get the data from bar.js via the bar parameter.

Difference Between console.log and sys.puts in Node.js

sys.puts can’t print the content of objects. It just prints the string passed into it in the logs. It’s also deprecated so it shouldn’t be used. console.log can print the content of arrays and objects. It’s not deprecated so it’s safe to use in our apps.

Conclusion

npm start runs the script named start from package.json . We can check if a string is a valid object ID before converting it to such. sys.puts shouldn’t be used since the sys module is deprecated. We can generate a timestamp with the Date constructor. To read modules asynchronously, we can use readFile to read the content. We shouldn’t use synchronous log functions even if we can write one.