0.0.2 • Published 5 months ago

@sens-tools/base-server v0.0.2

Weekly downloads
-
License
UNLICENSED
Repository
-
Last release
5 months ago

Sens Node.js Base Server

A powerful Express server package that provides a robust foundation for building secure and well-documented APIs with Swagger integration, authentication, rate limiting, and more.

Features

  • 🛡️ Security Features

    • Helmet for security headers
    • CORS support with configurable options
    • Rate limiting to prevent abuse
    • Basic authentication for Swagger UI
    • Toobusy protection against server overload
  • 📚 Swagger Integration

    • Multiple theme support (classic, dark, material, monokai, muted, newspaper, outline, shadow)
    • Instance-specific documentation
    • Basic authentication protection
    • Customizable base URL and API path
  • 🚀 Express Enhancements

    • Instance-based routing
    • Standardized response helper
    • Error handling middleware
    • Morgan logging with configurable formats
    • Body parsing middleware

Installation

pnpm add @sens-tools/base-server

Quick Start

import { SensServer } from '@sens-tools/base-server';

// Create your Swagger documentation
const swaggerJson = {
  openapi: '3.0.0',
  info: {
    title: 'Your API',
    version: '1.0.0',
  },
  paths: {
    '/users': {
      get: {
        responses: {
          '200': {
            description: 'List of users',
          },
        },
      },
    },
  },
};

// Initialize the server with configuration
const server = new SensServer({
  swaggerJson,
  iotaBaseUrl: 'your-domain.com',
  apiPath: '/api',
  swaggerPath: '/docs',
  swaggerUsername: 'admin',
  swaggerPassword: 'secret',
  morgan: 'dev',
  rateLimitWindowMs: 15 * 60 * 1000, // 15 minutes
  rateLimitMaxRequests: 100,
  toobusyMaxLag: 100,
  toobusyInterval: 500,
  corsOptions: {
    origin: ['https://your-frontend.com'],
    methods: ['GET', 'POST'],
  },
});

// Get the router to add your routes
const router = server.getRouter();

// Add your routes
router.get('/users', (req, res) => {
  res.api.ok({ users: [] });
});

// Start the server
server.start(3000);

Available Components

import SensServer, { handleEndpointResult } from '@sens-tools/base-server';

Exported Types

The package exports the following TypeScript types:

import type {
  SensConfig, // Complete server configuration with all required fields
  SensConfigInput, // Input configuration interface for SensServer constructor
  InstanceConfig, // Configuration for API instances
  EndpointResultType, // Type for endpoint result data (string | number | Record<string, unknown> | Array<unknown>)
  EndpointFunction, // Type for endpoint functions that return a Result type
  ErrorResponse, // Standard error response format
} from '@sens-tools/base-server';

Configuration Options

The SensConfigInput interface accepts the following configuration:

interface SensConfigInput {
  swaggerJson: any; // Your Swagger documentation
  iotaBaseUrl: string; // Base URL for your API
  corsOptions?: CorsOptions; // Optional CORS configuration
  swaggerUsername?: string; // Username for Swagger UI basic auth
  swaggerPassword?: string; // Password for Swagger UI basic auth
  morgan?: 'combined' | 'common' | 'dev' | 'short' | 'tiny'; // Logging format
  toobusyMaxLag?: number; // Maximum event loop lag in milliseconds
  toobusyInterval?: number; // Check interval in milliseconds
  rateLimitWindowMs?: number; // Rate limit window in milliseconds
  rateLimitMaxRequests?: number; // Maximum requests per window
  apiPath?: string; // API path prefix (defaults to '/api')
  swaggerPath?: string; // Swagger UI path (defaults to '/docs')
}

SensServer Components and Functionality

After initializing a new SensServer instance, you have access to several powerful components and methods:

Available Methods

// Get the router to add your routes
const router = server.getRouter();

// Get the Express app instance for advanced customization
const app = server.getApp();

// Get the current server configuration
const config = server.getConfig();

// Start the server
await server.start(port);

// Shutdown the server gracefully
await server.shutdown();

// Restart the server
await server.restart(port);

Request Context

Each request automatically includes instance and authentication information through req.api:

req.api.iota.instance; // The instance identifier
req.api.iota.token; // The authentication token

Response Helpers

The server provides a rich set of response helpers through res.api:

res.api.ok(data); // 200 OK
res.api.created(data); // 201 Created
res.api.accepted(data); // 202 Accepted
res.api.noContent(); // 204 No Content
res.api.badRequest(error); // 400 Bad Request
res.api.unauthorized(error); // 401 Unauthorized
res.api.forbidden(error); // 403 Forbidden
res.api.notFound(error); // 404 Not Found
res.api.methodNotAllowed(error); // 405 Method Not Allowed
res.api.requestTimeout(error); // 408 Request Timeout
res.api.conflict(error); // 409 Conflict
res.api.gone(error); // 410 Gone
res.api.unprocessableEntity(error); // 422 Unprocessable Entity
res.api.internalServerError(error); // 500 Internal Server Error
res.api.serviceUnavailable(error); // 503 Service Unavailable
res.api.tooBusy(error); // 503 Too Busy
res.api.gatewayTimeout(error); // 504 Gateway Timeout

Error Handling with handleEndpointResult

The SensServer provides a powerful error handling system through the handleEndpointResult utility. This utility helps standardize error handling across your API endpoints and ensures consistent error responses.

Basic Usage

import { handleEndpointResult } from '@sens-tools/base-server';

// Define your endpoint function
const getUsers = async (req: Request, res: Response) => {
  const users = await getUsersFromDatabase();
  if (users.isErr()) {
    return err(users.error);
  }
  return ok(users.value);
};

// Use handleEndpointResult in your route
router.get('/users', (req, res) => {
  handleEndpointResult(req, res, getUsers);
});

Error Response Format

All errors follow a consistent format:

{
  error: string,             // Error code/type
  error_description: string, // Human-readable error message
  details?: any              // Optional additional error details (e.g., validation errors)
}

Error Types Handled

The system automatically handles various types of errors:

  1. Validation Errors (Zod)

    {
      error: 'Validation Error',
      error_description: 'The request data failed validation',
      details: [
        {
          path: 'user.email',
          message: 'Invalid email format',
          code: 'invalid_string'
        }
      ]
    }
  2. API Errors

    {
      error: 'API Error',
      error_description: 'Custom error message',
      statusCode: 400 // Optional status code
    }
  3. Standard Errors

    {
      error: 'Internal Server Error',
      error_description: 'An unexpected error occurred'
    }

Example with Error Handling

import { handleEndpointResult } from '@sens-tools/base-server';
import { ok, err } from 'neverthrow';

const createUser = async (req: Request, res: Response) => {
  try {
    // Validate input
    const validation = userSchema.safeParse(req.body);
    if (!validation.success) {
      return err(validation.error);
    }

    // Create user
    const user = await db.users.create(validation.data);
    if (!user) {
      return err({
        error: 'User Creation Failed',
        error_description: 'Failed to create user in database',
      });
    }

    // Return success
    return ok(user);
  } catch (error) {
    return err(error);
  }
};

router.post('/users', (req, res) => {
  handleEndpointResult(req, res, createUser);
});

Swagger Documentation

Access your API documentation through multiple endpoints:

  • Default theme: /${swaggerPath}
  • Theme-specific: /${swaggerPath}/{theme}
  • Instance-specific JSON: /${swaggerPath}/{theme}/{instance}/swagger.json

Available themes:

  • classic (default)
  • dark
  • material
  • monokai
  • muted
  • newspaper
  • outline
  • shadow

Development

  1. Clone the repository
  2. Install dependencies:

    pnpm install
  3. Build the project:

    pnpm build

Version Management

This project uses Bumpp for version management. See BUMPP.md for detailed instructions.

Contributing

  1. Fork the repository
  2. Create your feature branch
  3. Commit your changes
  4. Push to the branch
  5. Create a new Pull Request