Skip to content

Latest commit

 

History

History
805 lines (629 loc) · 18.6 KB

File metadata and controls

805 lines (629 loc) · 18.6 KB

Utilities Reference

Comprehensive guide to all built-in utility functions and classes in the Qwe Framework.

Table of Contents

Overview

Qwe Framework provides a rich set of built-in utilities that eliminate the need for external dependencies. All utilities are accessible through the qwe context object or as standalone functions.

Built-in Utilities

  • Validation: Schema validation for request data
  • Hashing: Password hashing and verification
  • JWT: JSON Web Token operations
  • File Upload: File handling and validation
  • Template Response: Standardized API responses
  • ID Generation: Various ID generation methods
  • Caching: Memory and Redis-based caching
  • Sessions: Session management with multiple stores
  • Metrics: Performance monitoring and analytics
  • Testing: Built-in testing framework
  • Configuration: Type-safe configuration management

Validation

Powerful schema validation for request data, query parameters, and more.

Basic Usage

// Using validation through context
app.post('/users', async (qwe) => {
  const userSchema = qwe.validate.object({
    name: qwe.validate.string().min(2).max(50),
    email: qwe.validate.string().email(),
    age: qwe.validate.number().min(18).max(100)
  });

  const validation = await qwe.validate(userSchema, qwe.body);
  if (!validation.success) {
    return qwe.badRequest('Validation failed', validation.errors);
  }

  return qwe.success('Valid data', validation.data);
});

Standalone Usage

import { createValidator } from 'qwe-framework';

const validator = createValidator();

const schema = validator.object({
  username: validator.string().min(3).max(20).alphanum(),
  password: validator.string().min(8).pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/),
  confirmPassword: validator.string().equal('password')
});

Validation Types

String Validation

const stringSchema = validator.string()
  .min(3)                    // Minimum length
  .max(50)                   // Maximum length
  .email()                   // Email format
  .url()                     // URL format
  .pattern(/^[A-Z]+$/)       // Regex pattern
  .alphanum()                // Alphanumeric only
  .trim()                    // Trim whitespace
  .lowercase()               // Convert to lowercase
  .uppercase()               // Convert to uppercase
  .required();               // Required field

Number Validation

const numberSchema = validator.number()
  .min(0)                    // Minimum value
  .max(100)                  // Maximum value
  .integer()                 // Integer only
  .positive()                // Positive numbers
  .negative()                // Negative numbers
  .multiple(5)               // Multiple of 5
  .precision(2);             // Decimal precision

Array Validation

const arraySchema = validator.array()
  .items(validator.string())  // Array item type
  .min(1)                    // Minimum items
  .max(10)                   // Maximum items
  .unique()                  // Unique items only
  .length(5);                // Exact length

Object Validation

const objectSchema = validator.object({
  name: validator.string().required(),
  settings: validator.object({
    theme: validator.string().valid(['light', 'dark']),
    notifications: validator.boolean()
  }).optional()
});

Custom Validation

const customValidator = validator.string().custom((value) => {
  if (!value.includes('@company.com')) {
    throw new Error('Must be company email');
  }
  return value;
});

Authentication & Security

Password Hashing

Secure password hashing using built-in cryptographic functions:

// Using through context
app.post('/register', async (qwe) => {
  const { password } = qwe.body;
  
  // Hash password
  const hashedPassword = await qwe.hash.hash(password);
  
  // Save user with hashed password
  const user = await saveUser({ 
    ...userData, 
    password: hashedPassword 
  });
  
  return qwe.created('User registered', user);
});

app.post('/login', async (qwe) => {
  const { email, password } = qwe.body;
  const user = await findUserByEmail(email);
  
  // Verify password
  const isValid = await qwe.hash.verify(password, user.password);
  if (!isValid) {
    return qwe.unauthorized('Invalid credentials');
  }
  
  return qwe.success('Login successful', { user });
});

Standalone Usage

import { createHasher } from 'qwe-framework';

const hasher = createHasher();

// Hash password
const hashed = await hasher.hash('password123');

// Verify password
const isValid = await hasher.verify('password123', hashed);

// Synchronous scrypt hashing
const salt = 'randomsalt';
const hash = hasher.scrypt('password123', salt);

JWT Operations

JSON Web Token creation and verification:

