A web application framework for Node.js with enterprise-grade development capabilities through a plugin-based architecture and convention-over-configuration approach
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Foundation classes for building controllers, services, subscriptions, and utility components in Egg.js applications.
Base class that provides context-aware functionality for controllers, services, and other context-bound components.
/**
* BaseContextClass is a base class that can be extended for context-aware components
* It's instantiated at the context level and provides access to app and ctx
*/
class BaseContextClass extends EggCoreBaseContextClass {
/** Request context instance */
ctx: Context;
/** Application instance */
app: EggApplicationCore;
/** Service container */
service: BaseContextClass;
/** Component path name for logging */
pathName?: string;
/** Context-aware logger */
get logger(): BaseContextLogger;
}Usage Examples:
// Controller example
export default class UserController extends BaseContextClass {
async show() {
const { ctx, app } = this;
const userId = ctx.params.id;
// Access services through context
const user = await ctx.service.user.findById(userId);
// Use logger with automatic context information
this.logger.info('User viewed: %s', userId);
ctx.body = { user };
}
}
// Service example
export default class UserService extends BaseContextClass {
async findById(id: string) {
const { ctx } = this;
// Access database through app
const user = await this.app.mysql.get('users', { id });
if (!user) {
this.logger.warn('User not found: %s', id);
ctx.throw(404, 'User not found');
}
return user;
}
async create(userData: CreateUserData) {
const { ctx, app } = this;
// Validate using context helpers
ctx.validate(userCreateRule, userData);
// Use logger with service context
this.logger.info('Creating user: %s', userData.email);
const user = await app.mysql.insert('users', userData);
return user;
}
}Alias for BaseContextClass specifically for controllers.
/**
* Controller class - alias for BaseContextClass
* Used for handling HTTP requests and responses
*/
const Controller = BaseContextClass;Usage Examples:
import { Controller } from 'egg';
export default class HomeController extends Controller {
async index() {
const { ctx } = this;
// Access request data
const { page = 1, limit = 10 } = ctx.query;
// Use services
const posts = await ctx.service.post.list({ page, limit });
// Set response
ctx.body = {
posts,
pagination: {
page: Number(page),
limit: Number(limit),
total: posts.length
}
};
// Log request
this.logger.info('Home page requested with page=%s, limit=%s', page, limit);
}
}Alias for BaseContextClass specifically for services.
/**
* Service class - alias for BaseContextClass
* Used for business logic and data access
*/
const Service = BaseContextClass;Usage Examples:
import { Service } from 'egg';
export default class PostService extends Service {
async list(options: { page: number; limit: number }) {
const { ctx, app } = this;
const { page, limit } = options;
// Calculate offset
const offset = (page - 1) * limit;
// Database query
const posts = await app.mysql.select('posts', {
where: { status: 'published' },
orders: [['created_at', 'desc']],
limit,
offset
});
// Log operation
this.logger.info('Listed %d posts (page %d)', posts.length, page);
return posts;
}
async create(postData: CreatePostData) {
const { ctx, app } = this;
// Validate data
const errors = await ctx.validate(postCreateRule, postData);
if (errors) {
ctx.throw(422, 'Validation failed', { errors });
}
// Create post
const result = await app.mysql.insert('posts', {
...postData,
created_at: new Date(),
updated_at: new Date()
});
this.logger.info('Created post: %s', result.insertId);
return result;
}
}Alias for BaseContextClass specifically for scheduled tasks and subscriptions.
/**
* Subscription class - alias for BaseContextClass
* Used for scheduled tasks and background subscriptions
*/
const Subscription = BaseContextClass;Usage Examples:
import { Subscription } from 'egg';
export default class CleanupSubscription extends Subscription {
// Subscription configuration
static get schedule() {
return {
cron: '0 2 * * *', // Run at 2 AM daily
type: 'worker', // Run on all workers
env: ['prod'] // Only in production
};
}
async subscribe() {
const { ctx, app } = this;
this.logger.info('Starting cleanup job');
try {
// Clean expired sessions
await app.redis.del('session:*:expired');
// Clean old logs
const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
await app.mysql.delete('logs', {
created_at: { $lt: cutoffDate }
});
this.logger.info('Cleanup job completed successfully');
} catch (error) {
this.logger.error('Cleanup job failed:', error);
throw error;
}
}
}Utility class providing common helper functions accessible via context.
/**
* Helper class providing utility functions
* Available as ctx.helper in all context-aware components
*/
class Helper extends BaseContextClass {
/**
* Generate URL path for route name and parameters
* @param name - Router route name
* @param params - Route parameters and query string
* @returns URL path without host
*/
pathFor(name: string, params: Record<string, any>): string;
/**
* Generate full URL for route name and parameters
* @param name - Router route name
* @param params - Route parameters and query string
* @returns Full URL with host
*/
urlFor(name: string, params: Record<string, any>): string;
}Usage Examples:
// In controller
export default class LinkController extends Controller {
async generateLinks() {
const { ctx } = this;
// Generate path (relative URL)
const profilePath = ctx.helper.pathFor('user.profile', {
id: 123,
tab: 'settings'
});
// Result: /user/123/profile?tab=settings
// Generate full URL
const profileUrl = ctx.helper.urlFor('user.profile', {
id: 123,
tab: 'settings'
});
// Result: http://localhost:7001/user/123/profile?tab=settings
ctx.body = {
profilePath,
profileUrl
};
}
}
// In service or other components
export default class EmailService extends Service {
async sendPasswordReset(user: User) {
const { ctx } = this;
// Generate reset link
const resetUrl = ctx.helper.urlFor('auth.reset', {
token: user.resetToken
});
await this.sendEmail(user.email, 'Password Reset', {
resetUrl,
userName: user.name
});
this.logger.info('Sent password reset email to %s', user.email);
}
}Helpers can be extended in your application for project-specific utilities.
Usage Examples:
// app/extend/helper.js - Application helper extensions
export default {
// Format currency
formatCurrency(amount: number, currency = 'USD') {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency
}).format(amount);
},
// Generate secure token
generateToken(length = 32) {
const { ctx } = this;
return ctx.app.crypto.randomBytes(length).toString('hex');
},
// Sanitize HTML
sanitizeHtml(html: string) {
// Use sanitization library
return sanitize(html);
}
};
// Usage in controllers
export default class ProductController extends Controller {
async show() {
const { ctx } = this;
const product = await ctx.service.product.findById(ctx.params.id);
ctx.body = {
...product,
formattedPrice: ctx.helper.formatCurrency(product.price),
safeDescription: ctx.helper.sanitizeHtml(product.description)
};
}
}interface BaseContextLogger {
info(message: string, ...args: any[]): void;
warn(message: string, ...args: any[]): void;
error(message: string, ...args: any[]): void;
debug(message: string, ...args: any[]): void;
}
interface CreateUserData {
name: string;
email: string;
password: string;
}
interface CreatePostData {
title: string;
content: string;
status: 'draft' | 'published';
author_id: number;
}Install with Tessl CLI
npx tessl i tessl/npm-egg