Hooks Guide
Overview
Hooks allow you to execute code at specific points in the request lifecycle. Gati automatically records hook definitions and execution traces for debugging and visualization.
Hook Types
Before Hooks
Execute before the handler runs.
typescript
export const handler: Handler = async (req, res, gctx, lctx) => {
lctx.before(async () => {
// Validate authentication
const token = req.headers.authorization;
if (!token) throw new Error('Unauthorized');
}, { id: 'auth-check', level: 'global' });
res.json({ message: 'Success' });
};After Hooks
Execute after the handler completes.
typescript
lctx.after(() => {
console.log('Request completed');
}, { id: 'log-completion', level: 'local' });Catch Hooks
Execute when errors occur.
typescript
lctx.catch((error) => {
console.error('Handler failed:', error);
}, { id: 'error-logger', level: 'global' });Hook Levels
- global - Runs for all requests
- route - Runs for specific route patterns
- local - Runs only for this handler
Hook Manifest Recording
Gati automatically extracts hook definitions during build time and stores them in manifests. This enables:
- Runtime introspection
- Debugging and visualization
- Performance analysis
- Execution order verification
Manifest Structure
Each handler's hooks are recorded in a manifest:
json
{
"handlerId": "users-[id]",
"hooks": [
{
"id": "auth-check",
"type": "before",
"level": "global",
"isAsync": true,
"timeout": 5000
}
],
"createdAt": 1706140800000,
"version": "1.0.0"
}Accessing Manifests
typescript
import { createManifestStore } from '@gati-framework/runtime';
const store = createManifestStore();
const manifest = store.getHookManifest('users-[id]');
console.log(`Handler has ${manifest?.hooks.length} hooks`);Runtime Recording
Enable hook execution recording for debugging:
typescript
import { HookOrchestrator } from '@gati-framework/runtime';
const orchestrator = new HookOrchestrator();
const playback = orchestrator.enablePlayback();
// Hooks are now recorded during executionAnalyzing Execution
typescript
playback.startRequest(requestId);
// ... request executes ...
playback.endRequest(requestId);
const trace = playback.getHookTrace(requestId);
trace?.traces.forEach(hook => {
console.log(`${hook.hookId}: ${hook.duration}ms`);
});Configuration
Timeout
Set maximum execution time:
typescript
lctx.before(async () => {
await fetchData();
}, { id: 'fetch', timeout: 3000 });Retries
Configure retry attempts:
typescript
lctx.before(async () => {
await unreliableOperation();
}, { id: 'retry-op', retries: 3 });Best Practices
- Use meaningful IDs - Makes debugging easier
- Set appropriate timeouts - Prevent hanging requests
- Keep hooks focused - Single responsibility per hook
- Use correct levels - Global for auth, local for specific logic
- Handle errors gracefully - Use catch hooks for cleanup