// Using through context
app.post('/login', async (qwe) => {
  const user = await authenticateUser(credentials);
  
  // Create JWT token
  const token = qwe.jwt.sign(
    { userId: user.id, role: user.role },
    'your-secret-key',
    { expiresIn: '24h' }
  );
  
  return qwe.success('Login successful', { token, user });
});

// Verify JWT token
app.get('/protected', async (qwe) => {
  const token = qwe.headers.authorization?.replace('Bearer ', '');
  
  try {
    const decoded = qwe.jwt.verify(token, 'your-secret-key');
    qwe.user = decoded; // Add user to context
  } catch (error) {
    return qwe.unauthorized('Invalid token');
  }
  
  return qwe.success('Protected data', { user: qwe.user });
});

Standalone Usage

import { createJWT } from 'qwe-framework';

const jwt = createJWT();

// Sign token
const token = jwt.sign(
  { userId: 123, role: 'admin' },
  'secret-key',
  { expiresIn: '1h', issuer: 'my-app' }
);

// Verify token
const decoded = jwt.verify(token, 'secret-key');

// Decode without verification
const payload = jwt.decode(token);

Data Processing

JSON Parser

Enhanced JSON parsing with error handling:

import { createJSONParser } from 'qwe-framework';

const parser = createJSONParser({
  limit: '10mb',
  strict: true,
  reviver: (key, value) => {
    // Custom JSON reviver
    if (key === 'date') return new Date(value);
    return value;
  }
});

app.use(async (qwe, next) => {
  if (qwe.headers['content-type']?.includes('application/json')) {
    try {
      qwe.body = await parser.parse(qwe.rawBody);
    } catch (error) {
      return qwe.badRequest('Invalid JSON');
    }
  }
  await next();
});

Cookie Management

Secure cookie handling:

import { createCookieManager } from 'qwe-framework';

const cookies = createCookieManager({
  secret: 'cookie-secret',
  secure: true,
  httpOnly: true,
  sameSite: 'strict'
});

app.get('/set-cookie', (qwe) => {
  // Set secure cookie
  cookies.set(qwe, 'sessionId', 'abc123', {
    maxAge: 24 * 60 * 60 * 1000, // 24 hours
    path: '/',
    domain: '.example.com'
  });
  
  return qwe.success('Cookie set');
});

app.get('/get-cookie', (qwe) => {
  const sessionId = cookies.get(qwe, 'sessionId');
  return qwe.success('Cookie value', { sessionId });
});

Template Responses

Standardized API response formats:

import { createTemplateResponse } from 'qwe-framework';

const templates = createTemplateResponse({
  includeTimestamp: true,
  includePath: true,
  customFields: {
    version: '1.0.0',
    server: 'qwe-api'
  }
});

// Using templates directly
app.get('/users', (qwe) => {
  const response = templates.success('Users retrieved', users, {
    total: users.length,
    page: 1
  });
  return qwe.json(response);
});

// Using context methods (recommended)
app.get('/users', (qwe) => {
  return qwe.success('Users retrieved', users, {
    total: users.length,
    page: 1
  });
});

File Operations

File Upload

Handle file uploads with validation:

import { createUploadHandler } from 'qwe-framework';

const uploader = createUploadHandler({
  uploadDir: './uploads',
  maxFileSize: 5 * 1024 * 1024, // 5MB
  allowedTypes: ['image/jpeg', 'image/png', 'image/gif'],
  maxFiles: 3,
  preserveExtension: true
});

app.post('/upload', async (qwe) => {
  try {
    const files = await uploader.handle(qwe);
    
    const uploadedFiles = files.map(file => ({
      id: qwe.generateId(),
      filename: file.filename,
      originalName: file.originalName,
      size: file.size,
      mimetype: file.mimetype,
      url: `/uploads/${file.filename}`
    }));
    
    return qwe.success('Files uploaded', uploadedFiles);
  } catch (error) {
    return qwe.badRequest('Upload failed', { error: error.message });
  }
});

Specialized Upload Handlers

import { createImageUpload, createDocumentUpload } from 'qwe-framework';

// Image uploads with resizing
const imageUpload = createImageUpload({
  uploadDir: './uploads/images',
  maxFileSize: 2 * 1024 * 1024,
  resize: {
    width: 800,
    height: 600,
    quality: 80
  },
  generateThumbnail: true
});

// Document uploads
const docUpload = createDocumentUpload({
  uploadDir: './uploads/docs',
  allowedTypes: ['application/pdf', 'application/msword'],
  maxFileSize: 10 * 1024 * 1024,
  virus_scan: true
});

