@syncafricabs/shared-kernel-core

v1.0.0

Published

Uniform API responses, robust validation, zero boilerplate — for Node.js.

Downloads

109

Readme

@syncafricabs/shared-kernel-core

Uniform API responses, robust validation, zero boilerplate — for Node.js and TypeScript. Available from npm.

Overview

This library provides a complete solution for building consistent RESTful APIs with:

  • Standardized API Responses - Consistent JSON envelope format across your application
  • Validation Utilities - Comprehensive field validation helpers
  • Custom Exceptions - Pre-defined exception types for common scenarios
  • Global Exception Handling - Automatic HTTP status code mapping for Express
  • Utility Classes - Common helpers (slugify, truncate, currency formatting, etc.)

Installation

Package: @syncafricabs/shared-kernel-core

npm install @syncafricabs/shared-kernel-core
yarn add @syncafricabs/shared-kernel-core
pnpm add @syncafricabs/shared-kernel-core

API Response Format

All responses follow this standardized JSON envelope:

{
  "code": 200,
  "message": "Operation successful",
  "success": true,
  "data": { ... }
}

| Field | Type | Description | |-------|------|-------------| | code | number | HTTP status code (200, 201, 400, 401, 403, 404, 409, 500, etc.) | | message | string | Human-readable message | | success | boolean | true for successful operations, false for failures | | data | any | Response payload (null for error responses) |

Response Examples

Success Responses

// 200 OK - Resource retrieved
{
  "code": 200,
  "message": "User retrieved successfully",
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "email": "[email protected]"
  }
}
// 201 Created - Resource created
{
  "code": 201,
  "message": "User created successfully",
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "name": "Jane Doe",
    "email": "[email protected]"
  }
}
// 204 No Content - Deleted successfully
{
  "code": 204,
  "message": "User deleted successfully",
  "success": true,
  "data": null
}

Client Error Responses

// 400 Bad Request - Validation failed
{
  "code": 400,
  "message": "Validation failed",
  "success": false,
  "data": {
    "email": "Email is required",
    "password": "Password must be at least 8 characters long"
  }
}
// 401 Unauthorized - Invalid credentials
{
  "code": 401,
  "message": "Invalid credentials",
  "success": false,
  "data": null
}
// 403 Forbidden - Access denied
{
  "code": 403,
  "message": "Access denied",
  "success": false,
  "data": null
}
// 404 Not Found - Resource not found
{
  "code": 404,
  "message": "User not found",
  "success": false,
  "data": null
}
// 409 Conflict - Resource already exists
{
  "code": 409,
  "message": "User already exists",
  "success": false,
  "data": null
}
// 410 Gone - Expired resource or link
{
  "code": 410,
  "message": "Invitation link has expired",
  "success": false,
  "data": null
}
// 422 Unprocessable Entity - Business rule violation
{
  "code": 422,
  "message": "Insufficient funds",
  "success": false,
  "data": null
}
// 429 Too Many Requests - Rate limit exceeded
{
  "code": 429,
  "message": "Too many login attempts. Please try again later.",
  "success": false,
  "data": null
}
// 423 Locked - Account or resource locked
{
  "code": 423,
  "message": "Account is locked due to suspicious activity",
  "success": false,
  "data": null
}
// 402 Payment Required - Subscription or payment needed
{
  "code": 402,
  "message": "Subscription payment is required to access this feature",
  "success": false,
  "data": null
}
// 501 Not Implemented - Feature not yet available
{
  "code": 501,
  "message": "This feature is not yet available in your region",
  "success": false,
  "data": null
}
// 502 Bad Gateway - Upstream service failure
{
  "code": 502,
  "message": "Payment gateway is currently unavailable",
  "success": false,
  "data": null
}
// 503 Service Unavailable - Maintenance or overloaded
{
  "code": 503,
  "message": "System is under maintenance. Please try again later.",
  "success": false,
  "data": null
}
// 504 Gateway Timeout - Upstream timeout
{
  "code": 504,
  "message": "External reporting service timed out",
  "success": false,
  "data": null
}

Server Error Responses

// 500 Internal Server Error
{
  "code": 500,
  "message": "An unexpected error occurred. Please try again later.",
  "success": false,
  "data": null
}

Quick Start

Build API Responses

import { ApiEnvelope, ApiEnvelopeFactory, ResponseEntityBuilder } from '@syncafricabs/shared-kernel-core';

