# Hooks
# Why?
In the real world, everybody needs more than saving and listing records. Everybody needs more complicated logic in their code. Axe API provides you a basic structure of an API. It provides you basic CRUD actions with dynamic query options. But when you need custom logic, you will not be alone. Axe API provides you escape points to extend your HTTP requests and manipulate them.
There are two different ways to add your business logic; Hooks and Events. They are almost the same except one differences. We are going to explain it later. But first, we should understand what the hook is.
# Hooks
Axe API automatically handles your API. It creates routes, handles HTTP requests, performs the request, and creates a response. But it doesn't just do these. It also has some escape points. With those, you can add your code to the HTTP Request-Response cycle.
For example, let's assume that you want to hash the user's password in user creation. How can we do this? First, we should create a file that is called UserHooks.js
under app/Hooks
.
UserHooks.js
import bcrypt from "bcrypt";
const onBeforeInsert = async ({ formData }) => {
// Genering salt
formData.password_salt = bcrypt.genSaltSync(10);
// Hashing the password
formData.password = bcrypt.hashSync(
formData.password,
formData.password_salt
);
};
export { onBeforeInsert };
In the code above, we used bcrypt (opens new window) library to hash the user's password. By accessing form data, hashing the user's password is easy.
But can this function be executed? Yes! In the booting process, Axe API tries to discover what kind of hooks and events have been written. For a model called User
, if you create a hook which is called UserHook
, Axe API accepts that UserHooks
is the hook definition file for the model User
. In the HTTP request processing time, if there is any hook that has been written, Axe API calls that hook.
This feature gives us very important flexibility. First of all, you can add any logic by the parameters which Axe API passed. Secondly, the hook functions are almost isolated. It means that writing unit tests about them is very easy.
This structure is almost the same for Events, too.
# Events
The main difference between Hooks and Events is; events are asynchronous. It means that if you are using an hooks and handle the request, the HTTP request cycle waits for you to do your task. But in events, when you handle the event, the HTTP requests cycle keeps working and returns a response. So, if you want to send an e-mail to the user, you should use Events. On the other hand, if you want to be involved in the query or any business logic in the HTTP request cycle, you should use Hooks.
Using Events is very easy, almost same with the hooks. There is only one different thing in usage. Which is creating the event file under the app/Events
folders.
app/Events/UserEvents.js
const onAfterInsert = async ({ formData }) => {
// You can send an email to the user in here...
};
export { onAfterInsert };
# Request Lifecycle
To write hook or event functions, you should understand the Axe API HTTP Request's lifecycles. Before doing that, we are going to define basic facts.
# Definitions
- Handlers are types of model processing. There are five basic handlers in Axe API
- INSERT
- PAGINATE
- SHOW
- UPDATE
- DELETE
- Two different actions can be done on the data, in a handler;
- Manipulating
- Fetching
- Some of handlers do only one action, but some of them do both.
- Insert: Manipulating
- Update: Fetching, Manipulating
- Delete: Fetching, Manipulating
- Show: Fetching
- Paginate: Fetching
We can show which handler do what actions in a table;
Handler | Manipulating | Fetching |
---|---|---|
INSERT | ✓ | |
PAGINATE | ✓ | |
SHOW | ✓ | |
UPDATE | ✓ | ✓ |
DELETE | ✓ | ✓ |
These values are important because we are using that definitions in Request Lifecycle.
# Request Lifecycle
In Axe API, we use Before and After hooks/events to give more flexibility. Also, Axe API calls hooks first. After hooks, it calls events if there any. With this information, we can describe general schema of Request Lifecycle;
- Axe API start to process HTTP Request
- Call model-based middlewares
- Call the handler (INSERT, UPDATE, etc.)
- Call Before Fetching hooks
- Call Before Fetching events
- Execute Fetching action.
- Call After Fetching hooks
- Call After Fetching events
- Call Before Manipulating hooks
- Call Before Manipulating events
- Execute Manipulating action.
- Call After Manipulating hooks
- Call After Manipulating events
- Send the response.
This is the basic standard of our calling Hooks/Events system. By the type of handler, you can add many different hooks/events.
# Full Hooks/Events Table
The following table describes all possible hooks by handler types.
Handler | Manipulating | Fetching |
---|---|---|
INSERT | onBeforeInsert /onAfterInsert | |
PAGINATE | onBeforePaginate /onAfterPaginate | |
ALL | onBeforeAll /onAfterAll | |
SHOW | onBeforeShow /onAfterShow | |
UPDATE | onBeforeUpdate /onAfterUpdate | onBeforeUpdateQuery /onAfterUpdateQuery |
PATCH | onBeforeUpdate /onAfterUpdate | onBeforeUpdateQuery /onAfterUpdateQuery |
DELETE | onBeforeDelete /onAfterDelete | onBeforeDeleteQuery /onAfterUpdateQuery |
# Parameters
There are some parameters which you can use in a hook or event function.
# Common Parameters
request
: Request object of Expresss (opens new window)response
: Response object of Expresss (opens new window)model
: Current model instance. For example;User.js
.database
: Database connection instance. For example Knex.js (opens new window)relation
: The relation definition if the route is a related route (For exampleapi/users/:userId/posts
).parentModel
: The parent model instance if the route is a related route (For exampleapi/users/:userId/posts
).
# Special Parameters
query
: The Knex.js' query instance (opens new window).conditions
: The conditions which has been send by the HTTP client to filter data.item
: The current record. (For example; the item that will be updated.)result
: The query result. (For example SHOW and PAGINATE handlers.)formData
: The data has been sent by HTTP client to create or update row.
We can show all special parameters in the following table;
Hook/Events Name | Parameters |
---|---|
onBeforeInsert | formData |
onBeforeUpdateQuery | query |
onBeforeUpdate | item, formData, query, |
onBeforeDeleteQuery | query |
onBeforeDelete | query |
onBeforePaginate | conditions, query |
onBeforeAll | conditions, query |
onBeforeShow | conditions, query |
onAfterInsert | formData, item |
onAfterUpdateQuery | item, query |
onAfterUpdate | item, formData, query |
onAfterDeleteQuery | query, item |
onAfterDelete | item |
onAfterPaginate | results, conditions, query |
onAfterAll | results, conditions, query |
onAfterShow | item, conditions, query |
← Error Handling IoC →