Categories
Node.js Tips

Node.js Tips — Ending Tasks, Express Responses, and Streams

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.

Stop All Instances of Node.js Server

In Windows, we can stop the Node server by running the taskkill command:

taskkill /im node.exe

We can also add the /f flag to force termination of all Node tasks:

taskkill /f /im node.exe

We can also find the process by the port by using netstat :

netstat -ano | find "LISTENING" | find "8888"

Then we can kill a task by the process ID with the /pid flag:

taskkill /pid 12345

Where 12345 is the process ID from netstat .

We can also use /f to force the task to end.

On Linux, we can write:

killall node

to end all Node tasks.

We can find the task with the given port by running:

netstat -nlp | grep :1234

Then we will find the process ID of the task running on port 1234.

Then we can kill the task with the process ID:

kill 2345

where 2345 is the task ID.

We can also use the -9 flag to force the termination of the task:

kill -9 2345

Fix ‘Origin is not allowed by Access-Control-Allow-Origin’ Error

To fix the ‘origin is not allowed’ error, we can add the Access-Control-Allow-Origin response header.

For instance, if we’re using the http module to create the server, we can write:

var http = require('http');

http.createServer((request, response) => {
  response.writeHead(200, {
    'Content-Type': 'text/plain',
    'Access-Control-Allow-Origin' : '*',
    'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE'
  });
  response.end('Hello Worldn');
}).listen(3000);

We call writeHead to write the response headers.

We have:

'Access-Control-Allow-Origin' : '*'

to allow requests from all origins.

And:

'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE'

allows all request methods to be invoked.

If we’re using Express, we can create a middleware:

const cors = (req, res, next) => {
  res.header('Access-Control-Allow-Origin', "*");
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
}

Then we can use it by writing:

app.use(cors);

to use the middleware.

It sets the same response headers and calls next to call the next middleware.

Create Streams from a String in Node.Js

We can create a stream with the stream module.

For instance, we can write:

const { Readable } = require('stream');

async function * generate() {
  yield 'hello';
  yield 'world';
}

const readable = Readable.from(generate());

readable.on('data', (chunk) => {
  console.log(chunk);
});

We import the stream module.

Then we create a generator with the data that we want to send to the stream.

Then we use the Readable.from method to create the read stream.

Finally, we listen to the data event with the on method.

chunk has the data piped to the stream.

Access the Request Body When POSTing Using Express

We can access the request body with Express using the body-parser package.

For instance, we can write:

const bodyParser = require('body-parser');
app.use(bodyParser);

Then we can access the request body with req.body .

So we can write:

app.post('/', (req, res) => {
  console.dir(req.body);
  res.send("hello");
});

app.listen(3000);

to get the request body.

Together, we write:

const bodyParser = require('body-parser');
app.use(bodyParser);

app.post('/', (req, res) => {
  console.dir(req.body);
  res.send("hello");
});

app.listen(3000);

Fix ‘TypeError: Router.use() requires middleware function but got a Object’ Error

We use the express.Router method to create a router object where we can add routes.

Then we can export it or and then use it or use it directly.

For instance, we can write:

const tagsRouter = express.Router();

`tagsRouter`.get('/tags', (req, res) => {
  res.json(tags.get());
});

app.use('/tags', `tagsRouter`);

Or we can write:

tags.route.js

const tagsRouter = express.Router();

`tagsRouter`.get('/tags', (req, res) => {
  res.json(tags.get());
});

module.exports = tagsRouter;

app.js

const tagsRouter = require('./`tags.route`');
app.use('/tags', `tagsRouter`);

With the router object, we can group routes.

Conclusion

We can use Express router to group routes.

Also, we can use body-parser to parse the request body.

We can end tasks in various ways.

Read streams can be created easily.

To allow cross-origin communication, we can add some headers to the response.

Categories
Node.js Tips

Node.js Tips — Router, Shutdown, File Name of Uploads, and etag

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.

Simple Ways to Gracefully Shutdown Express Apps

