Core components
Server core
Hooks (FeathersJS)
27 min
overview the hooks component is a powerful feature of the ir engine's server core that enables the addition of processing logic before, after, or during error handling of service method executions it provides a structured way to implement cross cutting concerns such as authentication, validation, and data transformation without cluttering the core service logic by leveraging the hook system of feathersjs, this component creates a modular, reusable approach to handling common patterns across different services this chapter explores the implementation, types, and usage of hooks within the ir engine core concepts hook functions hooks are specialized functions that process service method calls function signature hooks receive a context object and return it (possibly modified) execution points hooks can run before, after, or during error handling of service methods context access hooks have access to the service, method, parameters, and data modification capability hooks can modify the incoming data or outgoing results chain of responsibility multiple hooks can be executed in sequence this functional approach creates a flexible system for extending service behavior hook types the system defines three main types of hooks before hooks execute before the service method runs validate incoming data authorize the request transform or augment the data set up additional context for the service method after hooks execute after the service method completes successfully transform the result data remove sensitive information trigger side effects like notifications log successful operations error hooks execute when an error occurs in before hooks, the service method, or after hooks format error responses log detailed error information attempt error recovery clean up resources these types provide a comprehensive framework for controlling the service method lifecycle hook context the hook context object contains all information about the service call service information references to the service and application method details the method being called and its parameters data access the incoming data and outgoing results user information the authenticated user (if available) error details information about any errors that occurred this context enables hooks to make informed decisions and modifications implementation hook function structure hook functions follow a standard structure // example hook function import { hook, hookcontext } from '@feathersjs/feathers'; / example hook that adds a timestamp to incoming data @param context hook context @returns modified context / export const addtimestamp hook = async (context hookcontext) => { // only run on create, update, or patch methods if (\['create', 'update', 'patch'] includes(context method)) { // add createdat for new records if (context method === 'create') { context data createdat = new date(); } // always add updatedat context data updatedat = new date(); } // always return the context return context; }; this function receives the hook context as its parameter checks the method to determine if it should run modifies the data by adding timestamp fields returns the modified context hook registration hooks are registered in dedicated hook configuration files // example hook configuration file src/user/user hooks ts import { authenticate } from '@feathersjs/authentication/hooks'; import { hooks as schemahooks } from '@feathersjs/schema'; import { addtimestamp } from ' / /hooks/add timestamp'; import { validateuserdata } from ' /validators'; import { logerror } from ' / /hooks/log error'; / hook configuration for the user service / export default { before { // hooks that run before all methods all \[ authenticate('jwt') ], // method specific hooks find \[ schemahooks validatequery(validateuserquery) ], get \[], create \[ schemahooks validatedata(validateuserdata), addtimestamp ], update \[ schemahooks validatedata(validateuserdata), addtimestamp ], patch \[ schemahooks validatedata(validateuserpatchdata), addtimestamp ], remove \[] }, after { all \[ // remove password from all responses context => { if (context result) { const removepassword = result => { if (result password) { delete result password; } return result; }; // handle both single results and arrays if (array isarray(context result data)) { context result data = context result data map(removepassword); } else if (array isarray(context result)) { context result = context result map(removepassword); } else { context result = removepassword(context result); } } return context; } ], find \[], get \[], create \[], update \[], patch \[], remove \[] }, error { all \[ logerror ], find \[], get \[], create \[], update \[], patch \[], remove \[] } }; this configuration imports hook functions from various sources organizes hooks by type (before, after, error) and method specifies the execution order of hooks for each method includes both reusable hooks and inline hook functions hook application hooks are applied to services during registration // example service registration src/user/user service ts import { application } from ' / /declarations'; import { userservice } from ' /user class'; import hooks from ' /user hooks'; / configures the user service @param app feathers application / export default function(app application) void { // create the service app use('/users', new userservice({ model app get('knexclient'), name 'user', paginate app get('paginate') })); // get the registered service const service = app service('users'); // set up hooks service hooks(hooks); } this function creates and registers the service retrieves the registered service applies the hook configuration to the service common hooks the system includes several common hooks for reuse authentication hook // simplified from src/hooks/authenticate ts import { authenticate as feathersauthenticate } from '@feathersjs/authentication/hooks'; import { hookcontext } from '@feathersjs/feathers'; / authentication hook that supports multiple strategies @param strategies authentication strategies to use @returns hook function / export const authenticate = ( strategies string\[]) => { return async (context hookcontext) => { // use the feathers authentication hook await feathersauthenticate( strategies)(context); // additional custom logic if needed return context; }; }; this hook wraps the feathers authentication hook supports multiple authentication strategies can add custom logic after authentication validation hook // simplified from src/hooks/validate schema ts import ajv from 'ajv'; import { hookcontext } from '@feathersjs/feathers'; / validates data against a json schema @param schema json schema to validate against @param datapath path to the data in the context (default 'data') @returns hook function / export const validateschema = (schema object, datapath = 'data') => { const ajv = new ajv({ allerrors true }); const validate = ajv compile(schema); return async (context hookcontext) => { // get the data to validate const data = datapath === 'data' ? context data context params query; // validate the data const valid = validate(data); // if validation fails, throw an error if (!valid) { const errors = validate errors || \[]; throw new error(`validation failed ${errors map(e => e message) join(', ')}`); } return context; }; }; this hook compiles a json schema for validation validates data or query parameters throws an error with detailed messages if validation fails error logging hook // simplified from src/hooks/log error ts import { hookcontext } from '@feathersjs/feathers'; / logs errors that occur during service method execution @param context hook context @returns modified context / export const logerror = async (context hookcontext) => { // get the logger from the app const logger = context app get('logger'); // log the error with context information logger error(`error in ${context path} ${context method} `, { error { message context error message, stack context error stack, code context error code }, params context params, data context data }); // continue with the error return context; }; this hook retrieves the logger from the application logs detailed error information includes context data for debugging allows the error to continue propagating hook workflow the complete hook workflow follows this sequence sequencediagram participant client as client code participant service as service method participant beforehooks as before hooks participant afterhooks as after hooks participant errorhooks as error hooks client >>beforehooks call service method alt before hooks execute successfully beforehooks >>service modified context alt service method executes successfully service >>afterhooks result in context alt after hooks execute successfully afterhooks >>client final result else error in after hooks afterhooks >>errorhooks error in context errorhooks >>client error response end else error in service method service >>errorhooks error in context errorhooks >>client error response end else error in before hooks beforehooks >>errorhooks error in context errorhooks >>client error response end this diagram illustrates before hooks execute first, potentially modifying the context if before hooks succeed, the service method executes if the service method succeeds, after hooks execute if any step fails, error hooks execute the final result or error is returned to the client hook context properties the hook context object contains several important properties core properties // hook context structure interface hookcontext { // application and service information app application; // the feathers application service any; // the service this hook is running on path string; // the service path (e g , 'users') method string; // the service method (e g , 'create') type 'before' | 'after' | 'error'; // the hook type // method parameters params { query? any; // query parameters for find provider? string; // how the service was called (e g , 'rest') user? any; // the authenticated user \[key string] any; // other parameters }; // method specific properties id? string | number; // the id for get, update, patch, remove data? any; // the data for create, update, patch result? any; // the result (for after hooks) error? error; // the error (for error hooks) // hook utilities statuscode? number; // http status code for the response dispatch? boolean; // whether to dispatch events } these properties provide complete information about the service call allow hooks to access and modify the request and response enable hooks to make decisions based on the context support different types of service methods context modification hooks can modify various aspects of the context // example of context modification in hooks const modifycontext = async (context hookcontext) => { // modify data (for before hooks) if (context data) { context data modifiedby = context params user? id; } // modify query (for before hooks) if (context params query) { context params query active = true; } // modify result (for after hooks) if (context result) { if (array isarray(context result data)) { context result data foreach(item => { delete item secretfield; }); } else { delete context result secretfield; } } // add custom parameters context params customvalue = 'some value'; return context; }; this example shows modifying incoming data in before hooks adjusting query parameters in before hooks transforming results in after hooks adding custom parameters for later hooks or the service method integration with other components the hooks system integrates with several other components of the server core services hooks extend service functionality // example of service integration import { authenticate } from ' / /hooks/authenticate'; import { validateschema } from ' / /hooks/validate schema'; import { userschema } from ' /user schema'; // in user hooks ts export default { before { create \[ authenticate('jwt'), validateschema(userschema) ] } }; // in user service ts export default function(app application) void { app use('/users', new userservice(options)); app service('users') hooks(hooks); } this integration adds authentication to service methods validates incoming data against schemas keeps service implementation focused on core logic separates cross cutting concerns from business logic authentication & authorization hooks implement security checks // example of authentication integration import { authenticate } from '@feathersjs/authentication/hooks'; import { isprovider } from 'feathers hooks common'; import { verifyscope } from ' / /hooks/verify scope'; // in project hooks ts export default { before { all \[ // only authenticate external requests isprovider('external') ? authenticate('jwt') null, // verify the user has the required scope context => { if (context params provider && context params user) { return verifyscope('project', 'write')(context); } return context; } ] } }; this integration authenticates users before allowing access verifies authorization scopes for operations applies security checks only when needed creates a layered security approach database management hooks enhance database operations // example of database integration import { softdelete } from ' / /hooks/soft delete'; import { addtimestamp } from ' / /hooks/add timestamp'; // in document hooks ts export default { before { create \[ addtimestamp ], update \[ addtimestamp ], patch \[ addtimestamp ], remove \[ // use soft delete instead of actual deletion softdelete ] } }; this integration adds timestamps to database records implements soft deletion instead of hard deletion ensures consistent data handling maintains data integrity benefits of hooks the hooks component provides several key advantages separation of concerns isolates cross cutting concerns from core service logic reusability enables hook functions to be shared across multiple services modularity allows functionality to be added or removed without changing service code composability supports combining multiple hooks to create complex behaviors testability makes it easier to test hooks and services independently consistency ensures common patterns are applied uniformly across services extensibility provides a framework for adding new functionality to existing services these benefits make hooks an essential component for creating maintainable and secure applications next steps with an understanding of how hooks extend service functionality, the next chapter explores how they are used to implement authentication and authorization next authentication & authorization docid\ syox53gmah1g1zy6btzw4