Hooks
Last updated: 4 - 5 - 2019

ZinkyJS's hooks are functions that are called before the request operation to give you the possibility to handle the request, stop it or anything you want to do before the operation execution.

There are 4 different types of hooks in ZinkyJS:

Additionally to that, we'll see:

Global Hooks

Global hooks are hooks that are called on every request in the app, before the request operation.

To add a hook, use addHook() method after app initialization.

const Zinky = require('zinky');

var app = new Zinky({
 aliases: {
    '': 'home'
    'customers': 'users'
  }
});

app.addHook((req, res, next) => {
  console.log("I'm a global hook. I run every time!")
  next();
})

app.listen();

You've probably noticed the usual (req, res, next), well known by ExpressJS developers. But if it's the first time you see them don't worry, here is a short explanation:

- req
: Represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on. By convention, the object is always referred to as req. It's an enhanced version of Node’s own request object and supports all built-in fields and methods.

- res
: Represents the HTTP response that an Express app sends when it gets an HTTP request. By convention, the object is always referred to as res. It's an enhanced version of Node’s own response object and supports all built-in fields and methods.

- next
: This is the callback. Call it when you are done with the hook and want to run next hook or operation (the operation is actually a hook that is called lastly, that's why we don't give it a next callback).

You can copy the code to your project and see what it does.

Module's Hook

A module's hook is a hook that is called on every request on the module.

To create a module's hook add hook(req, res, next) method to the module and you're done.

Test it, by adding this to "app_modules/users/index.js":

 hook(req, res, next) {
  console.log("Hello! I'm the users module hook. I run every time you request users module")
  next();
}

Visit localhost:3000/users/, and open the terminal that's running the app to see the result.
You will see these messages:

 I'm a global hook. I run every time!
Hello! I'm the users module hook. I run every time you request users module

BEFORE Hooks

BEFORE Hooks are, as their name suggests, hooks that run before a specific operation.
They are made by creating methods named 'BEFORE_' + operation

Eg:

 BEFORE_GET_root(req, res, next) {
  console.log("Keep Ready! You're about to access operation");
  next();
}

Add the above method to "app_modules/users/index.js", and visit localhost:3000/users/.
Check the terminal!

What we saw here, are internal BEFORE hooks, that means that they belongs to the module of the operation they're attached to. But since ZinkyJS is awesome, it gives us a way to attach a hook to a specific operation from outside its module. These are what we call external BEFORE hooks

External BEFORE hooks are created by writing methods named as following:
'BEFORE_' + operationModule + operation

Add this hook to "app_modules/home/index.js", and test it:

 BEFORE_users_GET_root(req, res, next) {
  console.log("I'm a before hook that lives at home");
  next();
}

AFTER Hooks

Just as ZinkyJS offers a way to make hooks before a specific operation, it allow us to attach hooks after the operation is called.

The AFTER hooks are called after the request has finished, which means that the client gets the request response before they are called.

And like BEFORE hooks, the AFTER hooks can be internal or external.

To see it in real add these lines to 'app_modules/users/index.js':

 AFTER_GET_root(req, res) {
  console.log("I'm the hook that runs after the client has received the response");
}

And these ones to "app_modules/home/index.js":

 AFTER_users_GET_root(req, res) {
  console.log("I'm called from home after client has been served");
}

Now run the app and visit localhost:3000/users/.

As you can see, AFTER hooks don't get a callback. That's because they are not called in a stack, ZinkyJS runs every one of them asynchronously and does not wait until the first finishes to call the second.

Express Middlewares

ZinkyJS hooks get the same parameters as ExpressJS middlewares do, that's what makes them compatible.

ExpressJS middlewares, when used in ZinkyJS, are used as global hooks and are added using addHook(). This method (addHook) works exactly like the use() method of ExpressJS.

In our example we'll use this basicauth-middleware that was developed originaly for ExpressJS but that we can use with ZinkyJS.
Here is how to do it:

 const Zinky = require('zinky');
const basicauth = require('basicauth-middleware');

var app = new Zinky({
 aliases: {
    'customers': 'users'
  }
});

app.addHook(basicauth('myname', 'somesecretword'));
app.listen();

Install the newly used package:

sudo npm install -g basicauth-middleware

Now run the app and open it in your browser.

Execution Order

We saw that ZinkyJS allows us to attach hooks before and after operations, but things can get confusing because of the multiple types of hooks. One of this unclear things is the order in which hooks are called. So let's explane it:
At first, when the app receives a request, ZinkyJS runs its built-in hooks, those who parse the url, cookies, query... and enhance req and res objects in order to make our lifes easier. Next, it calls the global hooks in the order they were added using addHook(). Then, ZinkyJS looks for the external BEFORE hooks ordered by their respective modules names alphabetically. After that, it calls the internal BEFORE hook and finally runs the operation and waits for the response to be sent to run all the AFTER Hooks simultaneously.

Summarizing all that, gives:

  1. Built-in Hooks
  2. Global Hooks
    (In the order they were added)
  3. External BEFORE Hooks
    (ordered by their respective modules names alphabetically)
  4. Internal BEFORE Hook
  5. Operation
  6. AFTER Hooks
    (simultaneously)
Next Course: Views & Templating Engines