To make gracefully shut down Express apps easier, we can use the @moebius/http-graceful-shutdown module to make shutting down connections much easier.

To install it, we run:

npm i -S @moebius/http-graceful-shutdown

Then we can write:”

const express = require('express');
const GracefulShutdownManager = require('@moebius/http-graceful-shutdown').GracefulShutdownManager;

const app = express();

const server = app.listen(8080);

const shutdownManager = new GracefulShutdownManager(server);

process.on('SIGTERM', () => {
  shutdownManager.terminate(() => {
    console.log('Server is terminated');
  });
});

We just use the package’s GracefulShutdownManager constructor with our Express server.

Then we can watch for the SIGTERM signal and call the terminate method on it.

The callback in terminate will be called when termination is done.

‘Error: Most middleware (like json) is no longer bundled with Express and must be installed separately.’

With Express 4, we’ve to install most of the packages that used to be included individually.

We’ve to install packages like the body-parser and template engines.

For instance, to install body-parser, we run:

npm i body-parser

Then we can use it by writing:

const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const ejs = require('ejs');

const app = express();

app.use(bodyParser.urlencoded({
    extended: true
}));

app.use(bodyParser.json());

Store a File with File Extension with Multer

To store a file with the file extension with Multer, we can append the extension to the file name.

For instance, we can write:

const multer = require('multer');

const storage = multer.diskStorage({
  destination(req, file, cb) {
    cb(null, 'uploads/')
  },
  filename(req, file, cb) {
    cb(null, `${Date.now()}.png`)
  }
})

const upload = multer({ storage });

We call the multer.diskStorage method with an object with a few methods.

The destination method specifies the folder to upload a file to.

In the filename method, we call the cb callback with the name of the file and the extension.

We can also get the extension from the MIME type in the filename method.

For instance, we can write:

const multer = require('multer');
import * as mime from 'mime-types';

const storage = multer.diskStorage({
  destination(req, file, cb) {
    cb(null, 'uploads/')
  },
  filename(req, file, cb) {
    const ext = mime.extension(file.mimetype);
    cb(null, `${Date.now()}.${ext}`);
  }
})

const upload = multer({ storage });

We use the mime-types package to help us get the MIME type of the uploaded file, which we’ll use for the extension.

mime.extension lets us get the extension from the MIME type.

file is the file object. file.mimetype is the MIME-type.

Then we interpolate the extension into the file name string in the callback.

Set Default Path (Route Prefix) in Express

We can use the Express’s Router constructor to create a router object.

This is where we can add a route prefix to a route.

For instance, we can write:

const router = express.Router();
router.use('/posts', post);

app.use('/api/v1', router);

First, we create the router by calling express.Router() .

Then we call router.use to create a route with the path posts .

Then we call app.use to pass the router into it as the 2nd argument.

We have the /api/v1 prefix as specified as the first argument of app.use .

Also, we can chain them together by writing:

app.route('/post')
  .get((req, res) => {
    res.send('get post')
  })
  .post((req, res) => {
    res.send('add post')
  })
  .put((req, res) => {
    res.send('update post')
  });

We have the post path used by a GET, POST, and PUT route.

Disable etag Header in Express

We can disable etag header with Express by call app.set .

For instance, we can write:

app.set('etag', false);

to turn off the etag header.

We can also write:

app.disable('etag')

to do the same thing.

Conclusion

We can shut down an Express server gracefully with a package.

Also, we’ve to install most middleware that used to be included with Express ourselves.

We can get the extension from an uploaded file and tack it onto the uploaded file’s file name.

Express’s router can be chained.

The etag header can be disabled.

Categories
Node.js Tips

Node.js Tips — CORS, Excel Files, and CSVs

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.

Reading Excel File Using Node.js

There are a few packages to let us read Excel files in a Node app.

One package we can use is the node-xlsx package.

To use it, we write:

const xlsx = require('node-xlsx');
const path = require('path');
const obj = xlsx.parse(path.join(__dirname, '/myFile.xlsx'));

