Categories
Node.js Tips

Node.js Tips — Build Errors, Tests, and Exit Codes

As with any kind of app, 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.

Fix NPM Error on Windows Looking for Tools Version

If we install native Node packages on Windows, we may run into errors that look something like:

MSBUILD : error MSB4132: The tools version "2.0" is unrecognized. Available tools versions are "4.0".

To fix this, we can run:

npm install --global --production windows-build-tools

in admin mode to install the build tools for Windows to compile those packages.

Use a Custom Express Server in Supertest

We have to export out Express server so that it can be tested with Supertest.

For instance, we can write:

app.js

//...
const app = express();
//...

module.exports = app;

Then in our test, we can write:

const request = require('supertest');
const app = require('./app');

describe('POST /', () => {
  it('should make request with foo', (done) => {
    request(app)
      .post('/')
      .send({
        'foo': 'bar'
      })
      .expect(200)
      .end((err, res) => {
        console.dir(err);
        console.dir(res);
        //...
        done();
      })
  })
})

We pass in the app which exported into the request function to make a request with our Express app.

Get Query String Params with Koa Router

To get a query string parameter with the Koa router, we can use the ctx.request.query property.

For instance, we can write:

import koaRouter from 'koa-router';

const router = koaRouter({
  prefix: '/foo'
});

router.get('/', async (ctx) => {
  console.log(ctx.request.query);
});

to get the parsed query parameters.

We can also use ctx.query for short:

import koaRouter from 'koa-router';

const router = koaRouter({
  prefix: '/foo'
});

router.get('/', async (ctx) => {
  console.log(ctx.query);
});

Accessing the Exit Code and stderr of a System Command

We can access the exit code and stderr of a system command by getting them from the error object.

For instance, if we’re using execSync to run our command, then we can write:

const childProcess = require('child_process');
const cmd = 'some command';

try {
  childProcess.execSync(cmd).toString();
} catch (error) {
  console.log(error.status);
  console.log(error.message);
  console.log(error.stderr);
  console.log(error.stdout);
}

We call execSync with a command.

Then we get the error with the catch block.

status has the exit code.

message has error messages.

stderr has the full error output.

stdout has the standard output.

If we use exec , we can get the error from the callback.

const childProcess = require('child_process');
const cmd = 'some command';

child_process.exec(cmd, (err, stdout, stderr) => {
  console.log(stdout)
  console.log(stderr)
  console.log(err)
}).on('exit', code => console.log(code))

We can get the stdout and stderr from the callback.

The exit code can be obtained by listening to the exit event.

It takes a callback with the exit code, which is the value of code .

err has the errors encountered.

Node.js server.address().address Returns :: in an Express App

To make server.address return an IP address, we’ve to specify the IP address specifically with listen .

For example, we can write:

const express = require('express');
const app = express();
const server = app.listen(8888, "127.0.0.1", () => {
  const { address, port } = server.address();
  console.log(`running at http://${host}:${port}`);
});

We pass in the IP address as the 2nd argument.

Then server.address will get the host , which has the IP address, and port , which has the port.

Unit Test an Event Being Emitted in Mocha

We can listen to events in our Mocha tests.

For instance, we can write:

it('should emit an event', function(done){
  this.timeout(1000);

  eventObj.on('event', () => {
    // run assertions...
    done();
  });
});

We call this.timeout to make sure that the test times out with an error if the event isn’t received in 1 second.

Then we can listen to the event event emitted by eventObj and run any assertions we want with it.

After that, we call done to move on to other pieces of code.

Conclusion

We can pass the IP address on listen to get the IP address the app is listening to with server.address() . Errors and exit code for shell commands can be retrieved with exec and execSync . We’ve to install windows-build-tools globally to fix any errors with build native packages. To test our Express app with Supertest, we’ve to import our Express app object and pass it to Supertest’s request function before we make our request.

Categories
Node.js Tips

Node.js Tips — Babel, Promises, Latest/Oldest MongoDB Records

As with any kind of app, 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.

Get the Latest and Oldest Record in Mongoose

We can get the latest document by using the sort method.

For instance, we can write:

MySchema.find().sort({ _id: -1 }).limit(1)

to get the latest document.

_id set to -1 means we sort the IDs in descending order.

To get the oldest document, we can write:

MySchema.find().sort({ _id: 1 }).limit(1)

_id set to 1 means we sort the IDs in ascending order.

limit limits the entries returned.

Add 1 Month from Now to Current Date in moment.js

We can add 1 month from now with monent.js with the add method.

For instance, we can write:

moment().add(1, 'months').calendar();

moment returns the current date and time.

We just call add with the quantity and the unit that we want to add to add what we want to the date.

Also, we can replace 'months' with 'days' and 'years' to add those quantities as well.

Convert Native Promise to a Bluebird

We can call Blurbird’s resolve method to convert a native promise to a Bluebird promise.

For example, we can write:

Promise.resolve(somePromise())

where somePromise is a function that returns a native ES6 promise.

Get “HTTP_REFERER” with NodeJS

If we use the http module to create our HTTP server, we can use the req.headers.referer to get the HTTP_REFERER header from the request.

For instance, we can write:

const http = require('http');
const server = http.createServer((req, res) => {
  console.log(req.headers.referer);
})

JavaScript Asynchronous Constructor

We can create static async methods in JavaScript classes, so we can use that to create methods that returns a promise with a resolved value we want.

For instance, we can write:

class Person{
  constructor(name){
    this.age = 5;
    this.name = name;
    return new Promise((resolve) => {
      resolve(this);
    });
  };
}

We have the Person constructor which returns a promise.

If we return something in the constructor , then it’ll be returned instead of returning the instance directly.

We returned a promise that resolves to the Person instance, so we can call then to get the resolved result.