Performance & Monitoring

Metrics Collection

Track application performance:

import { createMetrics } from 'qwe-framework';

const metrics = createMetrics({
  collectSystemMetrics: true,
  collectHttpMetrics: true,
  collectCustomMetrics: true
});

// Counter metric
const requestCounter = metrics.counter('http_requests_total', {
  help: 'Total number of HTTP requests',
  labelNames: ['method', 'status_code']
});

// Gauge metric
const activeConnections = metrics.gauge('active_connections', {
  help: 'Number of active connections'
});

// Histogram metric
const requestDuration = metrics.histogram('http_request_duration_seconds', {
  help: 'HTTP request duration in seconds',
  buckets: [0.1, 0.5, 1, 2, 5]
});

app.use(async (qwe, next) => {
  const startTime = Date.now();
  
  await next();
  
  const duration = (Date.now() - startTime) / 1000;
  const statusCode = qwe._getStatusCode().toString();
  
  requestCounter.inc({ method: qwe.method, status_code: statusCode });
  requestDuration.observe(duration);
});

Performance Monitor

Monitor application performance:

import { createPerformanceMonitor } from 'qwe-framework';

const monitor = createPerformanceMonitor({
  collectInterval: 5000, // 5 seconds
  thresholds: {
    cpuUsage: 80,
    memoryUsage: 90,
    responseTime: 1000
  }
});

monitor.on('threshold_exceeded', (metric, value, threshold) => {
  console.warn(`Performance threshold exceeded: ${metric} = ${value} (threshold: ${threshold})`);
});

app.get('/performance', (qwe) => {
  const stats = monitor.getStats();
  return qwe.success('Performance stats', stats);
});

Caching

Built-in caching with multiple backends:

import { createCache } from 'qwe-framework';

// Memory cache
const memoryCache = createCache('memory', {
  maxSize: 1000,
  ttl: 300 // 5 minutes default TTL
});

// Redis cache
const redisCache = createCache('redis', {
  host: 'localhost',
  port: 6379,
  password: 'redis-password',
  db: 0
});

// Usage
app.get('/expensive-data/:id', async (qwe) => {
  const cacheKey = `expensive-data:${qwe.params.id}`;
  
  // Try cache first
  let data = await memoryCache.get(cacheKey);
  if (data) {
    qwe.header('X-Cache', 'HIT');
    return qwe.success('Data retrieved', data);
  }
  
  // Compute expensive data
  data = await computeExpensiveData(qwe.params.id);
  
  // Cache for 10 minutes
  await memoryCache.set(cacheKey, data, 600);
  
  qwe.header('X-Cache', 'MISS');
  return qwe.success('Data retrieved', data);
});

Development Tools

ID Generation

Various ID generation methods:

import { 
  generateId, 
  generateShortId, 
  generateUUID, 
  generateNanoId,
  generateSecureToken,
  generateAlphanumeric 
} from 'qwe-framework';

// Default ID (timestamp-based)
const id = generateId(); // "1703123456789-abc123"

// Short ID
const shortId = generateShortId(); // "Xy9Kq2"

// UUID v4
const uuid = generateUUID(); // "550e8400-e29b-41d4-a716-446655440000"

// Nano ID
const nanoId = generateNanoId(10); // "V1StGXR8_Z"

// Secure token
const token = generateSecureToken(32); // 32-byte secure random token

// Alphanumeric ID
const alphaId = generateAlphanumeric(8); // "Abc123Xy"

// Using through context
app.post('/users', (qwe) => {
  const user = {
    id: qwe.generateId(),
    ...qwe.body,
    createdAt: new Date().toISOString()
  };
  
  return qwe.created('User created', user);
});

Hot Reload

Development server with hot reload:

import { createHotReload, createDevServer } from 'qwe-framework';

// Hot reload for file changes
const hotReload = createHotReload({
  watchDir: './src',
  extensions: ['.ts', '.js'],
  ignored: ['node_modules', '.git'],
  onReload: () => {
    console.log('🔄 Application reloaded');
  }
});

// Development server
const devServer = createDevServer({
  port: 3000,
  hotReload: true,
  livereload: true,
  open: true, // Open browser automatically
  proxy: {
    '/api': 'http://localhost:8080'
  }
});

if (process.env.NODE_ENV === 'development') {
  hotReload.watch();
  devServer.start();
}

Testing Framework

Built-in testing utilities:

