Skip to main content

Hooks types

Common: reusable logic Import: Allows to import excel files Send Notification (web) Scheduled Jobs Generate QR Code

Referencing a hook

Anywhere the platform asks for a hook identifier (for example customHookId in a custom query endpoint, or the before/after transaction hooks of a data source) you can use either:
  • the hook name, which is the readable identifier you gave it, or
  • the hook _id (the 24-character Mongo id shown in the hook detail).
Prefer the name: cloning an application or creating an environment copies the hooks with new _ids, so a reference by _id has to be remapped, while a reference by name keeps pointing at the local copy of the hook. A hook referenced this way only runs from its own table: customLead with customHookId can run the custom endpoint hooks of the Lead table, and the same applies to customEntityQuery and to the before/after transaction hooks of a mutation. Referencing a hook of another table returns Hook not found; call the operation of the hook’s table instead (for example customUsuario for a hook of Usuario). Hooks without a table still run from any table.
Anyone with the custom permission on a table can call its custom endpoint hooks, including anonymous users when the table grants anonymous access. A custom endpoint that is not meant to be public must check options.session and reject calls without a logged-in user.
The hook pickers in the designer (for example the import/export buttons) save the name. Configurations created before this change still hold the _id: they keep working as they are, and the picker shows the hook they point to. Selecting a hook again replaces the stored _id with the name. Configurations that still hold an _id can also be migrated in bulk: the platform can run a one-off migration for your application that rewrites the stored _ids (in features, feature versions and hook code) to the corresponding hook name. It is opt-in — ask the Codenull team to run it — and until it runs the existing references keep working exactly as they are.
Hook names are not enforced to be unique. If two hooks in the same application share a name, the reference resolves to the oldest one. The platform renames the duplicates automatically on startup (to <name>_2, <name>_3, …) so every hook stays reachable by a unique name.

Roles

Avoid hardcoding a role’s Id inside a hook. Roles live in the SQL Server Rol table — the Id itself is stable across clones and environments of the same application, but it isn’t readable or auditable in a hook’s code, and it’s specific to this app’s role catalog. Every role also has a Codigo, generated automatically from its name when the role is created and never changed afterwards — not even if the role is later renamed (see Authorization: Role Codigo). Prefer resolving roles by Codigo with getRoleByCodeAsync/getRolesByCodesAsync from ./utils/roleResolver: both are cached for 5 minutes, so calling them on every hook execution is safe. Both resolve the full row (Id, Nombre, Codigo) instead of just the Id, so you can read any other column of the role you just looked up — its current Nombre for a message, for example — without a second query.
getRolesByCodesAsync resolves several role codes in one call — useful to build a list of target role ids, for example when calling sendNotification with rolesTo:
Both functions return null (or omit that entry from the result) when there is no matching role — always treat that as deny, never as “no restriction configured”.

Hook context (instance and options)

Table hooks run as a callback with the signature async (instance, options) => { ... }:
  • instance: the record that triggered the hook. Access its fields with instance.dataValues.<Field>.
  • options.transaction: the active database transaction. Pass it to any additional query you run inside the hook (see Troubleshooting).
  • options.session?.userInfo: the authenticated user that triggered the event.
  • options.clientIp: IP address the request was made from, resolved from the reverse proxy headers. It can be null when there is no originating request (for example, scheduled jobs).
options.clientIp is informational (audit trails, logging). Do not use it as your only security control: IP addresses can be shared (NAT, corporate proxies) and change between requests.
The same options object (session, clientIp) is also available in before/after transaction hooks and in custom endpoint hooks.

Send Emails

  • From: Email address from where you want to send the email, It is not required if was configured in the application designer
  • To: Email address of the destination person
  • Subject: Subject of the email (text plain)
  • Message: The body of the email can be in HTML format or Text Plain.
To know more about the allowed email options please read nodemailer docs

Documentation for Sending Emails with Base64 Attachments (backend, hooks)

Override email provider settings

If you want to use a different mail provider you can pass that configuration as a second parameter of the sendEmail function

Async Logic

Querying and importing database model

To see more querying examples you can use any sequelize method: https://sequelize.org/v4/manual/tutorial/querying.html

Hooks Errors

This section will show you how to throw hook errors. The simplest way to throw an error looks like this

🔁Redirecting to a different Feature

If you want to allow the user to see a modal with a button that redirects to a new Feature, you should throw an exception using the CodenullError class with the following parameters: ✅ Example:
💡 type: "navigation" is mandatory to trigger the redirect behavior. The params array allows dynamic values to be passed to the destination feature
This is how the error message will look, once the user hit the “Aceptar/Ok” button will be redirected to the new feature
This requires the 1.1.9 version or greater

Executing Store Procedure from Hooks

You can know more about queries here https://sequelize.org/master/manual/raw-queries.html

Other Import examples

Troubleshooting

  • Timeout doing database operations on the afterSave or any other after hook
Solution: Add the transaction to the operation as the second parameter