// Create a success response
const response: ApiEnvelope<User> = ApiEnvelopeFactory.success('User retrieved', user);

// Or use ResponseEntityBuilder for Express-compatible responses
const result = ResponseEntityBuilder.ok('User retrieved', user);
res.status(result.status).json(result.body);

Validate Input Fields

import { GlobalFieldValidator } from '@syncafricabs/shared-kernel-core';

// Validate strings
GlobalFieldValidator.validateString(name, 'Name', 2, 100);

// Validate email
GlobalFieldValidator.validateEmail(email, 'Email');

// Validate phone
GlobalFieldValidator.validatePhone(phone, 'Phone');

// Validate URL
GlobalFieldValidator.validateUrl(website, 'Website');

// Validate UUID
GlobalFieldValidator.validateUUID(id, 'Id');

// Validate positive Long ID
GlobalFieldValidator.validatePositiveLong(userId, 'UserId');

// Validate integer
GlobalFieldValidator.validateInteger(count, 'Count');

// Validate period (days, 0-365)
GlobalFieldValidator.validatePeriod(days, 'Days');

// Validate size limit (1-1,000,000)
GlobalFieldValidator.validateSizeLimit(limit, 'Limit');

Handle Exceptions

The library includes pre-defined exception types and an Express middleware for automatic HTTP mapping:

import {
  ValidationException,
  AlreadyExistsException,
  NotFoundException,
  MissingFieldsException,
  UnauthorizedException,
  NotAllowedException,
  InvalidException,
  RequestFailedException,
  InsufficientFundsException,
  TooManyRequestsException,
  PaymentRequiredException,
  TokenExpiredException,
  SessionExpiredException,
  AccountSuspendedException,
  LockedException,
  ConflictException,
  QuotaExceededException,
  ExternalServiceException,
  DataIntegrityException,
  ExpiredException,
  ServiceUnavailableException,
  InvalidTokenException,
  PermissionDeniedException,
  FeatureNotAvailableException,
  BadGatewayException,
  GatewayTimeoutException,
  NotImplementedException,
  MaintenanceModeException,
  DoesNotExistException,
} from '@syncafricabs/shared-kernel-core';
import { GlobalExceptionHandler } from '@syncafricabs/shared-kernel-core';

// Throw these in your service layer
throw new ValidationException('Invalid input');
throw new AlreadyExistsException('User already exists');
throw new NotFoundException('User not found');
throw new MissingFieldsException('Email and password are required');
throw new UnauthorizedException('Invalid credentials');
throw new NotAllowedException('Access denied');
throw new InvalidException('Invalid state transition');
throw new RequestFailedException('Operation failed');
throw new InsufficientFundsException('Insufficient balance');
throw new TooManyRequestsException('Too many requests. Please try again later.');
throw new PaymentRequiredException('Subscription payment is required');
throw new TokenExpiredException('Token has expired');
throw new SessionExpiredException('Session has expired');
throw new AccountSuspendedException('Account is suspended');
throw new LockedException('Account is locked');
throw new ConflictException('Resource conflict detected');
throw new QuotaExceededException('Storage quota exceeded');
throw new ExternalServiceException('Payment gateway is unavailable');
throw new DataIntegrityException('Database constraint violation');
throw new ExpiredException('Link has expired');
throw new ServiceUnavailableException('Service is under maintenance');
throw new InvalidTokenException('Invalid token format');
throw new PermissionDeniedException('Permission denied');
throw new FeatureNotAvailableException('Feature not available in your region');
throw new BadGatewayException('Upstream service error');
throw new GatewayTimeoutException('Upstream service timeout');
throw new NotImplementedException('Feature not implemented');
throw new MaintenanceModeException('System is under maintenance');
throw new DoesNotExistException('Resource does not exist');

Exception-to-HTTP Mapping:

