Plugins System
Extend Azura with built-in and custom plugins.
Plugin Architecture
Azura's plugin system allows you to extend the framework's functionality in a modular way. Plugins can add middleware, routes, hooks, and more to your application.
import { Plugin } from '@azura/framework';
// Plugin interface
interface Plugin<API = unknown, Options = unknown> {
name: string;
register(app: AzuraServer, opts: Options): API;
dependencies?: string[];
}
Each plugin has a unique name, a register function that receives the server instance and options, and an optional list of dependencies.
Built-in Plugins
Azura comes with several built-in plugins that you can use out of the box:
CORS Plugin
import { AzuraServer, cors } from '@azura/framework';
const app = new AzuraServer();
// Register the CORS plugin
app.registerPlugin(cors, {
origin: '*', // Allow all origins
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
});
Compression Plugin
import { AzuraServer, compress } from '@azura/framework';
const app = new AzuraServer();
// Register the compression plugin
app.registerPlugin(compress, {
threshold: 1024 // Only compress responses larger than 1KB
});
Rate Limiting Plugin
import { AzuraServer, rateLimit } from '@azura/framework';
const app = new AzuraServer();
// Register the rate limiting plugin
app.registerPlugin(rateLimit, {
limit: 100, // 100 requests
timeframe: 60000 // per minute (60000ms)
});
Static Files Plugin
import { AzuraServer, serveStatic } from '@azura/framework';
const app = new AzuraServer();
// Register the static files plugin
app.registerPlugin(serveStatic, {
root: './public' // Serve files from the public directory
});
Metrics Plugin
import { AzuraServer, metrics, metricsEndpoint } from '@azura/framework';
const app = new AzuraServer();
// Register the metrics plugin
app.registerPlugin(metrics);
// Add a metrics endpoint
app.get('/metrics', metricsEndpoint());
Health Check Plugin
import { AzuraServer, health } from '@azura/framework';
const app = new AzuraServer();
// Register the health check plugin
app.get('/health', health());
Cache Plugin
import { AzuraServer, LRUCache } from '@azura/framework';
const app = new AzuraServer();
// Create an LRU cache
const cache = new LRUCache(1000); // Cache up to 1000 items
// Use the cache in a route
app.get('/cached-data', (req, res) => {
const cacheKey = req.path;
const cachedData = cache.get(cacheKey);
if (cachedData) {
return res.json(cachedData);
}
// Get fresh data
const data = { /* ... */ };
// Cache the data
cache.set(cacheKey, data);
res.json(data);
});
Creating Custom Plugins
You can create your own plugins to extend Azura's functionality:
import { AzuraServer } from '@azura/framework';
// Define a plugin
const loggerPlugin = {
name: 'logger',
register: (app, options = { level: 'info' }) => {
// Add middleware to log requests
app.use((req, res, next) => {
const start = Date.now();
// Add a listener for when the response finishes
res.on('finish', () => {
const duration = Date.now() - start;
console.log(
`[${options.level.toUpperCase()}] ${req.method} ${req.path} - ${res.statusCode} (${duration}ms)`
);
});
next();
});
// Return an API that other plugins can use
return {
log: (message: string, level = options.level) => {
console.log(`[${level.toUpperCase()}] ${message}`);
}
};
}
};
// Use the plugin
const app = new AzuraServer();
const logger = app.registerPlugin(loggerPlugin, { level: 'debug' });
// Use the plugin's API
logger.log('Server started', 'info');
Plugin Dependencies
Plugins can depend on other plugins. The plugin loader will automatically load dependencies in the correct order:
import { AzuraServer } from '@azura/framework';
// Define plugins
const databasePlugin = {
name: 'database',
register: (app, options) => {
// Connect to database...
return {
query: (sql: string) => {
// Execute query...
return [];
}
};
}
};
const userPlugin = {
name: 'users',
dependencies: ['database'], // This plugin depends on the database plugin
register: (app, options) => {
// Get the database plugin
const db = app.plugins.get('database');
// Add routes that use the database
app.get('/users', (req, res) => {
const users = db.query('SELECT * FROM users');
res.json(users);
});
return {
getUser: (id: string) => {
return db.query('SELECT * FROM users WHERE id = ?', [id])[0];
}
};
}
};
// Register plugins
const app = new AzuraServer();
app.registerPlugin(databasePlugin, { /* database options */ });
app.registerPlugin(userPlugin);
In this example, the userPlugin
depends on the databasePlugin
. The plugin loader will ensure that databasePlugin
is registered before userPlugin
.
Plugin Loader
Azura uses a PluginLoader
class to manage plugins and their dependencies:
import { AzuraServer, PluginLoader } from '@azura/framework';
// Create a server
const app = new AzuraServer();
// The server has a built-in plugin loader
const plugins = app.plugins;
// Register a plugin
const loggerApi = plugins.register('logger', loggerPlugin, { level: 'debug' });
// Get a plugin's API
const logger = plugins.get('logger');
logger.log('Hello, world!');
The plugin loader ensures that plugins are only registered once, even if they are requested multiple times by different dependencies.
Lifecycle Hooks Plugin
The lifecycle hooks plugin allows you to execute code at various stages of the request/response cycle:
import { AzuraServer, Lifecycle, HookType } from '@azura/framework';
const app = new AzuraServer();
// Get the lifecycle plugin
const lifecycle = app.plugins.get('lifecycle');
// Add hooks
lifecycle.add('onRequest', (ctx) => {
console.log('Request received:', ctx.request.url);
});
lifecycle.add('preHandler', (ctx) => {
console.log('Before handler execution');
});
lifecycle.add('onResponse', (ctx) => {
console.log('Response sent:', ctx.response.statusCode);
});
// Available hook types:
// - onRequest: Triggered when a request is received
// - preParsing: Before body parsing
// - preValidation: Before input validation
// - preHandler: Before route handler execution
// - onResponse: Before sending the response
// - onError: When an error occurs
Plugin Best Practices
- Give your plugins descriptive names
- Document your plugin's API and options
- Use dependencies to ensure plugins are loaded in the correct order
- Return an API object from your plugin's register function
- Handle errors gracefully within your plugins
- Make your plugins configurable through options