Jovo Hooks
Middleware hooks are the easiest way to extend certain parts of the Jovo Framework. You can see them as a lightweight version of Jovo plugins.
Introduction
Jovo hooks allow you to hook into the Jovo middleware architecture to extend or modify the framework without having to change its core code. Usually, this is used to hook into the RIDR Lifecycle, but it's also possible to hook into events.
Here are some examples of a hook:
// src/app.ts import { App, Jovo } from '@jovotech/framework'; // ... const app = new App({ /* app config */ }); app.hook('<middleware>', (jovo: Jovo): void => { // ... }); // Same hook without types app.hook('<middleware>', (jovo) => { // ... }); // Example: Execute code before the dialogue.start middleware app.hook('before.dialogue.start', (jovo: Jovo): void => { // ... });
If you compare hooks to plugins, you can see that hooks come with less boilerplate code but also offer less flexibility than plugins. We recommend using hooks for smaller customizations before diving deeper into the Jovo plugin architecture.
Hook Structure
The code snippet from above consists of the following elements:
app
: Make sure thatapp
is set. We recommend adding hooks to your app configuration files, for exampleapp.ts
.<middleware>
: This is the middleware this hook should use, for exampleresponse.output
. Find all middlewares in the RIDR docs. You can also addbefore
andafter
, e.g.before.response.output
.- Callback function with
jovo
: This is where you add the code that should get executed when the middleware triggers the hook.
Here is an example that logs the $output
array before it is turned into a native platform response:
// src/app.ts import { App, Jovo } from '@jovotech/framework'; // ... const app = new App({ /* app config */ }); app.hook('before.response.output', (jovo: Jovo): void => { console.log(jovo.$output); }); // Same hook without types app.hook('before.response.output', (jovo) => { console.log(jovo.$output); });
Learn more in the sections below:
Async Hooks
Hooks can also be async
, which can relevant for operations like API calls.
app.hook('<middleware>', async (jovo: Jovo): Promise<void> => { const response = await someApiCall(); // ... });
Hook Files
You can also store your hook functions in a separate file. Here is an example for sessionCount
:
// src/hooks/sessionCountHook.ts import { Jovo } from '@jovotech/framework'; export const sessionCountHook = (jovo: Jovo): void => { if (jovo.$session.isNew) { jovo.$user.data.sessionCount = (jovo.$user.data.sessionCount || 0) + 1; } };
In your app.ts
file, you can import and use the hook like this:
// src/app.ts import { App } from '@jovotech/framework'; import { sessionCountHook } from './hooks/sessionCount'; // ... const app = new App({ /* app config */ }); app.hook('before.response.output', sessionCountHook);
Example Hooks
New Session
This hook gets executed for every new session before a handler gets called. This can be useful for making API calls or cleaning up some data. See sessionCount
for an additional example.
// src/app.ts import { App, Jovo } from '@jovotech/framework'; // ... const app = new App({ /* app config */ }); app.hook('before.dialogue.start', (jovo: Jovo): void => { if (jovo.$session.isNew) { // ... } }); // Same hook without types app.hook('before.dialogue.start', (jovo) => { if (jovo.$session.isNew) { // ... } });
This hook can also be async
, which can relevant for operations like API calls.
app.hook('before.dialogue.start', async (jovo: Jovo): Promise<void> => { if (jovo.$session.isNew) { const response = await someApiCall(); // ... } });
If you're used to working with Jovo v3
: This hook can be used as a replacement of the NEW_SESSION
handler.
sessionCount
This hook stores a sessionCount
variable in the user database:
// src/app.ts import { App, Jovo } from '@jovotech/framework'; // ... const app = new App({ /* app config */ }); app.hook('before.dialogue.start', (jovo: Jovo): void => { if (jovo.$session.isNew) { jovo.$user.data.sessionCount = (jovo.$user.data.sessionCount || 0) + 1; } }); // Same hook without types app.hook('before.dialogue.start', (jovo) => { if (jovo.$session.isNew) { jovo.$user.data.sessionCount = (jovo.$user.data.sessionCount || 0) + 1; } });
New User
This hook gets executed for new users before a handler gets called. This can be useful for making API calls or adding some boilerplate data.
// src/app.ts import { App, Jovo } from '@jovotech/framework'; // ... const app = new App({ /* app config */ }); app.hook('before.dialogue.start', (jovo: Jovo): void => { if (jovo.$user.isNew) { // ... } }); // Same hook without types app.hook('before.dialogue.start', (jovo) => { if (jovo.$user.isNew) { // ... } });
This hook can also be async
, which can relevant for operations like API calls.
app.hook('before.dialogue.start', async (jovo: Jovo): Promise<void> => { if (jovo.$user.isNew) { const response = await someApiCall(); // ... } });
If you're used to working with Jovo v3
: This hook can be used as a replacement of the NEW_USER
handler.