{"componentChunkName":"component---src-templates-post-js","path":"/post/node-is-simple-part-5","result":{"data":{"contentfulHero":{"coverImage":{"file":{"url":"//images.ctfassets.net/xmu5vdhtphau/1jqMTE2RJBiMLIcZAnu6It/5495c6ec7df10a55768df442e73fe4b2/home-hero-min.jpg","fileName":"home-hero-min.jpg"}}}},"pageContext":{"post":{"id":"ab2a9ea8-cb4f-5970-be46-1359265a19f5","slug":"node-is-simple-part-5","title":"Node Is Simple — Part 5 ","createdAt":"Aug 24, 2020","tweetText":null,"type":"blog","video":null,"podcast":null,"categories":[{"id":"4384d042-dd09-5c7b-967b-95eab1334a2c","name":"Node.js","slug":"node-js"},{"id":"a397ebc3-492b-5568-b45d-6d4aa9722be7","name":"Tutorials","slug":"tutorials"}],"image":{"file":{"url":"//images.ctfassets.net/xmu5vdhtphau/3rLlrTNVqfNNCY7sOrQxnP/a20a0f5209e19a2f5f717ccb3122d3e0/part5.png","fileName":"part5.png"}},"author":{"name":"Nipuna Weerasekara","bio":{"childMarkdownRemark":{"html":"<p>Part time web developer, full time dreamer… Find me @ <a href=\"https://niweera.gq\">https://niweera.gq</a></p>"}},"avatar":{"file":{"fileName":"1_cuJOF_sqBLbMA69vCFMqEQ.jpeg","url":"//images.ctfassets.net/xmu5vdhtphau/4iEstuN4qOq6h1vKjwpPRW/413c90f5bfa0c51170b560407e31c7c6/1_cuJOF_sqBLbMA69vCFMqEQ.jpeg"}}},"bodyContent":{"childMarkdownRemark":{"html":"<p><strong><em>tl;dr</em></strong> — <em>This is the fifth article of the</em> <strong><em>Node is Simple</em></strong> <em>article series. In this article series, I will be discussing how to create a simple and secure NodeJS, Express, MongoDB web application.</em></p>\n<p>To follow the past tutorials:</p>\n<ul>\n<li><a href=\"https://node.dev/post/node-is-simple-part-1\">Node Is Simple — Part 1</a></li>\n<li><a href=\"https://node.dev/post/node-is-simple-part-2\">Node Is Simple — Part 2</a></li>\n<li><a href=\"https://node.dev/post/node-is-simple-part-3\">Node is Simple — Part 3</a></li>\n<li><a href=\"https://node.dev/post/node-is-simple-part-4\">Node Is Simple — Part 4</a></li>\n</ul>\n<p>Hello, hello, my dear fellow developers, glad you could make it to my article where I discuss developing web applications with NodeJS. As I promised in the previous article, in this article I will tell you how to use custom middleware with Express.</p>\n<h2>So what is this <em>Middleware?</em></h2>\n<p>That’s the question, isn’t it? As I told you many times, Express is great with middleware. As discussed in the <a href=\"https://expressjs.com/en/guide/using-middleware.html\">Express documentation</a>,</p>\n<blockquote>\n<p><strong><em>Middleware</em></strong> functions are functions that have access to the <a href=\"https://expressjs.com/en/4x/api.html#req\">request object</a> (<code>req</code>), the <a href=\"https://expressjs.com/en/4x/api.html#res\">response object</a> (<code>res</code>), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named <code>next</code>.</p>\n</blockquote>\n<p>Express is nothing without middleware. So I am going to implement a simple error handling middleware. As the Express documentation describes,</p>\n<pre><code>app.use(function (err, req, res, next) {  \n  console.error(err.stack)  \n  res.status(500).send('Something broke!')  \n})\n</code></pre>\n<p>this is how we create a simple middleware to log errors. But in this tutorial, I will extend this middleware to return specific error messages and HTTP error codes in the response and log the error messages in the console.</p>\n<p>So let’s get to it, shall we?</p>\n<p>First, let’s create some error classes to represent errors that we are going to get from the web application.</p>\n<p>Let’s create <em>/errors/index.js</em> file.</p>\n<pre><code>module.exports = {\n  AccessDeniedError: class AccessDeniedError {\n    constructor(message) {\n      this.message = message;\n    }\n  },\n  AuthenticationError: class AuthenticationError {\n    constructor(message) {\n      this.message = message;\n    }\n  },\n  ValidationError: class ValidationError {\n    constructor(message) {\n      this.message = message;\n    }\n  },\n  NotFoundError: class NotFoundError {\n    constructor(message) {\n      this.message = message;\n    }\n  }\n};\n</code></pre>\n<figcaption>/errors/index.js file (Contains error classes)</figcaption>\n<p>Let’s see what’s happening here. Here, we are declaring four classes to describe errors we encounter in web applications.</p>\n<ol>\n<li>Access Denied Error (HTTP 403)</li>\n<li>Authentication Error (HTTP 401)</li>\n<li>Not Found Error (HTTP 404)</li>\n<li>Validation Error (HTTP 400)</li>\n</ol>\n<p>Of course, there is another famous HTTP error which is called Internal Server Error (HTTP 500) but since it is a very generic error, we are not declaring a specific class to describe that and it will be the default error.</p>\n<p>Then let’s create the error handling middleware. Let’s create <em>/middleware/error-handling.js</em> file.</p>\n<pre><code>const {\n  ValidationError,\n  AuthenticationError,\n  AccessDeniedError,\n  NotFoundError\n} = require(\"../errors\");\nconst chalk = require(\"chalk\");\n\nconst errorLogger = (err, req, res, next) => {\n  if (err.message) {\n    console.log(chalk.red(err.message));\n  }\n  if (err.stack) {\n    console.log(chalk.red(err.message));\n  }\n  next(err);\n};\n\nconst authenticationErrorHandler = (err, req, res, next) => {\n  if (err instanceof AuthenticationError)\n    return res.status(401).send({ message: err.message });\n  next(err);\n};\n\nconst validationErrorHandler = (err, req, res, next) => {\n  if (err instanceof ValidationError)\n    return res.status(400).send({ message: err.message });\n  next(err);\n};\n\nconst accessDeniedErrorHandler = (err, req, res, next) => {\n  if (err instanceof AccessDeniedError)\n    return res.status(403).send({ message: err.message });\n  next(err);\n};\n\nconst notFoundErrorHandler = (err, req, res, next) => {\n  if (err instanceof NotFoundError)\n    return res.status(404).send({ message: err.message });\n  next(err);\n};\n\nconst genericErrorHandler = (err, req, res, next) => {\n  res.status(500).send({ message: err.message });\n  next();\n};\n\nconst ErrorHandlingMiddleware = app => {\n  app.use([\n    errorLogger,\n    authenticationErrorHandler,\n    validationErrorHandler,\n    accessDeniedErrorHandler,\n    notFoundErrorHandler,\n    genericErrorHandler\n  ]);\n};\n\nmodule.exports = ErrorHandlingMiddleware;\n</code></pre>\n<figcaption>/middleware/error-handling.js file (Contains the error handling middleware configurations)</figcaption>\n<p><img src=\"//images.ctfassets.net/xmu5vdhtphau/45sg1ZlK3UmbdHYSaDUS3b/a5c582d096d392d12c2bcfc812932834/1.jpeg\" alt=\"1\"></p>\n<figcaption>From https://knowyourmeme.com/memes/what-the-hell-happened-here</figcaption>\n<p>Well, the code is somewhat complicated, isn’t it? Fear not, I will discuss what is happening here. First, we need to know how the Express middleware work. In Express middleware, if you provide error first callback, it will create the signature as an error-handling middleware.</p>\n<blockquote>\n<p>Error-handling middleware always takes <strong><em>four</em></strong> arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don’t need to use the <code>next</code> object, you must specify it to maintain the signature. Otherwise, the <code>next</code> object will be interpreted as regular middleware and will fail to handle errors.</p>\n</blockquote>\n<p>(from <a href=\"https://expressjs.com/en/guide/using-middleware.html\">https://expressjs.com/en/guide/using-middleware.html</a>)</p>\n<p>And another thing to mention is that the middleware can be defined as arrays. The array order will be preserved and the middleware will be applied in that order. So according to our code,</p>\n<pre><code>1. errorLogger //Logging errors  \n2. authenticationErrorHandler //return authentication error  \n3. validationErrorHandler //return validation error  \n4. accessDeniedErrorHandler //return access denied error  \n5. notFoundErrorHandler //return not found error  \n6. genericErrorHandler //return internal server error\n</code></pre>\n<p>this middleware will be called in the particular order. In our web application, if there is an error thrown, first the error will be logged in the console and the error will be passed to the <em>authenticationErrorHandler</em> with the <code>next(err)</code> handler. If the error is an instance of <em>AuthenticationError</em> class, then it will end the request-response cycle by returning the relevant error. If not it will be passed on to the next error handling middleware. So as you can imagine it will be passed to down in the middleware stack and finally it will be passed to the <em>genericErrorHandler</em> middleware and the request-response cycle will be ended. And it is simple as that.</p>\n<p>Now let’s bind this middleware as an <a href=\"https://expressjs.com/en/guide/using-middleware.html#middleware.application\">application-level middleware</a>. Let’s update <em>/index.js</em> file.</p>\n<pre><code>const express = require(\"express\");\nconst chalk = require(\"chalk\");\nconst http = require(\"http\");\nconst https = require(\"https\");\nconst config = require(\"./config\");\n\nconst HTTP_PORT = config.HTTP_PORT;\nconst HTTPS_PORT = config.HTTPS_PORT;\nconst SERVER_CERT = config.SERVER_CERT;\nconst SERVER_KEY = config.SERVER_KEY;\n\nconst app = express();\nconst Middleware = require(\"./middleware\");\nconst ErrorHandlingMiddleware = require(\"./middleware/error-handling\");\nconst MainController = require(\"./controllers\");\n\nMiddleware(app);\napp.use(\"\", MainController);\nErrorHandlingMiddleware(app);\napp.set(\"port\", HTTPS_PORT);\n\n/**\n * Create HTTPS Server\n */\n\nconst server = https.createServer(\n  {\n    key: SERVER_KEY,\n    cert: SERVER_CERT\n  },\n  app\n);\n\nconst onError = error => {\n  if (error.syscall !== \"listen\") {\n    throw error;\n  }\n\n  const bind =\n    typeof HTTPS_PORT === \"string\"\n      ? \"Pipe \" + HTTPS_PORT\n      : \"Port \" + HTTPS_PORT;\n\n  switch (error.code) {\n    case \"EACCES\":\n      console.error(chalk.red(`[-] ${bind} requires elevated privileges`));\n      process.exit(1);\n      break;\n    case \"EADDRINUSE\":\n      console.error(chalk.red(`[-] ${bind} is already in use`));\n      process.exit(1);\n      break;\n    default:\n      throw error;\n  }\n};\n\nconst onListening = () => {\n  const addr = server.address();\n  const bind = typeof addr === \"string\" ? `pipe ${addr}` : `port ${addr.port}`;\n  console.log(chalk.yellow(`[!] Listening on HTTPS ${bind}`));\n};\n\nserver.listen(HTTPS_PORT);\nserver.on(\"error\", onError);\nserver.on(\"listening\", onListening);\n\n/**\n * Create HTTP Server (HTTP requests will be 301 redirected to HTTPS)\n */\nhttp\n  .createServer((req, res) => {\n    res.writeHead(301, {\n      Location:\n        \"https://\" +\n        req.headers[\"host\"].replace(\n          HTTP_PORT.toString(),\n          HTTPS_PORT.toString()\n        ) +\n        req.url\n    });\n    res.end();\n  })\n  .listen(HTTP_PORT)\n  .on(\"error\", onError)\n  .on(\"listening\", () =>\n    console.log(chalk.yellow(`[!] Listening on HTTP port ${HTTP_PORT}`))\n  );\n\nmodule.exports = app;\n</code></pre>\n<figcaption>/index.js file (Updated to reflect the binding of error handling middleware)</figcaption>\n<p>Now I have something to clarify. As you can see line 19, I have added the <em>ErrorHandlingMiddleware(app)</em> there. You might wonder is there a specific reason behind that. Actually there is.</p>\n<pre><code>Middleware(app);  \napp.use(\"\", MainController);  \nErrorHandlingMiddleware(app);  \napp.set(\"port\", HTTPS\\_PORT);\n</code></pre>\n<p>As you can remember, the Express treats the middleware in their order we are binding it with the app. So if we bind the error handling middleware before binding the Express router, the Express app would not know where are the errors are being thrown. So we first bind the Express router and then we bind the error handling middleware.</p>\n<p>Now if you start the web application as usual,</p>\n<pre><code>$ pm2 start \n</code></pre>\n<p>and do some CRUD, operation, you won’t see any errors return since we haven’t added any error handling in our <em>/services/index.js</em> file. So I will show you an example of an error by explicitly throwing an error.</p>\n<p>Let’s add this error endpoint. Every time you hit it, it will throw you a not found error. Let’s update <em>/controllers/index.js</em> file.</p>\n<h2>GET /error</h2>\n<pre><code>_const_ { NotFoundError } = require(\"../errors\");_/\\*\\*_ **_@route_** _GET /error  \n \\*_ **_@desc_** _Return an example error  \n \\*_ **_@access_** _Public  \n \\*/  \n_router.get(  \n  \"/error\",  \n  asyncWrapper(_async_ () => {  \n    _throw new_ NotFoundError(\"Sorry content not found\");  \n  })  \n);\n</code></pre>\n<p><img src=\"//images.ctfassets.net/xmu5vdhtphau/6YLrvwoGtX2SMbN0oeHtQO/29f7fe4d9637f05c0230dd4030f79c89/2.jpeg\" alt=\"2\"></p>\n<figcaption>Figure 1: Request and response of custom error endpoint</figcaption>\n<p>As you can see in figure 1, the response status is 404 and the message says <em>“Sorry content not found”</em>. So it works as it should.</p>\n<p>Now let’s see how our console looks. Now type,</p>\n<pre><code>$ pm2 logs\n</code></pre>\n<p>in your terminal and see the console log.</p>\n<p><img src=\"//images.ctfassets.net/xmu5vdhtphau/o4tzaDOWly5hbG3MZ0Rre/c8ed5e58fb087e45fcc1282071498ad7/3.jpeg\" alt=\"3\"></p>\n<figcaption>Figure 2: console log</figcaption>\n<h2>Bonus super-secret round</h2>\n<p>So I’m going to tell you a super-secret about how to view colored logs in PM2. You just have to add a single line to the /<em>ecosystem.config.js</em> file.</p>\n<pre><code>const fs = require(\"fs\");\n\nconst SERVER_CERT = fs.readFileSync(__dirname + \"/config/server.cert\", \"utf8\");\nconst SERVER_KEY = fs.readFileSync(__dirname + \"/config/server.key\", \"utf8\");\n\nmodule.exports = {\n  apps: [\n    {\n      name: \"node-is-simple\",\n      script: \"./index.js\",\n      watch: true,\n      args: [\"--color\"],\n      env: {\n        NODE_ENV: \"development\",\n        SERVER_CERT,\n        SERVER_KEY,\n        HTTP_PORT: 8080,\n        HTTPS_PORT: 8081,\n        MONGO_URI: \"mongodb://localhost/students\"\n      }\n    }\n  ]\n};\n</code></pre>\n<figcaption>ecosystem.config.js file (Reflects the update to view colored console output)</figcaption>\n<p>ecosystem.config.js file (Reflects the update to view colored console output)</p>\n<p>All you have to do is add line 12. <code>args: [\"--color\"],</code></p>\n<h2>Bonus Bonus round</h2>\n<p>Now I’m going to tell you about two additional Express middleware libraries which are going to save your life 🤣.</p>\n<ol>\n<li><a href=\"https://www.npmjs.com/package/morgan\">Morgan</a> (HTTP request logger middleware for node.js)</li>\n<li><a href=\"https://www.npmjs.com/package/cors\">CORS</a> (CORS is a node.js package for providing a <a href=\"http://www.senchalabs.org/connect/\">Connect</a>/<a href=\"http://expressjs.com/\">Express</a> middleware that can be used to enable <a href=\"http://en.wikipedia.org/wiki/Cross-origin_resource_sharing\">CORS</a> with various options.)</li>\n</ol>\n<p>I guarantee that these two libraries will save you from certain pitfalls and you’ll thank them pretty much all the time.</p>\n<p>This is a good article on Morgan.</p>\n<p><a href=\"https://www.digitalocean.com/community/tutorials/nodejs-getting-started-morgan\">Getting Started With morgan: the Node.js Logger Middleware</a></p>\n<p>This is a good article on CORS.</p>\n<p><a href=\"https://medium.com/@alexishevia/using-cors-in-express-cac7e29b005b\">Using CORS in Express</a></p>\n<p>So let’s update our <em>/middleware/common.js</em> file.</p>\n<pre><code>const bodyParser = require(\"body-parser\");\nconst helmet = require(\"helmet\");\nconst morgan = require(\"morgan\");\nconst cors = require(\"cors\");\n\nmodule.exports = app => {\n  app.use(bodyParser.json());\n  app.use(morgan(\"dev\"));\n  app.use(cors());\n  app.use(helmet());\n};\n</code></pre>\n<figcaption>/middleware/common.js file (Updated to reflect the new middleware CORS and Morgan)</figcaption>\n<p>Then let’s install these two packages.</p>\n<pre><code>$ npm install cors morgan\n</code></pre>\n<p>Let’s see how the Morgan would show the HTTP requests in our console. We have specified “<em>dev”</em> as the logging level for Morgan. You can find more details on that from the <a href=\"https://www.npmjs.com/package/morgan\">documentation</a>.</p>\n<p><img src=\"//images.ctfassets.net/xmu5vdhtphau/xUrRhbezOVo0wfWkWf7C6/34bce84d6e0ee8a2f0af2e8b5de975ee/4.png\" alt=\"4\"></p>\n<figcaption>Figure 3: Morgan request logging in the console</figcaption>\n<pre><code>GET / 200 3.710 ms - 39\n</code></pre>\n<p>Let’s understand what this means.</p>\n<pre><code>:method :url :status :response-time ms - :res\\[content-length\\]\n</code></pre>\n<p>This is what the documentation says. Let’s break it down.</p>\n<pre><code>:method = GET (The HTTP method of the request.):url = / (The URL of the request. This will use req.originalUrl if exists, otherwise req.url.):status = 200 (The status code of the response.):response-time = 3.710 (The time between the request coming into morgan and when the response headers are written, in milliseconds.):res\\[content-length\\] = 39 (content-length of the response. If the content-length is not present, the value will be displayed as \"-\" in the log.)\n</code></pre>\n<p>This is it. Now if we move on to what the CORS module does, it ain’t much but it’s honest work 😁. It will save you from Cross-Origin Resource Sharing issues. If you have worked with APIs and front-ends, the CORS error is something you’ve seen at least once in your lifetime.</p>\n<p><img src=\"//images.ctfassets.net/xmu5vdhtphau/59KdWJcWlLnCdUhetgtkX2/f6d039f5387aa1ad3e6b282b972dbcae/5.png\" alt=\"5\"></p>\n<figcaption>From https://fdezromero.com/cors-errors-in-ionic-apps/</figcaption>\n<p>So CORS module will allow you to add CORS header with ease. I know this article was a little bit longer because I had to share some super-secrets with you. So this is it for this article and I will tell you how to secure our endpoints with JWT authentication in the next article. As usual, you can find the updated code in the GitHub repository. (Look for the commit message “Tutorial 5 checkpoint”.)</p>\n<p><a href=\"https://github.com/Niweera/node-is-simple\">Niweera/node-is-simple</a></p>\n<p>So until we meet again, happy coding.</p>"}}}}}}