CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-fastify

Fast and low overhead web framework for Node.js with powerful plugin architecture

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

hooks.mddocs/

Hook System

Lifecycle hooks for intercepting and modifying request/response processing at various stages.

Capabilities

Hook Registration

Add lifecycle hooks to intercept request/response processing.

/**
 * Add a lifecycle hook
 * @param hookName - Name of the lifecycle hook
 * @param handler - Hook handler function
 * @returns FastifyInstance for method chaining
 */
addHook(hookName: HookName, handler: HookHandler): FastifyInstance;
type HookName = 
  | 'onRequest'
  | 'preParsing' 
  | 'preValidation'
  | 'preHandler'
  | 'preSerialization'
  | 'onSend'
  | 'onResponse'
  | 'onTimeout'
  | 'onError'
  | 'onClose'
  | 'onReady'
  | 'onListen'
  | 'onRegister'
  | 'onRequestAbort'
  | 'preClose';

Request Lifecycle Hooks

onRequest Hook

First hook executed in the request lifecycle, before body parsing.

/**
 * Called at the beginning of request processing
 * @param request - Fastify request object (body is null)
 * @param reply - Fastify reply object
 * @param done - Callback function for completion
 */
type onRequestHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  done: (err?: Error) => void
) => void;

/**
 * Async version of onRequest hook
 */
type onRequestAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply
) => Promise<void>;

Usage Examples:

// Callback style
fastify.addHook('onRequest', (request, reply, done) => {
  // Log incoming requests
  console.log(`${request.method} ${request.url}`);
  done();
});

// Async style
fastify.addHook('onRequest', async (request, reply) => {
  // Add request ID
  request.id = generateRequestId();
  
  // Check rate limiting
  const allowed = await checkRateLimit(request.ip);
  if (!allowed) {
    reply.code(429).send({ error: 'Too Many Requests' });
  }
});

preParsing Hook

Called before request body parsing, allows payload modification.

/**
 * Called before body parsing, can modify payload
 * @param request - Fastify request object
 * @param reply - Fastify reply object
 * @param payload - Request payload stream
 * @param done - Callback with optional payload modification
 */
type preParsingHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  payload: RequestPayload,
  done: (err?: Error, payload?: RequestPayload) => void
) => void;

/**
 * Async version of preParsing hook
 */
type preParsingAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  payload: RequestPayload
) => Promise<RequestPayload | undefined>;

Usage Examples:

// Callback style - modify payload
fastify.addHook('preParsing', (request, reply, payload, done) => {
  // Decompress gzipped payload
  if (request.headers['content-encoding'] === 'gzip') {
    const gunzip = zlib.createGunzip();
    done(null, payload.pipe(gunzip));
  } else {
    done();
  }
});

// Async style - payload logging
fastify.addHook('preParsing', async (request, reply, payload) => {
  if (request.headers['content-type']?.includes('application/json')) {
    console.log('Processing JSON payload');
  }
});

preValidation Hook

Called after body parsing but before schema validation.

/**
 * Called after parsing, before validation
 * @param request - Fastify request object (body is parsed)
 * @param reply - Fastify reply object
 * @param done - Callback function for completion
 */
type preValidationHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  done: (err?: Error) => void
) => void;

/**
 * Async version of preValidation hook
 */
type preValidationAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply
) => Promise<void>;

Usage Examples:

// Input sanitization
fastify.addHook('preValidation', async (request, reply) => {
  if (request.body && typeof request.body === 'object') {
    // Sanitize string fields
    for (const [key, value] of Object.entries(request.body)) {
      if (typeof value === 'string') {
        request.body[key] = value.trim();
      }
    }
  }
});

// Authentication check
fastify.addHook('preValidation', async (request, reply) => {
  const token = request.headers.authorization?.replace('Bearer ', '');
  if (!token) {
    reply.code(401).send({ error: 'Missing token' });
    return;
  }
  
  try {
    const user = await verifyToken(token);
    request.user = user;
  } catch (err) {
    reply.code(401).send({ error: 'Invalid token' });
  }
});

preHandler Hook

Called after validation but before route handler execution.

/**
 * Called after validation, before handler
 * @param request - Fastify request object (validated)
 * @param reply - Fastify reply object
 * @param done - Callback function for completion
 */
type preHandlerHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  done: (err?: Error) => void
) => void;

/**
 * Async version of preHandler hook
 */
type preHandlerAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply
) => Promise<void>;

Usage Examples:

// Authorization check
fastify.addHook('preHandler', async (request, reply) => {
  const requiredRole = request.routeConfig?.requiredRole;
  if (requiredRole && (!request.user || !request.user.roles.includes(requiredRole))) {
    reply.code(403).send({ error: 'Insufficient permissions' });
  }
});

// Request context setup
fastify.addHook('preHandler', async (request, reply) => {
  request.context = {
    requestId: request.id,
    userId: request.user?.id,
    timestamp: Date.now()
  };
});

Response Lifecycle Hooks

preSerialization Hook

Called before response serialization, can modify payload.

/**
 * Called before response serialization
 * @param request - Fastify request object
 * @param reply - Fastify reply object
 * @param payload - Response payload to be serialized
 * @param done - Callback with optional payload modification
 */
type preSerializationHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  payload: any,
  done: (err?: Error, payload?: any) => void
) => void;

/**
 * Async version of preSerialization hook
 */
type preSerializationAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  payload: any
) => Promise<any>;

Usage Examples:

// Add metadata to all responses
fastify.addHook('preSerialization', async (request, reply, payload) => {
  if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
    return {
      ...payload,
      _metadata: {
        requestId: request.id,
        timestamp: new Date().toISOString(),
        version: '1.0'
      }
    };
  }
  return payload;
});

// Response filtering based on user permissions
fastify.addHook('preSerialization', async (request, reply, payload) => {
  if (request.user && payload?.sensitive_data) {
    if (!request.user.roles.includes('admin')) {
      delete payload.sensitive_data;
    }
  }
  return payload;
});

onSend Hook

Called before sending the response, can modify the serialized payload.

/**
 * Called before sending response
 * @param request - Fastify request object
 * @param reply - Fastify reply object  
 * @param payload - Serialized response payload
 * @param done - Callback with optional payload modification
 */
type onSendHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  payload: string | Buffer,
  done: (err?: Error, payload?: string | Buffer) => void
) => void;

/**
 * Async version of onSend hook
 */
type onSendAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  payload: string | Buffer
) => Promise<string | Buffer>;

Usage Examples:

// Compress responses
fastify.addHook('onSend', async (request, reply, payload) => {
  if (request.headers['accept-encoding']?.includes('gzip') && 
      payload.length > 1024) {
    reply.header('content-encoding', 'gzip');
    return zlib.gzipSync(payload);
  }
  return payload;
});

// Response logging
fastify.addHook('onSend', (request, reply, payload, done) => {
  console.log(`Response ${reply.statusCode} for ${request.method} ${request.url}`);
  done();
});

onResponse Hook

Called after the response is sent to the client.

/**
 * Called after response is sent
 * @param request - Fastify request object
 * @param reply - Fastify reply object
 * @param done - Callback function for completion
 */
type onResponseHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  done: (err?: Error) => void
) => void;

/**
 * Async version of onResponse hook
 */
type onResponseAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply
) => Promise<void>;

Usage Examples:

// Access logging
fastify.addHook('onResponse', async (request, reply) => {
  const responseTime = Date.now() - request.startTime;
  console.log(`${request.method} ${request.url} ${reply.statusCode} ${responseTime}ms`);
});

// Metrics collection
fastify.addHook('onResponse', async (request, reply) => {
  metrics.incrementCounter('http_requests_total', {
    method: request.method,
    status_code: reply.statusCode,
    route: request.routerPath
  });
  
  metrics.recordHistogram('http_request_duration_seconds', 
    (Date.now() - request.startTime) / 1000
  );
});

Error and Timeout Hooks

onError Hook

Called when an error occurs during request processing.

/**
 * Called when an error occurs
 * @param request - Fastify request object
 * @param reply - Fastify reply object
 * @param error - Error that occurred
 * @param done - Callback function for completion
 */
type onErrorHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  error: FastifyError,
  done: (err?: Error) => void
) => void;

/**
 * Async version of onError hook
 */
type onErrorAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  error: FastifyError
) => Promise<void>;

Usage Examples:

// Error logging
fastify.addHook('onError', async (request, reply, error) => {
  console.error(`Error in ${request.method} ${request.url}:`, error);
  
  // Send error to monitoring service
  await errorTracker.recordError(error, {
    requestId: request.id,
    userId: request.user?.id,
    route: request.routerPath
  });
});

