Categories
Node.js Tips

Node.js Tips — Testing Events, Env Variables, and Editing Mongoose 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 Load an Image from a URL into a Buffer in Node.js

We can make a request for the image.

Then we can use the Buffer.from method to load it into a buffer.

For instance, we can write:

const response = await axios.get(url,  { responseType: 'arraybuffer' })
const buffer = Buffer.from(response.data, "utf-8")

We use the Axios HTTP client to make a GET request.

To do that, we pass in the URL for the image and set the responseType of the response to 'arraybuffer' .

Then we pass in response.data to the Buffer.from method with the 'utf-8' encoding.

This saves the data to the buffer.

Loading Environment Variables with dotenv

We can load environment variables with the dotenv library.

To do that, we write:

const path = require('path')
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })

We require the dotenv library.

Then we call the config method to set the path of the .env file.

We specified that we move one level up from the current directory to find the .env file.

Read Lines Synchronously from a Text File in Node.js

We can use the readFileSync method to read a text file synchronously.

For example,m we can write:

const fs = require('fs');
const lines = fs.readFileSync(filename, 'utf-8')
  .split('n')
  .filter(Boolean);

We call readFileSync to read the text file’s content.

Then we call split to split the string by the newline character.

Then we call filter with Boolean to remove any lines with empty strings.

This works because empty strings are falsy.

So Boolean will convert them to false.

Parse Filename from URL with Node.js

To get a file name from a URL, we can use the url and path modules.

For instance, we can write:

const url = require("url");
const path = require("path");
const parsed = url.parse("http://example.com:8080/test/foo.txt/?q=100");
console.log(path.basename(parsed.pathname));

We call url.parse to parse the URL into its parts.

Then we can use the basename to get the last part of the URL before the query string, which is 'foo.txt' .

Send Cookies with node-fetch

We can send cookies with node-fetch by setting the cookie header.

For instance, we can write:

fetch('/some/url', {
  headers: {
    accept: '*/*',
    cookie: 'accessToken=1234; userId=1234',
  },
  method: 'GET',
});

We use the fetch function from the library.

The cookie is set in the headers property of the 2nd argument.

The cookie property has the cookie.

Add Properties to an Object Returned from Mongoose

If we want to add properties to an object that’s retrieved from Mongoose, we can either use the lean method or we can call toObject on the returned document.

For instance, we can write:

Item.findById(id).lean().exec((err, doc) => {
  //...
});

Then we can add properties to doc since it’s a plain object.

Or we can write:

Item.findById(id).exec((err, doc) => {
  const obj = doc.toObject();
  //...
});

In the callback, we call doc.toObject() to return a plain object from the document.

Then we can manipulate obj as we wish.

How to Test Node.js Event Emitters with Sinon

We can test event emitters in Sinon by using its spies.

For instance, we can write:

const sinon = require('sinon');
const EventEmitter = require('events').EventEmitter;

describe('EventEmitter', function() {
  describe('#emit()', function() {
    it('should invoke the callback', () => {
      const spy = sinon.spy();
      const emitter = new EventEmitter();
      emitter.on('foo', spy);
      emitter.emit('foo');
      spy.called.should.equal.true;
    })

    it('should pass arguments to the callbacks', () => {
      const spy = sinon.spy();
      const emitter = new EventEmitter();
      emitter.on('foo', spy);
      emitter.emit('foo', 'bar', 'baz');
      sinon.assert.calledOnce(spy);
      sinon.assert.calledWith(spy, 'bar', 'baz');
    })
  })
})

We pass in the spy as the event handler function.

Then we can check if the spy is being called.

If it is, then the event is emitted.

Otherwise, it’s not.

We can check if arguments are called with emit by using calledWith to check them.

Conclusion

We cab load an image as an array buffer to save it to a Node buffer.

The dotenv library can be used to load environment variables in a Node app.

If we want to add properties to the document retrieve from Mongoose, we can use lean or call the toObject method.

We can test for even emitter events with spies.

