Cheatsheet

Backend dev cheatsheet !

Express

  • Error-handling middleware should always be defined as the last of all middlewares
  • The next() function can take an error as its parameter, which it will pass to the next middleware
  • Using the 404-catching middleware after all other route handlers will ensure it forwards the 404 error to the error-handling middleware, in case the request does not match any of the router's routes.
  • app.get and app.post are just shorthands for the express router, which can be required using const router = express.Router(). A good practice is to modularize the routing then use it as a middleware with app.use('/', routes) or the shorthand app.use(routes)
  • If only a function is passed to app.use, without any route as its first parameter, the middleware will apply to all routes
  • To parse the body of POST requests, express needs a middleware, such as body-parser
  • Different middlewares can be used as arguments of app.use (or router.use). They can be defined inline, but for readability purposes a good practice is to have middlewares definitions grouped either at the top or bottom (thanks to functions hoisting) of the file, or even in an external middlewares file (following the node modular architecture idea)
  • Middlewares should be passed as function references, express will then take care of calling them for us (see Node)
  • Calling next(err)will actually stop the middleware flow and call the error-handling function, passing the error to it

Node

  • util.inspect()can be used to debug objects in the console, otherwise node will simply return a [object OBJECT] instead of the object' string representation.
  • __dirnameshould always be used to construct dir names, instead of ./so as to make sure the constructed dir is valid
  • If module.exports is a single function, then it can either be called later on using the var assigned to its require, ex

    let express = require('express') 
    let app = express()

    But it can also be called on-place :

    let app = require('express')() 

    Both examples produce the same result, making app() a new instance of the express function


    NOTE FOR EXPRESS MIDDLEWARES

    When passing middleware functions to express' use() function, there is no need to actually call them as express will do it for us.

Mocha/Chai

  • Chai assertion library can be used with mocha testing framework, but any assertion library can be used such as sinon
  • Chai makes used of chained methods for its assertions, e.g:

    • expect(varToTest).to.be.true
    • assert(varToTest, resultWanted) Note: This is syntaxic sugar over node's native assert lib
    • See external cheatsheet in references

JS

  • A callback is sent by the browser/node into the webapi. Then, it goes into the task queue. However, tasks from the queue are sent to the stack only when the stack is clear. That's why using setTimeout with a 0 timeout effectively defers the function to the end of the stack.
  • async/await is just syntactic sugar for promises. Which means we can either catch errors with a try/catch or by chaining a .catch to the await(somePromise).
  • await can only be used in an async function. Which makes it unusable from the very top-level of a module, except if we wrap-it in a C-style main()
  • Class that inherits from a parent class should have super(args) in their constructor, allowing them to use their parent methods and vars
  • Bluebird can be used the exact same way as the native ES6 promises, as such it can (and should) replace the native Promise constructor using require. However it has a few advantages:

    1. Bluebird can be used to promisify functions i.e created an "async"-prefixed equivalent. It works only on functions with callbacks following the node.js callbacks convention
    2. It has a Promise.all() method, where the next promise depends on multiple promises resolving.
    3. You can chain a .finally() which will be executed no matter the promise resolves or rejects. This might be implemented natively soon though, as per the TC39 proposal, Promise.prototype.finally is currently in stage 3 of the process.
    4. Even if just using then and catch, bluebird is way more performant compared to native promises

    And a lot more !

  • arr.indexOf(elementToCheck) === -1: Checks for the presence of an element in an array

Mongo/Mongoose

  • Schemas passed to to mongoose.model(), shouldn't have an _idproperty, as findById method won't work anymore then
  • Using query.exec() will make sure that mongoose returns a promise that resolves to the result of our query. This is extremely useful : knowing this, we can create CRUD functions with ES7 that are very clean and concise, ex async find(product) => { return await ProductModel.find({product}).exec() } Using ES6 arrow functions, ES6 shorthand for {object : object}, ES7 async/await and mongoose await, this makes for very clean code !

References