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

decoration.mddocs/

Decoration System

Extend Fastify instances, requests, and replies with custom properties and methods.

Capabilities

Instance Decoration

Add properties and methods to the Fastify instance.

/**
 * Add property or method to Fastify instance
 * @param name - Property name
 * @param value - Property value or method function
 * @param dependencies - Array of required decorators
 * @returns FastifyInstance for method chaining
 */
decorate(name: string, value: any, dependencies?: string[]): FastifyInstance;

/**
 * Check if decorator exists on instance
 * @param name - Decorator name to check
 * @returns Boolean indicating if decorator exists
 */
hasDecorator(name: string): boolean;

/**
 * Get decorator value from instance
 * @param name - Decorator name
 * @returns Decorator value
 */
getDecorator(name: string): any;

Usage Examples:

// Add utility method
fastify.decorate('utils', {
  formatDate: (date) => date.toISOString(),
  generateId: () => Math.random().toString(36).substr(2, 9),
  validateEmail: (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
});

// Use decorated utility
fastify.get('/current-time', async (request, reply) => {
  return {
    time: fastify.utils.formatDate(new Date()),
    id: fastify.utils.generateId()
  };
});

// Add database connection
fastify.decorate('db', database);

// Use in routes
fastify.get('/users', async (request, reply) => {
  const users = await fastify.db.query('SELECT * FROM users');
  return users;
});

Request Decoration

Add properties and methods to request objects.

/**
 * Add property or method to request objects
 * @param name - Property name
 * @param value - Property value or method function
 * @param dependencies - Array of required decorators
 * @returns FastifyInstance for method chaining
 */
decorateRequest(name: string, value: any, dependencies?: string[]): FastifyInstance;

/**
 * Check if request decorator exists
 * @param name - Decorator name to check
 * @returns Boolean indicating if decorator exists
 */
hasRequestDecorator(name: string): boolean;

Usage Examples:

// Add user context to requests
fastify.decorateRequest('user', null);
fastify.decorateRequest('getUserRole', function() {
  return this.user?.role || 'guest';
});

// Use in hooks
fastify.addHook('preHandler', async (request, reply) => {
  const token = request.headers.authorization?.replace('Bearer ', '');
  if (token) {
    request.user = await verifyToken(token);
  }
});

// Use in route handlers
fastify.get('/profile', async (request, reply) => {
  if (!request.user) {
    reply.code(401).send({ error: 'Unauthorized' });
    return;
  }
  
  return {
    user: request.user,
    role: request.getUserRole()
  };
});

// Add request tracking
fastify.decorateRequest('startTime', null);
fastify.decorateRequest('getElapsed', function() {
  return Date.now() - this.startTime;
});

fastify.addHook('onRequest', (request, reply, done) => {
  request.startTime = Date.now();
  done();
});

Reply Decoration

Add properties and methods to reply objects.

/**
 * Add property or method to reply objects
 * @param name - Property name
 * @param value - Property value or method function
 * @param dependencies - Array of required decorators
 * @returns FastifyInstance for method chaining
 */
decorateReply(name: string, value: any, dependencies?: string[]): FastifyInstance;

/**
 * Check if reply decorator exists  
 * @param name - Decorator name to check
 * @returns Boolean indicating if decorator exists
 */
hasReplyDecorator(name: string): boolean;

Usage Examples:

// Add success response helper
fastify.decorateReply('success', function(data, message = 'Success') {
  return this.send({
    success: true,
    message,
    data,
    timestamp: new Date().toISOString()
  });
});

// Add error response helper
fastify.decorateReply('error', function(message, code = 400) {
  return this.code(code).send({
    success: false,
    error: message,
    timestamp: new Date().toISOString()
  });
});

// Use in route handlers
fastify.get('/users/:id', async (request, reply) => {
  try {
    const user = await findUser(request.params.id);
    if (!user) {
      return reply.error('User not found', 404);
    }
    return reply.success(user, 'User retrieved successfully');
  } catch (err) {
    return reply.error('Failed to retrieve user', 500);
  }
});

// Add pagination helper
fastify.decorateReply('paginated', function(data, page, limit, total) {
  return this.send({
    data,
    pagination: {
      page,
      limit,
      total,
      pages: Math.ceil(total / limit)
    }
  });
});

Decoration Dependencies

Manage decorator dependencies and load order.

// Decorator with dependencies
fastify.decorate('config', appConfig);
fastify.decorate('database', databaseConnection, ['config']);
fastify.decorate('cache', cacheInstance, ['config', 'database']);

// Fastify ensures decorators are available in the right order
fastify.get('/status', async (request, reply) => {
  return {
    database: await fastify.database.status(),
    cache: await fastify.cache.status(),
    config: fastify.config.environment
  };
});

// Plugin with dependencies
async function databasePlugin(fastify, options) {
  // This plugin requires 'config' decorator
  if (!fastify.hasDecorator('config')) {
    throw new Error('Config decorator required');
  }
  
  fastify.decorate('db', createDatabase(fastify.config.database));
}

// Register with dependencies
await fastify.register(configPlugin);
await fastify.register(databasePlugin); // Will have config available

Getter/Setter Decorators

Create decorators with getter and setter functions.

// Decorator with getter/setter
fastify.decorate('currentUser', {
  getter() {
    return this.user || null;
  },
  setter(user) {
    this.user = user;
    this.log.info({ userId: user.id }, 'User context set');
  }
});

// Usage in middleware
fastify.addHook('preHandler', async (request, reply) => {
  const token = request.headers.authorization;
  if (token) {
    const user = await validateToken(token);
    fastify.currentUser = user; // Uses setter
  }
});

// Usage in routes
fastify.get('/me', async (request, reply) => {
  const user = fastify.currentUser; // Uses getter
  if (!user) {
    reply.code(401).send({ error: 'Not authenticated' });
    return;
  }
  return user;
});

Plugin-scoped Decorations

Decorators are scoped to plugin contexts for encapsulation.

// Parent context
fastify.decorate('parentHelper', () => 'from parent');

await fastify.register(async function childPlugin(fastify) {
  // Child has access to parent decorators
  console.log(fastify.parentHelper()); // "from parent"
  
  // Child-specific decorator
  fastify.decorate('childHelper', () => 'from child');
  
  fastify.get('/child-route', (request, reply) => {
    return {
      parent: fastify.parentHelper(),
      child: fastify.childHelper()
    };
  });
});

// Parent cannot access child decorators
// console.log(fastify.childHelper()); // Error!

Advanced Decoration Patterns

Complex decoration scenarios and best practices.

// Service container pattern
fastify.decorate('services', {});

// Register services
fastify.services.user = {
  async findById(id) {
    return await userRepository.findById(id);
  },
  async create(data) {
    return await userRepository.create(data);
  }
};

fastify.services.email = {
  async send(to, subject, body) {
    return await emailProvider.send(to, subject, body);
  }
};

// Factory pattern for decorators
function createApiDecorator(baseUrl, headers = {}) {
  return {
    async get(path) {
      const response = await fetch(`${baseUrl}${path}`, { headers });
      return response.json();
    },
    async post(path, data) {
      const response = await fetch(`${baseUrl}${path}`, {
        method: 'POST',
        headers: { ...headers, 'Content-Type': 'application/json' },
        body: JSON.stringify(data)
      });
      return response.json();
    }
  };
}

// Use factory
fastify.decorate('api', createApiDecorator('https://api.example.com', {
  'Authorization': 'Bearer token'
}));

// Conditional decorations
if (process.env.NODE_ENV === 'development') {
  fastify.decorate('debug', {
    logRequest: (request) => console.log(request.method, request.url),
    logResponse: (reply) => console.log('Response:', reply.statusCode)
  });
} else {
  fastify.decorate('debug', {
    logRequest: () => {},
    logResponse: () => {}
  });
}

Decoration Type Safety (TypeScript)

Extend types for decorated properties.

// Extend Fastify types
declare module 'fastify' {
  interface FastifyInstance {
    config: AppConfig;
    db: Database;
    services: ServiceContainer;
  }
  
  interface FastifyRequest {
    user?: User;
    startTime: number;
    getUserRole(): string;
  }
  
  interface FastifyReply {
    success(data: any, message?: string): FastifyReply;
    error(message: string, code?: number): FastifyReply;
  }
}

// Use with full type safety
fastify.get('/users', async (request, reply) => {
  const users = await fastify.db.users.findAll(); // Typed
  return reply.success(users); // Typed
});

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