import { 
  createTestFramework, 
  createTestClient,
  describe, 
  it, 
  beforeEach, 
  afterEach,
  assert 
} from 'qwe-framework';

const testFramework = createTestFramework();
const client = createTestClient(app);

describe('User API', () => {
  beforeEach(async () => {
    await setupTestData();
  });

  afterEach(async () => {
    await cleanupTestData();
  });

  it('should create user', async () => {
    const response = await client
      .post('/users')
      .send({
        name: 'John Doe',
        email: 'john@example.com'
      })
      .expect(201);

    assert.equal(response.body.success, true);
    assert.equal(response.body.data.name, 'John Doe');
  });

  it('should validate user input', async () => {
    const response = await client
      .post('/users')
      .send({ name: '' })
      .expect(400);

    assert.equal(response.body.success, false);
    assert.ok(response.body.errors);
  });
});

Configuration Management

Type-safe configuration management:

import { createConfig } from 'qwe-framework';

const config = createConfig({
  sources: ['env', 'file', 'args'],
  schema: {
    port: { type: 'number', default: 3000 },
    host: { type: 'string', default: 'localhost' },
    database: {
      type: 'object',
      properties: {
        url: { type: 'string', required: true },
        pool: { type: 'number', default: 10 }
      }
    },
    jwt: {
      type: 'object',
      properties: {
        secret: { type: 'string', required: true },
        expiresIn: { type: 'string', default: '24h' }
      }
    }
  }
});

// Access configuration
const port = config.get('port'); // Type-safe: number
const dbUrl = config.get('database.url'); // Type-safe: string
const jwtSecret = config.get('jwt.secret'); // Type-safe: string

// Environment-specific configs
const isDev = config.get('NODE_ENV') === 'development';
const isProd = config.get('NODE_ENV') === 'production';

// Watch for changes
config.watch('database.pool', (newValue, oldValue) => {
  console.log(`Database pool size changed: ${oldValue}${newValue}`);
});

Best Practices

1. Use Context Utilities

// ✅ Good: Use context utilities
app.post('/users', async (qwe) => {
  const validation = await qwe.validate(schema, qwe.body);
  const hashedPassword = await qwe.hash.hash(password);
  const token = qwe.jwt.sign(payload);
  const id = qwe.generateId();
  
  return qwe.success('User created');
});

// ❌ Avoid: External dependencies
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const { v4: uuid } = require('uuid');

2. Error Handling

// ✅ Good: Proper error handling
app.post('/users', async (qwe) => {
  try {
    const validation = await qwe.validate(userSchema, qwe.body);
    if (!validation.success) {
      return qwe.badRequest('Validation failed', validation.errors);
    }
    
    const user = await createUser(validation.data);
    return qwe.created('User created', user);
  } catch (error) {
    console.error('User creation failed:', error);
    return qwe.internalServerError('Failed to create user');
  }
});

3. Validation Schemas

// ✅ Good: Reusable schemas
const userSchema = qwe.validate.object({
  name: qwe.validate.string().min(2).max(50),
  email: qwe.validate.string().email(),
  age: qwe.validate.number().min(18).max(100)
});

const updateUserSchema = userSchema.partial(); // Make all fields optional

// ❌ Avoid: Inline validation
const validation = await qwe.validate(
  qwe.validate.object({ name: qwe.validate.string() }),
  qwe.body
);

4. Configuration

// ✅ Good: Centralized configuration
const config = createConfig({
  schema: {
    upload: {
      type: 'object',
      properties: {
        maxSize: { type: 'number', default: 5242880 },
        allowedTypes: { type: 'array', default: ['image/*'] }
      }
    }
  }
});

const uploader = createUploadHandler({
  maxFileSize: config.get('upload.maxSize'),
  allowedTypes: config.get('upload.allowedTypes')
});

// ❌ Avoid: Hardcoded values
const uploader = createUploadHandler({
  maxFileSize: 5242880,
  allowedTypes: ['image/jpeg', 'image/png']
});

Conclusion

Qwe Framework's built-in utilities provide everything you need to build robust web applications without external dependencies. The utilities are designed to work seamlessly together and provide type-safe, performant solutions for common development tasks.

Key Benefits

  • Zero Dependencies: All utilities built-in
  • Type Safety: Full TypeScript support
  • Performance: Optimized implementations
  • Consistency: Unified API across all utilities
  • Flexibility: Configurable for different use cases

Next Steps


Need help? Check the API Reference for complete documentation.