Comprehensive guide to the Qwe Framework plugin system, including built-in plugins and custom plugin development.
The Qwe Framework plugin system provides a powerful way to extend application functionality through reusable components. Plugins follow a standardized interface and can register middleware, modify application behavior, and integrate with the framework's core features.
- 🔌 Standardized Interface: All plugins implement the same contract
- ⚡ Easy Integration: Simple registration with
app.plugin() - 🔧 Middleware Support: Plugins can register middleware functions
- 🎛️ Configurable: Options-based configuration for flexibility
- 🏗️ Extensible: Create custom plugins for specific needs
classDiagram
class QwePlugin {
<<interface>>
+string name
+string? version
+install(app: QweApp): void
}
class BasePlugin {
<<abstract>>
+string name
+string? version
+install(app: QweApp): void
}
class CorsPlugin {
+options: CorsOptions
+install(app: QweApp): void
}
class LoggerPlugin {
+options: LoggerOptions
+install(app: QweApp): void
}
class RateLimiterPlugin {
+options: RateLimiterOptions
+install(app: QweApp): void
}
QwePlugin <|.. BasePlugin
BasePlugin <|-- CorsPlugin
BasePlugin <|-- LoggerPlugin
BasePlugin <|-- RateLimiterPlugin
Cross-Origin Resource Sharing support:
import { cors } from 'qwe-framework';
// Basic usage
app.plugin(cors());
// With options
app.plugin(cors({
origin: ['https://example.com', 'https://app.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true
}));Request logging with multiple formats:
import { logger } from 'qwe-framework';
// Development format with colors
app.plugin(logger({ format: 'dev' }));
// Apache combined format
app.plugin(logger({ format: 'combined' }));Log Formats:
tiny:GET /users 200 - 15msdev: Color-coded format for developmentcombined: Apache combined format
Protect your API from abuse:
import { rateLimiter } from 'qwe-framework';
app.plugin(rateLimiter({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Max 100 requests per window
message: 'Too many requests, please try again later'
}));Add security headers:
import { security } from 'qwe-framework';
app.plugin(security({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"]
}
}
}));Headers Added:
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
- X-XSS-Protection: 1; mode=block
- Strict-Transport-Security
- Content-Security-Policy
Compress response data:
import { compression } from 'qwe-framework';
app.plugin(compression({
threshold: 1024, // Only compress responses > 1KB
level: 6 // Compression level (1-9)
}));Parse request bodies:
import { bodyParser } from 'qwe-framework';
app.plugin(bodyParser({
json: { limit: '10mb' },
urlencoded: { limit: '1mb', extended: true }
}));Automatic JWT validation:
import { jwtAuth } from 'qwe-framework';
app.plugin(jwtAuth({
secret: process.env.JWT_SECRET,
algorithms: ['HS256'],
unless: (qwe) => qwe.url.startsWith('/public')
}));import { createApp, cors, logger, rateLimiter } from 'qwe-framework';
const app = createApp();
// Register plugins in order
app.plugin(logger());
app.plugin(cors());
app.plugin(rateLimiter({ max: 100 }));
app.listen(3000);Plugin order matters! Recommended order:
app.plugin(logger()); // 1. Logging
app.plugin(cors()); // 2. CORS
app.plugin(security()); // 3. Security headers
app.plugin(compression()); // 4. Compression
app.plugin(bodyParser()); // 5. Body parsing
app.plugin(rateLimiter()); // 6. Rate limiting
app.plugin(jwtAuth()); // 7. Authenticationimport { BasePlugin, QweApp, QweMiddleware } from 'qwe-framework';
export interface MyPluginOptions {
enabled?: boolean;
message?: string;
}
export class MyPlugin extends BasePlugin {
name = 'my-plugin';
version = '1.0.0';
constructor(private options: MyPluginOptions = {}) {
super();
}
install(app: QweApp): void {
const middleware: QweMiddleware = async (qwe, next) => {
// Plugin logic here
if (this.options.enabled !== false) {
qwe.header('X-My-Plugin', 'active');
}
await next();
};
app.use(middleware);
}
}
// Factory function
export function myPlugin(options?: MyPluginOptions): MyPlugin {
return new MyPlugin(options);
}Request ID plugin for tracing:
import { BasePlugin, QweApp, QweMiddleware } from 'qwe-framework';
import { generateId } from 'qwe-framework';
export interface RequestIdOptions {
header?: string;
generator?: () => string;
}
export class RequestIdPlugin extends BasePlugin {
name = 'request-id';
version = '1.0.0';
constructor(private options: RequestIdOptions = {}) {
super();
}
install(app: QweApp): void {
const headerName = this.options.header || 'X-Request-ID';
const generator = this.options.generator || generateId;
const middleware: QweMiddleware = async (qwe, next) => {
const requestId = qwe.headers[headerName.toLowerCase()] || generator();
// Add to context
(qwe as any).requestId = requestId;
// Add to response header
qwe.header(headerName, requestId);
await next();
};
app.use(middleware);
}
}
export function requestId(options?: RequestIdOptions): RequestIdPlugin {
return new RequestIdPlugin(options);
}export class MetricsPlugin extends BasePlugin {
name = 'metrics';
version = '1.0.0';
private metrics: Array<{
method: string;
url: string;
statusCode: number;
duration: number;
timestamp: Date;
}> = [];
install(app: QweApp): void {
const middleware: QweMiddleware = async (qwe, next) => {
const startTime = Date.now();
await next();
this.metrics.push({
method: qwe.method,
url: qwe.url,
statusCode: qwe._getStatusCode(),
duration: Date.now() - startTime,
timestamp: new Date()
});
};
app.use(middleware);
// Add metrics endpoint
app.get('/metrics', (qwe) => {
const total = this.metrics.length;
const avgDuration = total > 0
? this.metrics.reduce((sum, m) => sum + m.duration, 0) / total
: 0;
return qwe.success('Metrics', {
totalRequests: total,
averageResponseTime: Math.round(avgDuration),
recentRequests: this.metrics.slice(-10)
});
});
}
}// ✅ Good: Single responsibility
class LoggerPlugin extends BasePlugin {
// Only handles logging
}
// ❌ Avoid: Multiple responsibilities
class LoggerCorsPlugin extends BasePlugin {
// Handles both logging and CORS - too complex
}// ✅ Good: Sensible defaults
export interface MyPluginOptions {
enabled?: boolean; // Default: true
level?: 'debug' | 'info'; // Default: 'info'
}
class MyPlugin extends BasePlugin {
constructor(private options: MyPluginOptions = {}) {
super();
this.options.enabled = options.enabled ?? true;
this.options.level = options.level ?? 'info';
}
}// ✅ Good: Graceful error handling
install(app: QweApp): void {
const middleware: QweMiddleware = async (qwe, next) => {
try {
await this.doSomething(qwe);
await next();
} catch (error) {
console.error(`${this.name} plugin error:`, error);
await next(); // Don't break the chain
}
};
app.use(middleware);
}// ✅ Good: Efficient operations
class PerformantPlugin extends BasePlugin {
private cache = new Map();
install(app: QweApp): void {
const middleware: QweMiddleware = async (qwe, next) => {
// Fast cache lookup
const cached = this.cache.get(qwe.url);
if (cached) {
qwe.header('X-Cache', 'HIT');
}
await next();
};
app.use(middleware);
}
}describe('MyPlugin', () => {
it('should add custom header', async () => {
const app = createApp();
app.plugin(new MyPlugin({ header: 'X-Test' }));
app.get('/test', (qwe) => qwe.success('ok'));
const response = await request(app)
.get('/test')
.expect(200);
expect(response.headers['x-test']).toBeDefined();
});
});The Qwe Framework plugin system provides a powerful and flexible way to extend application functionality. Whether using built-in plugins or creating custom ones, the standardized interface ensures consistency and maintainability.
- Use built-in plugins for common functionality
- Follow the plugin interface when creating custom plugins
- Order plugins correctly for proper execution flow
- Handle errors gracefully to maintain stability
- Keep plugins focused on single responsibilities
- 📖 Explore Utilities for built-in tools
- 🔐 Learn Authentication with JWT middleware
- ⚡ Add Real-time Features with WebSocket support
- 🗄️ Set up Database & ORM for data persistence
Need help? Check the API Reference or visit our GitHub repository for examples and support.