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;
}