Categories
Node.js Tips

Node.js Tips — Testing Redirects, Sessions, and Auth Middlewares

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.

Use the Middleware to Check the Authorization Before Entering Each Route in Express

We can add a middleware to a route to check for the proper credentials before entering a route.

For instance, we can write:

const protectedMiddlewares = [authChecker, fetchUser];
const unprotectedMiddlewares = [trackVisistorCount];

app.get("/", unprotectedMiddlewares, (req, res) => {
  //...
})

app.get("/dashboard", protectedMiddlewares, (req, res) => {
  // ...
})

app.get("/auth", unprotectedMiddlewares, (req, res) => {
  //...
})

app.put("/auth", unprotectedMiddlewares, (req, res) => {
  //...
})

We have an array of middleware for the protected dashboard route.

And we have an array of middleware for the unprotected routes.

A middleware may look like the following:

const authChecker = (req, res, next) => {
  if (req.session.auth || req.path === '/auth') {
    next();
  } else {
    res.redirect("/auth");
  }
}

We have the authChecker middleware that checks the path of the route and the session.

If there’s a session set, then we call the next middleware which should lead to a protected route handler in the end.

Otherwise, we redirect to the auth route.

Testing Requests that Redirect with Mocha and Supertest in Node

To test requests that redirect to another route with Supertest running in the Mocha test runner, we can write;

it('should log out the user', (done) => {
  request(app)
    .post('/login')
    .type('form')
    .field('user', 'username')
    .field('password', 'password')
    .end((err, res) => {
      if (err) { return done(err); }
      request(app)
        .get('/')
        .end((err, res) => {
          if (err) { return done(err); }
          res.text.should.include('profile');
          done();
        });
    });
});

We test a login route for redirection by checking the response text in the second end callback.

To do that, we made a POST request with the username and password.

Then that callback is called after the redirect is done.

We can get the text from the response to see if it’s the text in the profile route.

Send Additional HTTP Headers with Express

We can send whatever response headers we want with the setHeader method of the response object.

For instance, we can write:

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  return next();
});

We set the Access-Control-Allow-Origin to * to allow requests from all origins.

Working with Sessions in Express

To work with sessions in an Express app, we can use the expression-middleware.

For instance, we can use it by writing:

const express = require('express');
const session = require('express-session');

const app = express();

app.use(session({
  resave: false,
  saveUninitialized: false,
  secret: 'secret'
}));

app.get('/', (req, res) => {
  if (req.session.views) {
    ++req.session.views;
  } else {
    req.session.views = 1;
  }
  res.send(`${req.session.views} views`);
});

app.listen(3000);

We used the express-session package with a few options.

session is a function that returns a middleware to let us work with sessions.

resave means we don’t save a session if it’s not modified is it’s false .

saveUninitialized means that we don’t create a session until something is stored if it’s false .

secret is the secret for signing the sessions.

Then we can store whatever data we want in the req.session property.

It’ll persist until the session expires.

We just keep increasing the views count as we hit the / route.

The default is the memory store, which should only be used if we don’t have multiple instances.

Otherwise, we need to use persistent sessions.

Get the List of Connected Clients Username using Socket.io

We can get the list of clients connected to a namespace or not by using the clients method.

For instance, we can write:

const clients = io.sockets.adapter.rooms[roomId];
for (const clientId of Object.keys(clients)) {
  console.log(clientId);
  const clientSocket = io.sockets.connected[clientId];
}

We get an object with the client IDs as the keys with the io.socket.adapter.rooms object.

roomId is the ID of the room we’re in.

Then we can get the socket for the client with the io.socket.connected object.

Conclusion

We can get the clients with Socket.io.

Also, we can write our own middlewares to check for credentials before proceeding to the route.

express-session lets us work with sessions in our Express app.

We can test redirects with Supertest by checking the response content in the end callback.

Categories
Node.js Tips

Node.js Tips — Test File Uploads, App-Wide headers, Caching

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.

Programmatically Stop and Restart Express Servers to Change Ports

We can stop the server and restart it by writing:

server.on('close', () => {
  server.listen(3000);
});

server.listen(8000, () => {
  server.close();
});

We added a listener for the close event that’s run when the server is closed.

Then we call listen with a port.

We have the callback that calls the close method that triggers the close event.

And then the callback we passed to server.on will run.

Automatically Add Header to Every “render” Response

We can add a header to every render response by creating our own middleware to add the response header.

For instance, we can write:

app.get('/*', (req, res, next) => {
  res.header('X-XSS-Protection' , 0);
  next();
});

We add the X-XSS-Protection custom response header with value 0.

We can make the middleware run app-wide by writing:

app.use((req, res, next) => {
  res.set('X-XSS-Protection', 0);
  next();
});

Then we can add a test by installing Mocha and the hipper package by running:

npm install --save-dev mocha hippie

Also, we can test that by writing:

describe('Response Headers', () => {
  it('responds with header X-XSS-Protection with value 0', (done) => {
    hippie(app)
      .get('/foo')
      .expectHeader('X-XSS-Protection', 0)
      .end(done);
  });
});

We import the app object which we have in the previous example.

Then we pass that to hippie and call a route and then call expectHeader to check that the header returned.

And then we call end with done to finish the test.

Set Cache Control Header for Dynamic Data Express

We can set the Cache-Control header with our own value.

For instance, we can write:

res.set('Cache-Control', 'public, max-age=86400');

which sets the Cache-Control header to one day, which is 86400 seconds.