| Exception | HTTP Status | Use Case | |-----------|-------------|----------| | ValidationException | 400 | Validation errors, invalid input | | MissingFieldsException | 400 | Required fields missing | | AlreadyExistsException / ConflictException | 409 | Resource already exists or business conflict | | NotFoundException / DoesNotExistException | 404 | Resource not found | | UnauthorizedException / TokenExpiredException / SessionExpiredException / InvalidTokenException | 401 | Authentication required, token/session expired, invalid token | | NotAllowedException / InvalidException / AccountSuspendedException / LockedException / PermissionDeniedException | 403 | Access denied, account locked, permission denied | | RequestFailedException | 500 | Server-side request failure | | InsufficientFundsException / PaymentRequiredException | 400 | Insufficient funds or payment required | | TooManyRequestsException / QuotaExceededException | 429 | Rate limit or quota exceeded | | ExternalServiceException / BadGatewayException | 502 | Third-party API or upstream service failure | | DataIntegrityException | 422 | Database constraint violation | | ExpiredException | 410 | Expired links, offers, or resources | | ServiceUnavailableException / MaintenanceModeException | 503 | System under maintenance or overloaded | | GatewayTimeoutException | 504 | Upstream service timeout | | NotImplementedException / FeatureNotAvailableException | 501 | Feature not yet implemented or unavailable | | Generic Error | 500 | Unhandled server errors |

Express Integration

import express from 'express';
import { GlobalExceptionHandler, ApiEnvelopeFactory } from '@syncafricabs/shared-kernel-core';

const app = express();

app.use(express.json());

// Global exception handler
app.use(GlobalExceptionHandler.middleware());
app.use(GlobalExceptionHandler.validationErrorsMiddleware());

app.get('/api/users/:id', (req, res) => {
  const { id } = req.params;
  GlobalFieldValidator.validatePositiveLong(Number(id), 'Id');
  
  const user = userService.findById(Number(id));
  const result = ResponseEntityBuilder.ok('User retrieved', user);
  res.status(result.status).json(result.body);
});

app.listen(3000);

Controller Example

import express from 'express';
import { ResponseEntityBuilder, GlobalFieldValidator } from '@syncafricabs/shared-kernel-core';

const app = express();
app.use(express.json());

app.post('/api/users', (req, res) => {
  const { name, email, age } = req.body;

  GlobalFieldValidator.validateString(name, 'Name', 2, 100);
  GlobalFieldValidator.validateEmail(email, 'Email');
  GlobalFieldValidator.validatePositiveLong(age, 'Age');

  const user = userService.create(req.body);
  const result = ResponseEntityBuilder.created('User created successfully', user);
  res.status(result.status).json(result.body);
});

app.get('/api/users/:id', (req, res) => {
  const { id } = req.params;
  GlobalFieldValidator.validatePositiveLong(Number(id), 'Id');

  const user = userService.findById(Number(id));
  const result = ResponseEntityBuilder.ok('User retrieved', user);
  res.status(result.status).json(result.body);
});

app.delete('/api/users/:id', (req, res) => {
  const { id } = req.params;
  userService.delete(Number(id));
  const result = ResponseEntityBuilder.noContent('User deleted');
  res.status(result.status).json(result.body);
});

app.listen(3000);

Utility Classes

import { BaseUtils } from '@syncafricabs/shared-kernel-core';

BaseUtils.formatCurrency(99.99, 'USD'); // $99.99
BaseUtils.formatPercentage(0.1567); // 15.67%
BaseUtils.generateSlug('Hello World'); // hello-world
BaseUtils.truncate('Some long text...', 10); // Some long ...
BaseUtils.maskString('1234567890'); // ******7890
BaseUtils.sanitizeHtml('<script>alert("xss")</script>'); // &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;

Project Structure

shared-kernel/
├── src/
│   ├── ApiEnvelope.ts                 # Generic API response envelope
│   ├── ApiEnvelopeFactory.ts          # Factory for creating envelopes
│   ├── ResponseEntityBuilder.ts       # Express-compatible response builder
│   ├── validation/
│   │   ├── GlobalFieldValidator.ts    # Validators + custom annotations
│   │   └── index.ts
│   ├── exception/
│   │   ├── GlobalExceptionHandler.ts  # Express error middleware
│   │   ├── ErrorResponse.ts           # Error response DTO
│   │   └── [custom exceptions].ts     # Custom exception types
│   └── configs/
│       ├── BaseUtils.ts               # Utility classes
│       └── index.ts
├── package.json
├── tsconfig.json
└── README.md

License

Apache License, Version 2.0

Author

Providence Chikukwa

  • Email: [email protected]
  • GitHub: https://github.com/iamprovy-dev
  • LinkedIn: https://www.linkedin.com/in/provychikukwa
  • Organization: SyncAfrica Business Solutions (https://www.syncafricabs.com)