// Custom error responses
fastify.addHook('onError', (request, reply, error, done) => {
  if (error.code === 'FST_ERR_VALIDATION') {
    reply.code(400).send({
      error: 'Validation Error',
      details: error.validation
    });
  }
  done();
});

onTimeout Hook

Called when a request times out.

/**
 * Called when request times out
 * @param request - Fastify request object
 * @param reply - Fastify reply object
 * @param done - Callback function for completion
 */
type onTimeoutHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply,
  done: (err?: Error) => void
) => void;

/**
 * Async version of onTimeout hook
 */
type onTimeoutAsyncHookHandler = (
  request: FastifyRequest,
  reply: FastifyReply
) => Promise<void>;

Usage Examples:

// Timeout logging
fastify.addHook('onTimeout', async (request, reply) => {
  console.warn(`Request timeout: ${request.method} ${request.url}`);
  
  // Log slow requests for optimization
  await logSlowRequest({
    method: request.method,
    url: request.url,
    params: request.params,
    query: request.query
  });
});

onRequestAbort Hook

Called when a client aborts the request.

/**
 * Called when request is aborted by client
 * @param request - Fastify request object
 * @param done - Callback function for completion
 */
type onRequestAbortHookHandler = (
  request: FastifyRequest,
  done: (err?: Error) => void
) => void;

/**
 * Async version of onRequestAbort hook
 */
type onRequestAbortAsyncHookHandler = (
  request: FastifyRequest
) => Promise<void>;

Usage Examples:

// Cleanup on abort
fastify.addHook('onRequestAbort', async (request) => {
  console.log(`Request aborted: ${request.method} ${request.url}`);
  
  // Cancel any ongoing operations
  if (request.operationId) {
    await cancelOperation(request.operationId);
  }
});

Application Lifecycle Hooks

onReady Hook

Called when the application is ready and all plugins are loaded.

/**
 * Called when application is ready
 * @param done - Callback function for completion
 */
type onReadyHookHandler = (done: (err?: Error) => void) => void;

/**
 * Async version of onReady hook
 */
type onReadyAsyncHookHandler = () => Promise<void>;

Usage Examples:

// Database initialization
fastify.addHook('onReady', async () => {
  await database.connect();
  console.log('Database connected');
});

// Health check setup
fastify.addHook('onReady', async () => {
  setInterval(async () => {
    await performHealthCheck();
  }, 30000);
});

onListen Hook

Called when the server starts listening.

/**
 * Called when server starts listening
 * @param done - Callback function for completion
 */
type onListenHookHandler = (done: (err?: Error) => void) => void;

/**
 * Async version of onListen hook
 */
type onListenAsyncHookHandler = () => Promise<void>;

Usage Examples:

// Startup notifications
fastify.addHook('onListen', async () => {
  console.log('Server is now listening');
  await notifyServiceRegistry();
});

onClose Hook

Called when the server is closing.

/**
 * Called when server is closing
 * @param instance - Fastify instance being closed
 * @param done - Callback function for completion
 */
type onCloseHookHandler = (
  instance: FastifyInstance,
  done: (err?: Error) => void
) => void;

/**
 * Async version of onClose hook
 */
type onCloseAsyncHookHandler = (instance: FastifyInstance) => Promise<void>;

Usage Examples:

// Cleanup resources
fastify.addHook('onClose', async (instance) => {
  await database.disconnect();
  await redis.quit();
  console.log('Resources cleaned up');
});

preClose Hook

Called before the server starts closing.

/**
 * Called before server starts closing
 * @param done - Callback function for completion
 */
type preCloseHookHandler = (done: (err?: Error) => void) => void;

/**
 * Async version of preClose hook
 */
type preCloseAsyncHookHandler = () => Promise<void>;

onRegister Hook

Called when a plugin is registered.

/**
 * Called when a plugin is registered
 * @param instance - FastifyInstance where plugin is being registered
 * @param done - Callback function for completion
 */
type onRegisterHookHandler = (
  instance: FastifyInstance,
  done: (err?: Error) => void
) => void;

Usage Examples:

// Track plugin registration
fastify.addHook('onRegister', (instance, done) => {
  console.log(`Plugin registered: ${instance.pluginName}`);
  done();
});

docs

content-parsing.md

decoration.md

error-handling.md

hooks.md

index.md

plugins.md

routing.md

schema.md

server-lifecycle.md

testing.md

tile.json