ts-request-mediator v1.1.7
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;
14 days ago
15 days ago
15 days ago
17 days ago
23 days ago
23 days ago
23 days ago
22 days ago
22 days ago
22 days ago
21 days ago
21 days ago
23 days ago
24 days ago
24 days ago
24 days ago
24 days ago
24 days ago
24 days ago
26 days ago
26 days ago
26 days ago
30 days ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
5 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
8 months ago
8 months ago
8 months ago
8 months ago
11 months ago
8 months ago
11 months ago
8 months ago
8 months ago
11 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
10 months ago
10 months ago
10 months ago
9 months ago
10 months ago
10 months ago
10 months ago
8 months ago
8 months ago
8 months ago
12 months ago
12 months ago
12 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago