@soft-artel/modules
v1.2.13
Published
Exception, Validation
Downloads
192
Readme
Exception, Logger, Validation, Utils Module
Exception
class enhances error handling by allowing for the categorization of exceptions through specific types and parameters. This structure provides greater clarity and detail, enabling developers to manage errors more effectively and respond with informative, context-rich messages.
Logger
is a flexible and customizable logging library for Node.js and browsers. It supports various output formats and modes, making it suitable for debugging, error handling, and other logging scenarios that require detailed event tracking.
Valid
provides a flexible and powerful way to validate data structures in TypeScript and JavaScript. You can define validation rules and schemas for your data, ensuring that they conform to expected types and formats.
Installation
npm install @soft-artel/modules
Exception
Exception Types
const ExceptionTitles = {
TimeResync = "TimeResync",
BadRequest = "BadRequest",
Validation = "Validation",
Authorize = "Authorize",
AccessNotAllowed = "AccessNotAllowed",
NotFound = "NotFound",
MethodNotAllowed = "MethodNotAllowed",
ExternalRequest = "ExternalRequest",
Core = "Core",
Service = "Service",
DataSource = "DataSource",
UserBlocked = "UserBlocked",
IPAddressNotAllowed = "IPAddressNotAllowed",
UnprocessableContent = "UnprocessableContent",
NoInternet: "No internet connection",
Server: "Server error",
};
Constructor
constructor(
typeOrCode: ExceptionType | number,
messageOrError: string | Error | unknown,
params?: Record<string, any>,
options?: Options
)
typeOrCode
— This parameter can be either an ExceptionType (like 'BadRequest', 'NotFound', etc.) or a numerical HTTP status code. It determines the type of exception being created.
messageOrError
— This can be a string representing the custom error message or another Error object. If an Error is provided, its message and stack trace will be used to populate the new exception.
params?
— An object containing additional information related to the exception. This can be used to pass context-specific data that may be helpful for debugging or logging.
options?
— An object conforming to the Options interface, allowing for further customization of the exception behavior (e.g., whether to show parameters in the response).
Usage
throw new Exception(ExceptionTitles.BadRequest, Error || "Message", {
param: 1,
});
Logger
Default config logger
const defaultConfigLogger: Config = {
stage: isBrowser ? '' : process.env.STAGE || 'dev',
app: isBrowser ? '' : process.env.APP_NAME || '',
version: isBrowser ? '' : process.env.APP_VER || '',
format: isBrowser ? 'plain' : process.env.LOG_FORMAT === 'json' ? 'json' : 'plain',
mode: isBrowser ? 'errors' : process.env.STAGE && process.env.STAGE !== 'test' ? 'errors' : 'silent',
}
Config
interface Config {
stage: string,
app: string,
version: string,
format: 'plain' | 'json'
mode: 'debug' | 'errors' | 'silent'
}
stage
— Represents the environment stage in which the application is running.
app
— Specifies the name of the application.
version
— Represents the version of the application.
format
— Determines the output format of the log messages.
mode
— Sets the logging mode to control the verbosity and type of log messages.
Buffer
interface Log{
d: Date; // log date
t: LogType // log type
m: string; // log mesage
p?: any; // log params
s?: string // log stack
}
Modes of Operation
The Logger supports three modes of operation:
debug:
- The logger outputs all messages with different collors (info, debug, dump, done, warning, and error).
Or in JSON format.
errors:
- The logger outputs only error messages (
err
), warning messages (wrn
), and done messages (dne
). - Logs are stored in the buffer, limited to 100 entries.
- However, if an error occurs during the operation, it outputs all the logs that were recorded before the error.
silent:
- In this mode, the logger does not output any messages at all.
- Logs still be buffered.
Logger.shared.mode = "debug"; // Switch to debug mode
Copy Logger to log requests or paralells process
You can create a copy of shared logger with customized env for each request:
const requestLogger = Logger.shared.copy({
status: number // request status
dt: Date, // request date
key: string, // request key
loc: string // request location
mem: number //Memory usage
});
Example with Environment Variables
Logger can be configured using environment variables for flexibility across different stages of your application.
APP_NAME=myApp
APP_VER=1.0.0
STAGE=development
LOG_FORMAT=json
Logger.info("Application initialized"); // Will automatically use env config
API
The shared Logger instance that can be accessed globally.
Logger.shared;
Generates a new unique key for log tracing.
Logger.newKey;
Logs a detailed dump message, useful for outputting large objects or debug information.
Logger.dump(message: string, params?: any, isAlert?: boolean): void
Logs a debug message.
Logger.dbg(message: string, params?: any, isAlert?: boolean): void
Logs an informational message.
Logger.info(message: string, params?: any, isAlert?: boolean): void
Logs a warning.
Logger.warn(message: any, params?: any, isAlert?: boolean): void
Logs an error message. If the error is an Exception, it will also set the logger's status to the HTTP status code of the exception.
Logger.error(message: any, params?: any, isAlert?: boolean): void
Helper Functions
Helper function to convert an error to a structured log format.
convertError(err: any, paramsObj?: any): { message: string, params?: any, stack?: string }
Converts log parameters to a JSON string for output.
convertParamsToJson(log: Log, prefix: string): string
This function attempts to merge the environment object and the log object into a JSON string. If an error occurs, it is caught and logged, and the error message is returned.
makeJsonLogRowStr(env: ProcessEnv, log: Log): string
This function formats a log entry as a plain text string with color differentiation, including a timestamp, HTTP status, error message, and log parameters.
makePlainLogRowStr(env: ProcessEnv, log: Log, withPrefixOpt: string = ''): string
Usage
import { Logger } from "@soft-artel/modules";
Logger.info("Log an info message");
Logger.dbg("Log a debug message");
Logger.warn(new Error("Log a warning with additional parameters"), {
additional: "info",
});
Logger.error(new Error("Log an error"), {
cause: "Database not reachable",
});
Valid
Features
- Support for Primitive Types: strings, numbers, booleans, etc.
- Validation of Complex Structures: objects, arrays, and dictionaries.
- Customizable Validation Rules: minimum and maximum values, patterns, lists of allowed values.
- Partial Validation Support: allows for partial validation of objects (useful for PATCH requests).
- Detailed Validation Errors: provides detailed information on which fields failed validation and why.
API
Types
Valid.Type
Enumeration of supported data types:
uuid
- UUID strings
serial
- Auto-incrementing numbers
smallint
- Integers from -32768 to +32767
integer
- Integers from -2147483648 to +2147483647
bigint
- Large range integers
coordinate
- Coordinates with specified precision
double
- High-precision floating-point numbers
string
- Fixed-length strings
text
- Text fields with no length limit
phone
- Strings representing phone numbers
boolean
- Boolean values
date
- Dates without time zones
datez
- Dates with time zones
timestamp
- Timestamps
daykey
- Integers representing days
email
- Strings matching email format
ipv4
- IPv4 addresses
object
- Objects
array
- Arrays
dictionary
- Dictionaries (objects with arbitrary keys)
stream
- Data streams
buffer
- Data buffers
Valid.RuleOptions
Object defining validation rules for a specific field:
type: Valid.Type
- Data type
null?: boolean
- Is null allowed?
default?: any
- Default value if the field is absent
min?: number
- Minimum value or length
max?: number
- Maximum value or length
mod?: number
- Modulus for numeric values
values?: any[] | object
- Allowed values (enumeration)
pattern?: string | RegExp
- Pattern for strings
schema?: Valid.Schema
- Schema for nested objects
rule?: Valid.RuleOptions
| Valid.Type - Rule for array or dictionary items
allowPartial?: boolean
- Allow partial validation
Valid.Schema
Object where keys are field names and values are Valid.Rule or Valid.RuleOptions.
Functions
Valid.process
Main function for validating data.
Valid.process<I = any>(
value: any,
rule: Valid.Rule,
allowPartial?: boolean
): I | Partial<I>
value
: The value to validate
rule
: The validation rule or schema
allowPartial
: Allow partial validation (default is false)
Returns the validated value or throws a ValidationError.
Valid.Object
Creates a validation rule for objects.
Valid.Object<I>(
schema: Valid.Schema<I>,
options?: {
null?: boolean;
default?: Partial<I>;
allowPartial?: boolean;
}
): Valid.RuleOptions<I>
schema
: Validation schema for the object
options
: Additional options
Valid.Patch
Creates a rule for partial validation of objects (useful for PATCH requests).
Valid.Patch<I>(schema: Valid.Schema<I>): Valid.RuleOptions<I>
Exceptions
ValidationError
class ValidationError extends Error {
constructor(
readonly propName: string,
readonly value: any,
readonly rule: Valid.Rule | Valid.Schema | undefined
) {
super(`ValidationError: ${propName}`);
}
}
propName
: The field name that failed validation
value
: The invalid value
rule
: The violated rule or validation schema
Usage
Defining Validation Rules
You can define a validation schema for your data using the types and rules provided by the library.
const userSchema: Valid.Schema = {
id: "uuid",
name: { type: "string", min: 1, max: 100 },
email: "email",
age: { type: "integer", min: 0, max: 120 },
isActive: { type: "boolean", default: true },
};
Validating Data
Use the Valid.process function to validate data against your schema.
try {
const validUser = Valid.process(userData, Valid.Object(userSchema));
// Data validated successfully
console.log(validUser);
} catch (error) {
// Handle validation errors
console.error("Validation Error:", error.message);
}
Partial Object Validation
For cases where you need to validate only part of an object (e.g., during PATCH requests), you can use the allowPartial option.
try {
const validPartialUser = Valid.process(
partialUserData,
Valid.Object(userSchema, { allowPartial: true })
);
// Partial data validated successfully
console.log(validPartialUser);
} catch (error) {
console.error("Validation Error:", error.message);
}
Util
This set of utility functions is designed to help with common tasks involving objects, enums, arrays, dates, numbers and strings. Each function addresses typical operations one might need in a project.
Objects
- Checks if the parameter is a valid object.
isObject(obj?: any)
- Checks if the objects are equal by their keys.
isObjectsEqual(object?: any, object2?: any)
- Returns an object of type Partial from the specified set of keys.
objPickKeys<O = Record<string, any>>( obj:O, keys: (keyof O)[]): Partial<O>
- Removes the specified keys from the object and returns a new object without those keys.
objDeleteKeys<O>( obj:O, keys: (keyof O)[]): Partial<O>
- Creates a reverse mapping for an object, where keys become values and values. become keys
reverseMapping(obj: {[key: number]: string}): {[key: string]: number}
Enums
- Converts a numeric enum to an array of strings containing the enum's key names.
enumToKeysArray(enumObject: Object): string[]
- Converts a string enum to an array of strings containing the enum's values.
enumToValuesArray(enumObject: Object): string[]
Arrays
- Returns a random element from an array.
randomElement<I=any>( arr: I[]):I
- Removes an element from an array if it is present.
deleteElement<I=any>( arr: I[], elm: I ): I[]
- Checks if the text exists in the specified key of objects in an array.
findInArrayObjects( array: Record<string, any>[], key: string, text: string): boolean
Time and Delays
- Delays execution for the specified number of milliseconds.
asyncSleep (ms: number, fn?: (id: any) => void): Promise<boolean>
- Generates a numerical key for a given date in the format YYYYMMDD. If no date is provided, it uses the current date.
getDayKey(date?: Date): number
- Returns a date adjusted for a given time zone offset in minutes.
getDateWithTimeZone(date?: Date, offsetMin?: number): Date
- Formats a date into a string. It allows customization on how to display the date and time and whether to include seconds or only the date.
getFormattedDate(date?: Date, delimiter: string = 'в ', options: {...}): string
- Parses an ISO date string and returns an object with separate strings for the date and time.
getDateAndTimeFromISO(isoString: string, offsetMin?: number): { date: string, time: string }
- Returns the number of seconds that have passed since a specified time.
getTimeSecSince(since: number, sec = 'sec.')
Strings
- Removes all non-numeric characters from a string.
strOnlyDigits(str: string): string
- Searches for text within a string without case sensitivity.
findText(text?: string | null, inString?: string): boolean
- Returns a string with the first letter capitalized.
static capitalize(str: string)
Numbers
- Rounds a number to the specified number of decimal places.
mathRound(num: number, n: number = 2): number
- Returns a string representation of a number with consideration for declension.
makeStringValue(dVal: number, bGender: boolean)
- Checks a number and adds its representation and declension to an array.
checkNumber(fValue: number, oObjDesc: OrderItem, fnAddNum: FnAddNumber, fnAddDesc: FnAddNumber)
- Converts a number into a string, considering declensions and currency descriptions.
numberToPhrase(fAmount: number, withCurrencyDesc: boolean = true)
- Declines words based on the number provided.
declineWord(n: number, word: keyof typeof this.acceptedWords)
- Returns the name of a month based on its number.
getMonthByNumber(number: number, isGenitive = true)
Format currency methods
- Formats a number as a monetary amount with two decimal places and adds a currency symbol.
formatCurrencyNum(money: number, currency: string =''): string
- Formats a string representing a numeric value
formatCurrencyStr(str: string, currency: string =''): string
Other methods
- Formats full names into a short version (LastName I. O.).
getShortFIO(name?: string, surname?: string, patronymic?: string)