We can use it in a middleware by writing:

app.use((req, res, next) => {
  res.set('Cache-Control', 'public, max-age=86400');
  next();
})

We just put the line in and call next to call the next middleware.

Express Serve Static Folder Relative to Parent Directory

We can serve a folder as a static folder relative to a directory with path.join .

For instance, we can write:

const path = require('path');
const express = require('express');
const app = express();

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

We call express.static to set the public folder which is one level above the current folder as a folder for serving static files.

Send Multiple Response Chunks in one Route

If need to send our responses in chunks, we can use the response.write method.

For instance, we can write:

response.write("foo");
response.write("bar");
response.end();

We called response.write twice to send different parts of the response,

Then we call response.end to finish sending the response.

Unit Test with a File Upload in Mocha

We can test file upload by writing:

const should = require('should');
const supertest = require('supertest');
const request = supertest('localhost:3000');

describe('upload', () => {
  it('a file', (done) => {
    request
      .post('/upload')
      .field('foo', 'bar')
      .attach('image', 'pic.jpg')
      .end((err, res) => {
        res.should.have.status(200);
        done();
      });
  });
});

We make a POST request with supertest and call attach to attach the file with the given name.

field has the text fields that we want to submit with the file upload.

Then we check that the response is 200 with the callback.

We can attach more than one field or file attachment.

Listen to socket.io Errors in an Express App

We can listen to socket.io in an Express app by passing in the server object returned by listen into the socket.io function.

For instance, we can write:

const express = require('express');
const app = express();
const server = app.listen(port);
const io = require('socket.io')(server);

We pass the server into the function returned by the socket.io package,.

Also, we can write:

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

const server = http.createServer(app);
consr io = require('socket.io').listen(server);
server.listen(80);

We pass the server returned from the http module into the listen method instead.

Conclusion

We can set the header by using the res.header method.

There are multiple ways to listen to errors from socket.io in an Express app.

We can also test file uploads with Supertest.

Categories
Node.js Tips

Node.js Tips — File Size, Plain Text Request Body, Sen

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.

Force Parse Request Body as Plain Text Instead of JSON in Express

We can remove the body-parser middleware to parse the request body as raw text.

For instance, we can write:

const express = require('express');

const app = express();

const parseRawBody = (req, res, next) => {
  req.setEncoding('utf8');
  req.rawBody = '';
  req.on('data', (chunk) => {
    req.rawBody += chunk;
  });
  req.on('end', () => {
    next();
  });
}

app.use(parseRawBody);

app.post('/test', (req, res) => {
  res.send(req.rawBody);
});

app.listen(3000);

We created our own parseRawBody middleware that takes the request, response objects and the next function.

req is the request, which is a read stream.

We can get the data from it by listening to the data event.

In the handler for the data event, we concatenate the chunks of text to the req.rawBody property.

Then when the end event is emitted, then the stream has no more data to emit, so we call next to move to the next middleware.

Then we can access req.rawBody in the routes that come after it.

If we use the body-parser package, then we can use the bodyParser.text() middleware to keep the request body as plain text.

For instance, we can write:

app.use(bodyParser.text());

Then we can access the request body by writing:

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

req.body has the string with the request body.

Sending Message to a Specific Client with Socket.io and Empty Message Queue

To send a message to a specific client and empty the message queue with socket.io, we can listen to the connection event and then set the socket object as the property of an object.

For instance, we can write:

const socketio = require('socket.io');
const clients = {};
const io = socketio.listen(app);

io.sockets.on('connection', (socket) => {
  clients[socket.id] = socket;
});

The property name is the socket’s ID, indicated by the socket.id property.

We saved each client’s socket so that we can call emit to send a message to the client later.

Then we can send a message by writing:

const socket = clients[socketId];
socket.emit('show', {});

Where socketId is the ID of the socket that we set earlier.

We call emit with our own event and data we want to send.

Modifying Express Request Object

To modify the Express’s request object, we can assign our properties in the request object.

For instance, we can write:

app.use((req, res, next) => {
  req.root = `${req.protocol}://${req.get('host')}`;
  next();
});

We set the req.root property to the protocol and host of the URL combined.

The callback is a middleware that we can use anywhere.

next is a function that calls the next middleware in the chain.

Find the Size of the File in Node.js

We can find the size of a file with stateSync .

For instance, we can write:

function getFileSize(filename) {
  const stats = fs.statSync(filename);
  const fileSizeInBytes = stats.size;
  return fileSizeInBytes;
}

We call statsSync on the filename parameter, which is the string path to a file.

Then we can get the size in bytes with the size property.

We can also use the filesize package to get the file size.

For instance, we can write:

const filesize = require("filesize");
const stats = fs.statSync("foo.txt");
const fileSizeInMb = filesize(stats.size, {round: 0});

The benefit of this package is that we can conveyor the size to whatever format we like.

For instance, we can change the base, convert it to an object, and much more.

The example above converted the size to the file size in megabytes.

We can do other conversions by writing:

const filesize = require("filesize");
const stats = fs.statSync("foo.txt");
const fileSizeMb = filesize(stats.size, {round: 0});
const fileSizeArray = filesize(stats.size, {output: "array"});
const fileSizeObj = filesize(stats.size, {output: "object"});

The array has the size and unit as separate entries of the array.

object puts the size, union, exponent in their own properties.

Conclusion

We can keep the request body text in various ways.

There are libraries to help us get the file size in the format we want.

We can send messages to a specific client with Socket.io.

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.