We can pass in a path to parse the Excel file from the path.

Also, we can write:

const xlsx = require('node-xlsx');
const path = require('path');
const obj = xlsx.parse(fs.readFileSync(path.join(__dirname, '/myFile.xlsx'));

to parse a buffer, which readFileSync returns.

ExcelJS is another package that we can use to parse workbooks.

For instance, we can write:

const ExcelJS = require('exceljs');
const path = require('path');
const workbook = new Excel.Workbook();
const filename = path.join(__dirname, '/myFile.xlsx');
workbook.xlsx.readFile(filename);
  .then(() => {
    // use workbook
  });

to read from a workbook.

Also, we can write:

const workbook = new Excel.Workbook();
stream.pipe(workbook.xlsx.createInputStream());

to read from a stream.

Pass Variables to JavaScript in Express

We can pass variables to Express templates by passing in a 2nd argument to res.render .

For instance, we can write:

app.get('/foo.js', (req, res) => {
  res.set('Content-Type', 'application/javascript');
  res.render('foo', { foo: { bar: 'baz' } });
});

Then in the foo template, we can write:

<script>
  const foo = <%- JSON.stringify(foo) %>;
</script>

We’re using an EJS template, so we interpolate variables with <%- %> .

Also, we’ve to call JSON.stringify to convert it to a string so we can interpolate it.

Write to a CSV in Node.js

We can use csv-stringify package to create a CSV string from a nested array.

Then we can use fs.writeFile to write the CSV string to a file.

For instance, we can write:

import stringify from 'csv-stringify';
import fs from 'fs';

let data = [];
let columns = {
  id: 'id',
  name: 'name'
};

for (let i = 0; i < 100; i++) {
  data.push([i, `name ${i}`]);
}

stringify(data, { header: true, columns }, (err, output) => {
  if (err) throw err;
  fs.writeFile('file.csv', output, (err) => {
    if (err) throw err;
    console.log('csv saved.');
  });
});

We create a nested array with a columns array for the columns.

The key in columns are the field name. The value in columns are the heading names.

Then we populate our data into the data array.

Next, we call stringify to turn the heading and data into one CSV string.

The first argument is the data.

Then 2nd is an object with some options.

header set to true means we show some header.

columns is for setting the column fields.

The columns are populated by the position of each item in each row.

For each row in data , the first entry is the id and the 2nd is the name .

The callback is called when the CSV conversion is done.

output has the CSV string.

Then we can fs.writeFile to write the string to a file.

Reload Express.js Routes Changes without Manually Restarting Server

We can make an Express app restart automatically when we change the code by using Nodemon.

We can run our app with nodemon instead of node once it’s installed.

To install it, we run:

npm install -g nodemon

Then we run:

nodemon app.js

to use it.

Fix ‘Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response’ Error with Express Apps

We can add the cors middleware to allow cross-origin requests.

Then this error should go away.

We can write:

const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.options('*', cors());

We use the cors middleware to add the Access-Control-Allow-Origin and Access-Control-Allow-Methods headers.

Also, we added the required OPTION routes with the cors middleware.

We allow all routes to accept OPTION requests with '*' .

Conclusion

There are several packages to read Excel files.

We can pass variables to templates with Express.

Also, we can write CSV easily to a file with a library.

To allow our Express app to listen for cross-origin requests, we need the cors middleware.

Categories
Node.js Tips

Node.js Tips — Closing Connections, Templates, and Dates

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.

Custom Validation Using 2 Fields with Mongoose

To do custom validation using 2 fields with Mongoose, we can create a custom schema and a validation function and pass that as the value of a field in the object we pass into the Schema constructor.

For instance, we can write:

const dateRangeSchema = {
  startDate: { type: Date },
  endDate: { type: Date }
};

const checkDates = (value) => {
  return value.endDate < value.startDate;
}

const schema = new Schema({
  dateRange: { type: dateRangeSchema, validate: checkDates }
});

We created the dateRangeSchema with the startDate and endDate fields.

Also, we created thew checkDates function to return the date range.

And then we pass both into the object to specify the data type for a field.

We can also pass in a callback to validate by writing:

schema.pre('validate', function(next) {
  if (this.startDate > this.endDate) {
    next(new Error('start date is after the end date'));
  } else {
    next();
  }
});

We get the startDate and endDate values from the model and call next with an error if the start date is bigger than the end date.

Otherwise, we call next with nothing to proceed as normal.

Format a Date Coming from MongoDB

We can format a date coming from MongoDB with the toDateString method.

For instance, we can write:

Schema
  .virtual('date')
  .get(function() {
    return this._id.generationTime.toDateString();
  });

We can also use the moment.js library to make our lives easier.

For instance, we can write:

Schema
  .virtual('date')
  .get(function() {
    return moment(this._id.generationTime).format("YYYY-MM-DD HH:mm");
  });

We called the format method to format the moment object created from the moment function into the date format we want.

It’s returned as a string.

Variable in Class Name in Jade/Pug Template

We can interpolate a string into a Jade/Pug template by writing:

div(class="language-#{session.language}")

Listen to All Interfaces Instead of Localhost Only in an Express App

We listen to all interfaces in an Express app by passing in '0.0.0.0' as the 2nd argument of listen.

For instance, we can write:

const express = require('express');
const app = express();
app.listen(3000, '0.0.0.0');

Accessing EJS Variable in Javascript Logic

If we have a route that renders an EJS template, we can render the variable that’s passed in from the render method.

For instance, we can write:

app.get("/post/:title, (req, res) => {
  //...
  res.render("post", { title, description });
}

to create our route,

Then in our EJS template, we can write:

<% if (title) { %>
     <h2>Post</h2>
     <script>
        const postTitle = <%= title %>
     </script>
<% } %>

We get the title from the object in the 2nd argument.

Then we interpolate the title into the template.

Now we can assign that to a variable.

End an Express.js POST Response

We call res.end to end the response to end the response.

For instance, we can write:

res.end('hello');

Or we can render a template and then call res.end :

res.render('some.template');
res.end();

Shut Down an Express Server Gracefully When Its Process Is Killed

We can listen to the SIGTERM and SIGINT signals and then run our code in the handler for those signals and close the server in the callback.

For instance, we can write:

const express = require('express');

const app = express();

app.get('/', (req, res) => res.send('hello'});

const server = app.listen(3000);

setInterval(() => server.getConnections((err, connections) =>  {
  console.log(`${connections} connections currently open`)
}), 1000);

process.on('SIGTERM', shutDown);
process.on('SIGINT', shutDown);

let connections = [];

server.on('connection', connection => {
  connections.push(connection);
  connection.on('close', () => {
    connections = connections.filter(curr => curr !== connection)
  });
});

const shutDown = () => {
  server.close(() => {
    process.exit(0);
  });

  setTimeout(() => {
    process.exit(1);
  }, 10000);

  connections.forEach(curr => curr.end());
  setTimeout(() => connections.forEach(curr => curr.destroy()), 5000);
}

We listen to the SIGTERM and SIGINT signals with the process.on method.

We pass in the shutDown function, where we call server.close to close the connections.

We also exit with code 1 after 10 seconds if the connections aren’t closed successfully.

The connections are stored in the connections array and call end to close each connection.

We also call destroy to destroy the connections after 5 seconds.

The connections cames from the connection event handler where we pushed new connection objects into the connections array.

We also add the close handler with the filter method.

Conclusion

We can validate multiple fields concurrently with Mongoose.

Also, we can shut down connections gracefully.

We can also format the date coming from MongoDB.

Categories
Node.js Tips

Node.js Tips — Mongoose Updates, HTML Emails, and Stubbing Dependencies

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.

Using Mongoose Promises with async/await

Mongoose methods return promises.

So we can use them with async and await .

For instance, we can write:

const orderEmployees = async(companyID) => {
  try {
    const employees = await User.find({ company: companyID }).exec();
    console.log(employees);
    return employees;
  } catch (err) {
    return 'error occured';
  }
}

We can User.find with a query.

That returns a promise with the resolved result.

We can also catch errors with catch .

Pass Variable to HTML Template in nodemailer

Nodemailer accepts HTML for content.

To make creating HTML emails easier, we can use a templating engine like Handlebars.

For instance, we can write:

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

const readHTMLFile = (path, callback) => {
  fs.readFile(path, {
    encoding: 'utf-8'
  }, (err, html) => {
    if (err) {
      throw err;
      callback(err);
    } else {
      callback(null, html);
    }
  });
};

smtpTransport = nodemailer.createTransport(smtpTransport({
  host: mailConfig.host,
  secure: mailConfig.secure,
  port: mailConfig.port,
  auth: {
    user: mailConfig.auth.user,
    pass: mailConfig.auth.pass
  }
}));

readHTMLFile(path.join(__dirname, '/template.html'), (err, html) => {
  const template = handlebars.compile(html);
  const replacements = {
    username: "joe"
  };
  const htmlToSend = template(replacements);
  const mailOptions = {
    from: 'from@email.com',
    to: 'to@email.com',
    subject: 'test',
    html: htmlToSend
  };
  smtpTransport.sendMail(mailOptions, (error, response) => {
    if (error) {
      console.log(error);
      callback(error);
    }
  });
});

We import the Handlebars library and call compiler with the template.

The template is read from the readHTMLFile function which uses fs to read the file.

Then it’s passed to the callback.

We get the template with the html parameter.

Once we compile the template, we call template with the object with the properties to interpolate the properties into the template to get the final email.

Then we call smptTransport.sendMail to send the email.

We set the html property with the HTML content.

htmlToSend is an HTML string.

Formatting ISODate from MongoDB

We can format the date object from MongoDB with the toTimeString method.

We just call ut by writing:

const date = new Date("2019-07-14T01:00:00+01:00")
consr str = date.toTimeString();

MongoDB also has the ISODate function to make working with ISO date strings easy.

For example, we can write:

ISODate("2019-07-14T01:00:00+01:00").toLocaleTimeString()

to parse the ISO date string and convert it to a locale-sensitive time string.

We can also get the hours and minutes:

ISODate("2019-07-14T01:00:00+01:00").getHours()
ISODate("2019-07-14T01:00:00+01:00").getMinutes()

Stub Node.js Built-in fs During Testing

We want to mock the fs module so that tests won’t do real file operations.

To do that, we use rewire to stub out required modules.

For instance, if our real code is:

reader.js

const fs = require('fs');
const findFile = (path, callback) => {
  fs.readdir(path, (err, files) => {
     //...
  })
}

We can use rewire to stub out readdir in our test code by writing:

const rewire = require('rewire')
const `reader` = rewire('./`reader`')

const fsStub = {
  readdir(path, callback){
    callback(null, [])
  }
}

`reader`.__set__('fs', fsStub)

`reader`()

Now we can use reader without actually calling readdir since we called __set__ to set the fs module to our stub instead of the read fs module.

Return Updated Collection with Mongoose

We can return an updated collection in Mongoose, then we can get it from findOneAndUpdate with the new option set to true .

For instance, we can write:

Model
  .findOneAndUpdate({
    user_id: data.userId
  }, {
    $set: {
      session_id: id
    }
  }, {
    "new": true
  })
  .exec()
  .then(data => {
    return {
      sid: data.session_id
    }
  })

We call findOneAndUpdate and then we use $set to update a field,

We pass in an object with the new property set to true to return the latest data in the then callback.

Also, we can write:

Lists.findByIdAndUpdate(listId, {
  $push: {
    items: taskId
  }
}, (err, list) => {
  ...
});

We get the latest list with list .

$push appends an item to the items list in the document.

Conclusion

We can get the latest list after the update.

We can stub dependencies with rewire .

We can use HTML templates with Nodemailer.

Mongoose methods return promises.