Then we can call then on it by writing:

new Person('james')
  .then((instance) => {
    //...
  });

instance has the Person instance, and we can do what we like with it.

Using Babel Register with require(‘babel/register’)

To use Babel in our app without any transportation, we can use the babel/register package.

We add the package on top of our script, then we can use the features supported by the preset.

To use it, we run:

npm install @babel/core @babel/register --save-dev

to install @babel/core and @babel/register to add Babel Register.

Then to use it, we can write:

require("@babel/register");

const env = process.env.NODE_ENV || 'development';
const port = process.env.NODE_PORT || 8888;

const http = require('http');
const express = require('express');

const app = express();

app.set('port', port);
app.use(express.static(path.join(__dirname, 'public')));

app.get('*', (req, res) => {
  res.send('hello!');
});

http.createServer(app).listen(app.get('port'), () => {
  console.info('app started');
});

We require the babel-register package at the top of the script.

Then we run our Express apps with the latest features below it.

Now the Express app is transpiled on the fly.

Also, we can add babel-cli to our project instead of using Babel Register, which is faster since it doesn’t do on-the-fly transpilation.

To do that, we can run:

npm install --save-dev @babel/core @babel/node

to install the Babel packages.

Then we can run babel-node in our app:

npx babel-node app.js

Then we can write:

app.js

const env = process.env.NODE_ENV || 'development';
const port = process.env.NODE_PORT || 8888;

const http = require('http');
const express = require('express');

const app = express();
app.set('port', port);

app.use(express.static(path.join(__dirname, 'public')));

app.get('*', (req, res) => {
  res.send('hello!');
});

http.createServer(app).listen(app.get('port'), () => {
  console.info('app started');
});

and it’ll run properly since we’re using Babel to transpile the app.

Conclusion

We can get the oldest and latest records with Mongoose easily. Also, we can use Babel Register or Babel Node to run our app. We can return anything in our constructor including promises, so we can use that to create an async constructor. We can get the HTTP referer from the headers. Native promises can be converted to Bluebird promises.

Categories
Node.js Tips

Node.js Tips — Request URLs, Parsing Request Bodies, Upload

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.

Get Path from the Request

We can get the path from the request by using the request.url to get parse the request URL.

For instance, we can write:

const http = require("http");
const url = require("url");

const onRequest = (request, response) => {
  const pathname = url.parse(request.url).pathname;
  console.log(pathname);
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.write("hello");
  response.end();
}

http.createServer(onRequest).listen(8888);

All we have to do is to get the request.url property to get the URL.

Then we can parse it with the url module.

We can then get the pathname to get the relative path.

Convert Relative Path to Absolute

We can convert a relative path to an absolute path by using the path module’s resolve method.

For example, we can write:

const resolve = require('path').resolve
const absPath = resolve('../../foo/bar.txt');

We call resolve with a relative path to return the absolute path of the file.

Get the String Length in Bytes

We can get the string length in bytes by using the Buffer.byteLength method.

For instance, we can write;

const byteLength = Buffer.byteLength(string, 'utf8');

We pass in a string to Buffer.byteLength to get the string length in bytes.

Get Data Passed from a Form in Express

To get data passed in from a form in Express, we can use the body-parser package to do that.

Then to get the parsed results, we can get it from the req.body property.

We can write:

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));

app.post('/game', (req, res) => {
  res.render('game', { ...req.body });
});

We call app.post to create a POST route, which gets the request body via req.body because we called bodyParser.urlencoded to parse URL encoded payloads.

extended set to true lets the body-parser accept JSON like data within the form data including nested objects.

With this option, we don’t have to send key-value pairs as we do with traditional HTML form send.

Running Multiple Express Apps on the Same Port

We can use app.use to incorporate multiple Express apps and run them on the same port.

For instance, we can write:

app
  .use('/app1', require('./app1').app)
  .use('/app2', require('./app2').app)
  .listen(8080);

We require app1 and app2 to use the routes from both of them in one app.

Then we call listen to listen to requests in port 8080.

Change Working Directory with NodeJs child_process

We can change the working directory with the cwd option.

For example, we can write:

const exec = require('child_process').exec;

exec('pwd', {
  cwd: '/foo/bar/baz'
}, (error, stdout, stderr) => {
  // work with result
});

We call exec with an object with the cwd property to set the current working directory.

Then we get the result in the callback.

Upload a Binary File to S3 using AWS SDK for Node.js

We can upload a binary file to S3 using the Node.js AWS SDK by using the AWS package.

For instance, we can write:

const AWS = require('aws-sdk');
const fs = require('fs');

AWS.config.update({ accessKeyId: 'key', secretAccessKey: 'secret' });

const fileStream = fs.createReadStream('zipped.tgz');

fileStream.on('error', (err) => {
  if (err) {
    console.log(err);
  }
});

fileStream.on('open', () => {
  const s3 = new AWS.S3();
  s3.putObject({
    Bucket: 'bucket',
    Key: 'zipped.tgz',
    Body: fileStream
  }, (err) => {
    if (err) {
     throw err;
    }
  });
});

We use the aws-sdk package.

First, we authenticate with AWS.config.update .

Then we create a read stream from the file with createReadStream .

Then we listen to the file being opened with by attaching a listener to the 'open' event.

We then create an AWS.S3 instance.

And we call putObject to upload the file.

Bucket is the bucket name.

Key is the path to the file.

Body is the read stream of the file we created.

We also listen to the error event in case any errors are encountered.

Conclusion

We can get the path of the request with the request.url property if we’re using the http module to listen to requests.

To convert relative to absolute paths, we can use the path module’s resolve method.

We can upload files with S3 by creating a read stream and call putObject .

We can set the current working directory with exec .

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.