UNPKG

blackbox_server

Version:

service for quickly creating server applications

355 lines (307 loc) 9.05 kB
import { Express, NextFunction, Request, Response, Router } from 'express' import { Model, Query, UpdateWriteOpResult } from 'mongoose' import { checkAccessIP } from './decorators' import { StatusCode } from './controllers/baseController/base-controller' import { HttpUnauthorizedException } from './dataClasses/httpErrors' import { JwtPayload } from 'jsonwebtoken' import { IConfigApp } from './utils/utils' import { getConfig, getConfigFile } from './utils' export interface BlackBoxApp extends Express {} /** * Перечисление событий сервера */ export const enum BlackBoxEventName { CLIENT_REQUEST = 'CLIENT_REQUEST', SERVER_IS_RUNNING = 'SERVER_IS_RUNNING', SERVER_IS_STOPPED = 'SERVER_IS_STOPPED', DB_IS_CONNECTED = 'DB_IS_CONNECTED', AMQP_IS_RECONNECTING = 'AMQP_IS_RECONNECTING', AMQP_IS_CONNECTED = 'AMQP_IS_CONNECTED', AMQP_CHANNEL_IS_CLOSED = 'AMQP_CHANNEL_IS_CLOSED', AMQP_WORKER_IS_STARTED = 'AMQP_WORKER_IS_STARTED', } /** * Перечисления кодов ответа сервера */ export const enum BlackBoxStatusCode { OK = 200, BAD_REQUEST = 400, UNAUTHORIZED = 401, FORBIDDEN = 403, NOT_FOUND = 404, TOO_MANY_REQUESTS = 429, INTERNAL_SERVER_ERROR = 500, } /** * Перечисления причин ошибок */ export const enum BlackBoxReasonError { REQUEST = 'REQUEST', AMQP = 'AMQP', AMQP_CHANNEL = 'AMQP_CHANNEL', SOCKET = 'SOCKET', CONTROLLER = 'CONTROLLER', JWT = 'JWT', } // ==== Сущности ==== /** * Базовый контроллер */ class BlackBoxBaseController { request: Request response: Response next: NextFunction | null constructor( request: TBlackBoxRequest, response: TBlackBoxResponse, next?: TBlackBoxNextFunction ) /** * Обрабатываем запрос к БД и выводим ответ * @param promise - запрос к БД */ prepareQueryAndSendResponse(promise: Query<any[], any, {}>): void prepareQueryAndSendResponse<T>( promise: Query<UpdateWriteOpResult, T, {}, any> ): void /** * Отправка данных на фронт * @param result - данные для отправки * @param code - код ответа из TStatusCode */ render: (result: any, code: StatusCode) => void } /** * Базовый класс для ошибок */ class HttpErrors extends Error { constructor(name: string) } /** * Класс ошибки валидации */ class HttpValidationException extends HttpErrors { readonly response: Response constructor(message: string, response: Response) } /** * Слишком много запросов */ class HttpTooManyRequests extends HttpErrors { readonly response: Response constructor(message: string, response: Response) } /** * Веутреня ошибка сервера */ class HttpInternalServerException extends HttpErrors { readonly response: Response constructor(message: string, response: Response) } /** * Базовый класс для сервиса */ class BaseServiceModel { readonly Model: Model<any> constructor(model: Model<any>) /** * Найти все записи модели */ findAll<T>(): Query<T[], any, {}> /** * Поиск записей по одному полю * @param fieldName - название поля * @param value - значение поля */ findByOneField<T>( fieldName: string, value: string | number | null | boolean ): Query<T[], any, {}> /** * Поиск последней записи по полю * @param fieldName - название поля * @param value - значение поля */ findLastByOneField<T>( fieldName: string, value: string | number | null | boolean ): Query<T, any, {}, any> /** * Найти последнюю запись */ findLast<T>(limit: number = 1): Query<T[], any, {}> /** * Создание записи * @param data - данные записи */ create<T>(data: T) /** * Создание или обновление записи * @param data - данные записи */ createOrUpdateById<T extends { _id: string }>( data: T ): Query<UpdateWriteOpResult, T, {}, any> /** * Обновить одну запись по фильтру * @param filter * @param data */ updateOneByFilter<T>( filter: object, data: T ): Query<UpdateWriteOpResult, T, {}, any> updateOneByFilter<T>( filter: object, data: object ): Query<UpdateWriteOpResult, T, {}, any> /** * Удаление записи * @param filter */ remove(filter: object): Query< { ok?: number | undefined; n?: number | undefined } & { deletedCount?: number | undefined }, any, {} > } /** * Роутер * @constructor */ export function BlackBoxRouter(): Router /** * Базовый контроллер * @constructor */ export function BlackBoxBaseController(): typeof BlackBoxBaseController /** * Класс ошибок валидации * @constructor */ export function BlackBoxHttpValidationException(): typeof HttpValidationException /** * Класс ошибок с большим количеством запросов * @constructor */ export function BlackBoxHttpTooManyRequests(): typeof HttpTooManyRequests /** * Класс внутренних ошибок сервера * @constructor */ export function BlackBoxHttpInternalServerException(): typeof HttpInternalServerException /** * Класс внутренних ошибок сервера * @constructor */ export function BlackBoxHttpUnauthorizedException(): typeof HttpUnauthorizedException /** * Базовый сервис * @constructor */ export function BlackBoxBaseServiceModel(): typeof BaseServiceModel // ==== Функции ==== /** * Основная функция для создания приложения * @param env */ export function createApp(env: { BASE_PATH?: string NODE_ENV?: string }): BlackBoxApp /** * Типы аргументов для функций запросов */ export interface TBlackBoxRequest extends Request { ClientInfo: { readonly connectDate: Date requestUrl: string requestMethod: string requestCookies: string requestSignedCookies: string requestIP: string body: object queryParams: object decodeAccessToken?: IObjectJWT } } export type TBlackBoxResponse = Response export type TBlackBoxNextFunction = NextFunction // ==== Обработка запросов ==== /** * Страница 404 * @param _request * @param response * @param _next */ export function notFound( _request: Request, response: Response, _next: NextFunction ): Response<any, Record<string, any>> /** * Обработчик ошибок после запроса * @param error * @param _request * @param _response * @param _next */ export function onErrorAfterResponse( error: Error, _request: Request, _response: Response, _next: NextFunction ): void /** * Обработчик ошибок в запросах * @param error * @param _request * @param response * @param _next */ export function onErrorRequest( error: Error, _request: Request, response: Response, _next: NextFunction ): Response<any, Record<string, any>> /** Декораторы */ /** * Декоратор для проверки количества вызовов метода с одного IP * @param maxStack - количество запросов * @param timeLifeStack - интервал жизни очереди * @param messageError - сообщение об ошибки */ export function checkAccessIp( maxStack: number, timeLifeStack: number, messageError?: string ) /** * Аутентификация с помощью Bearer токена * @param messageError - сообщение об ошибки * @param secretKey - строка для расшифровки JWT */ export function checkTokenBearer(secretKey: string = '', messageError?: string) /** utils */ interface IObjectJWT extends JwtPayload { email: string } /** * Проверка токена авторизации для предоставления ответа клиенту * @param token - токен * @param response - объект ответа * @param secret - строка расшифровки jwt */ export function decodeJwtForResponse( token: string, response: Response, secret: string ): IObjectJWT /** * Чтение из файла * @param url */ export function readFromFile<T>(url: string): T