Categories
Node.js Tips

Node.js Tips — Excel Files, Flash Messages, and Response Data

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.

Correctly Exporting async Functions in Node.js

We can export an async function like any other function.

For instance, we can write:

async function doSomething() {
  // ...
}

module.exports.doSomething = doSomething;

We export doSomething like we can with any other function.

ReadFile in Base64 Nodejs

We can read a file into a base64 string by using the readFileSync method.

For instance, we can write:

const fs = require('fs');
const str = fs.readFileSync('/path/to/file.jpg', { encoding: 'base64' });

We pass in the 2nd argument with an object.

It has the encoding property set to 'base64' so that we can parse the file into a base64 string.

It’s returned and assigned to str .

Find and Update Subdocument with Mongoose

We can find and update a subdocument with the findOneAndUpdate method.

For instance, we can write:

Person.findOneAndUpdate(
  { "_id": personId, "address._id": address._id },
  {
    "$set": {
      "address.$": address
    }
  },
  (err, doc) => {
    console.log(doc);
  }
);

We call the findOneAndUpdate method with a few arguments.

The first is the query to find the object to update.

We query both the parent document and the subdocument with it.

We query the person document by ID, and address with the address._id .

The 2nd argument is the $set method to set the value for the address.$ to set the address subdocument.

The $ is the positional operator variable.

It’s used to get the subdocument that matches the given position.

Then the callback has the results once the operation is done.

Skip Subsequent Mocha Tests from Spec if One Fails

Mocha has a bail operation to skip the remaining tests if one fails.

We can also use b for short.

Returning data from Axios API

To get data from an HTTP request made by Axios, we can return the response.data object in our then callback.

For instance, we can write:

axios.get(url)
  .then(response => {
     return response.data;
  })
  then(data => {
    res.json(data);
  })

We call res.json with the response data after the request is made successfully.

Read the Body of a Fetch Promise

We can get the body of a Fetch promise by using the json method to convert the response object to a JSON object.

For instance, we can write:

fetch('https://api.ipify.org?format=json')
  .then(response => response.json())
  .then‌​(data => console.log(data))

We called response.json() to get the JSON.

Parse XLSX with Node and Create JSON

To make parsing XLSX files easy in a Node app, we can use the xlsx package.

We can use it by writing:

const XLSX = require('xlsx');
const workbook = XLSX.readFile('spreadsheet.xlsx');
const [sheetName] = workbook.SheetNames;
const json = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName])

We use the xlsx package.

Then we can use the readFile to read the spreadsheet with the given path.

The workbook.SheetNames property get the sheet names from the XLSX file.

We get the first name with our example.

Then we call sheet_to_json to convert the sheet with the given name.

We get the sheet by using the workbook.Sheets object.

Check if a JSON is Empty in NodeJS

We can check if a JSON object is empty with the Object.keys method.

For example, we can write:

Object.keys(obj).length === 0;

where obj is the JSON object we want to check.

Send Flash Messages in Express

A flash message is a message that’s stored during a session.

We can use the connect-flash middleware to send a flash message to the template.

To install the package, we run:

npm install connect-flash

Then we can write:

const flash = require('connect-flash');
const app = express();

app.configure(function() {
  app.use(express.cookieParser(''));
  app.use(express.session({ cookie: { maxAge: 60000 }}));
  app.use(flash());
});

app.get('/flash', (req, res) => {
  req.flash('info', 'flash message');
  res.redirect('/');
});

app.get('/', (req, res) => {
  res.render('index', { messages: req.flash('info') });
});

We set the flash message with req.flash .

The first argument is the key of the message.

The 2nd argument is the message itself.

We can get the message by the key if we use req.flash with one argument as we did on the '/' route.

Conclusion

We can export async functions like any other function.

The connect-flash package lets us store messages that are available during the session.

The xlsx package lets us parse data from XLSX files.

Subdocuments can be updated with Mongoose.

We can get the response data with various HTTP clients.

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.