You're Invited: Meet the Socket team at BSidesSF and RSAC - April 27 - May 1.RSVP
Socket
Sign inDemoInstall
Socket

ts-request-mediator

Package Overview
Dependencies
Maintainers
1
Versions
218
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install
Package was removed
Sorry, it seems this package was removed from the registry

ts-request-mediator

Request mediator for server

1.1.7
unpublished
latest
Source
npm
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

NPM version:latest npm downloads npm bundle size (minified + gzip) Coverage Status License

Framework agnostic request mediator

Advantages

  • written on typescript
  • simple and lightweight
  • clean API
  • supports middlewares as decorators

Install

npm install ts-request-mediator reflect-metadata
yarn add ts-request-mediator reflect-metadata

tsconfig.json

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Architecture design

Scopes

  • application
  • request
  • useCase
  • service

Request scope

  flowchart LR;
      requestHandler1-->requestHandler2-->id1{{targetHandler}}-->requestHandler3-->requestHandler4;

Example:

  flowchart LR;
      AuthorizeUser-->id1{{CreateTodo}}-->LogRequest;

Use case scope

  flowchart LR;
      useCaseHandler1-->useCaseHandler2-->id1{{targetHandler}}-->useCaseHandler3-->useCaseHandler4;

Example:

  flowchart LR;
      SetUserContext-->id1{{CreateTodo}}-->DoSmthAfter;

Service scope

  flowchart LR;
      serviceHandler1-->serviceHandler2-->id1{{targetHandler}}-->serviceHandler3-->serviceHandler4;

Usage

Describe a use case

import { IQueryHandler, request, context, transaction, useService, inject } from "ts-request-mediator";
import { by } from "ts-ioc-container";

@transaction
@request("before", [AuthorizeUser])
@request("after", [LogRequest])
@useCase("before", [SetUserContext])
class CreateTodo implements IQueryHandler<CreateTodoQuery, Todo> {
  constructor(
    @inject(by(ITodoRepositoryKey)) private todoRepository: ITodoRepository,
    @inject(context(IUserKey)) private user: IUser,
    @inject(useService(INotifyAllUsersKey, { transaction: true })) private notifyAllUsers: INotifyAllUsers
  ) {
  }

  @before
  validate(query: CreateTodoQuery): void {
    PermissionError.assert(this.user.isAdmin, "User has no permission to create a todo");
  }

  async handle(query: CreateTodoQuery): Promise<Todo> {
    const todo = await this.todoRepository.create(query);
    return todo;
  }

  @after
  async notify(query: CreateTodoQuery, todo: Todo): Promise<void> {
    await this.notifyAllUsers.handle(todo);
  }
}

const INotifyAllUsersKey = Symbol("INotifyAllUsers");
interface INotifyAllUsers extends IQueryHandler<Todo, void> {
}

class NotifyAllUsers implements INotifyAllUsers {
  constructor(
    @inject(by(INotificationServiceKey)) private notificationService: INotificationService
  ) {
  }

  async handle(todo: Todo): Promise<void> {
    const users = await this.userRepository.findAll();
    await this.notificationService.notify(users, `New todo created: ${todo.title}`);
  }
}

Wrap your dependency container into adapter


import { IDependencyContainer } from 'ts-ioc-container';

export class ContainerAdapter implements IDependencyContainer {
  constructor(private container: IContainer) {}

  createScope(tags: string[]): IDependencyContainer {
    return new ContainerAdapter(this.container.createScope(tags));
  }

  dispose(): void {
    this.container.dispose();
  }

  registerValue(key: string | symbol, value: unknown): void {
    this.container.register(fromValue(value).forKey(key).build());
  }

  resolve<T>(key: constructor<T> | symbol): T {
    return this.container.resolve(key);
  }
}

Create mediator


const mediator = new RequestMediator(new ContainerAdapter(container));

And finally invoke your use case

const todo = await mediator.send(CreateTodo, {title: 'Buy milk', description: '2% fat'});

Implement your transaction context and put into DI container

import { PrismaClient } from '@prisma/client';
import { forKey, Resolveable } from 'ts-ioc-container';
import { ITransactionContextKey, ITransactionContext } from 'ts-request-mediator';
import { perApplication } from '../../core/di';

@perApplication
@forKey(ITransactionContextKey)
export class PrismaTransactionContext implements ITransactionContext {
  constructor(public dbClient: PrismaClient = new PrismaClient()) {}

  execute<Response>(setContext: (context: ITransactionContext) => Promise<Response>): Promise<Response> {
    return this.dbClient.$transaction((transactionClient) =>
      setContext(new PrismaTransactionContext(transactionClient as PrismaClient)),
    );
  }
}

export const prismaClient = (c: Resolveable) =>
  l.resolve<PrismaTransactionContext>(ITransactionContextKey).dbClient;

Keywords

typescript

FAQs

Package last updated on 27 Apr 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts