ddd
Como disparar eventos com nestjs
- Dependencias
- "@qq-framework/ddd": "^3.4.x"
- "@qq-framework/basic": "^3.2.x"
- Crie um provider em seu módulo utilizando a classe
DomainEventPublisherNestImplService
do@qq-framework/ddd
// any.module.ts
import { EventPublisher } from '@nestjs/cqrs'
import { DomainEventPublisherNestImplService } from '@qq-framework/ddd'
@Module({
controllers: [
...
],
providers: [
...
{
provide: 'NestDomainEventPublisher',
useFactory(eventPublisher: EventPublisher) {
return new DomainEventPublisherNestImplService(eventPublisher)
},
inject: [EventPublisher],
}
...
],
imports: [
...
],
})
export class CoreModule implements NestModule {}
- Injete o provider criado no construtor da classe de serviço onde deseja disparar o evento, utilizando a interface
DomainEventPublisherService
do@qq-framework/basic
//any.service
import {
AggregateRoot,
DomainEventPublisherService,
} from '@qq-framework/basic'
...
constructor(
@Inject('NestDomainEventPublisher') private readonly publisher: DomainEventPublisherService<AggregateRoot>
) {
}
...
- Para publicar o evento, utilize o publisher injetado na sua classe, passando o seu agregado.
...
const publish = await this.publisher.publish(campoExistente.value)
if (publish.isFailure()) return R.failure(publish.error)
...
Pooling de rotas
- "@qq-framework/ddd": "^3.5.x"
Como adicionar um parâmetro de pooling de rotas.
Será via o decorator @Pooling
. Este decorator irá receber a rota ser chamada para ter o retorno do processo sendo executado. Ele irá injetar um parâmetro string
no exemplo chamado idPooling
) no paramêtro do método. Ele será a chave de referência para a rota de busca.
Essa rota por sua vez no buildResponse irá devolver dentro do objeto uma chave poolingRoute
. poolingRoute
será a rota a ser requisitada para ter o retorno.
Exemplo:
@Controller("core")
export class CoreController extends AbstractController {
private readonly logger = new Logger(CoreController.name);
constructor(
private readonly useCase: UseCase,
private readonly query: Query
) {
super(CoreController.name, CoreModule.name, {
httpCodeMap,
defaultHttpCodeErrors: 500,
});
}
@Post("postar-mensagem")
@Pooling("core/rota-pooling")
public async executarMetodo(@Body() params: any, idPooling: string) {
this.useCase.execute({ params, idPooling });
return super.buildResponse({ result: Result.ok() });
}
@Get("rota-pooling/:id")
public async executarMetodo(@Params() id: string) {
const result = await this.query.execute(id);
return super.buildResponse({ result });
}
}
Migrando para versão 2.x.x
Se você estiver realizando uma migração da versão 1.x.x
para versão 2.x.x
os seguintes scripts devem ser executados no banco de dados da sua aplicação:
alter table public.process_log add column error_class varchar null;
alter table public.process_log add column error_type varchar null;
alter table public.single_thread_command_log add column error_class varchar null;
alter table public.single_thread_command_log add column error_type varchar null;
alter table public.event_log add column error_class varchar null;
alter table public.event_log add column error_type varchar null;
O impacto que essa versão deve gerar nas aplicações que estavam utilizando a versão 1.x.x
será nos métodos de gravação de logs de erros. Os métodos de gravação de log como, por exemplo, ProcessLog.saveError
, o parâmetro error
, qua anteriormente recebia uma string, passou a receber uma instance de Error
.
Implementando response padrão nos controllers
Para utilizar essa funcionalidade é necessário versão 2.1.0
do qq-framework/http
ou superior.
Essa implementação visa padronizar os responses dos controllers das aplicações.
Em caso de sucesso, retornando HttpResponseOk
e em caso de falha, HttpResponseError
export interface HttpResponseOk {
data: any;
}
export interface HttpResponseError {
erro: string;
message: string;
}
//any.controller.ts
import { Body, Controller, Logger, Post } from '@nestjs/common'
import { AbstractController } from '@qq-framework/ddd'
import { PostarMensagemUseCase } from './application/usecases/PostarMensagem.usecase'
import { CoreModule } from './core.module'
const httpCodeMap: HttpCodeMap = {
RepositoryException: 400,
}
@Controller('core')
export class CoreController extends AbstractController {
private readonly logger = new Logger(CoreController.name)
constructor(private readonly postarMensagemUseCase: PostarMensagemUseCase) {
super(CoreController.name, CoreModule.name, {
httpCodeMap,
defaultHttpCodeErrors: 500,
})
}
@Post('postar-mensagem')
public async postarMensagem(@Body() params: any) {
const result = await this.postarMensagemUseCase.execute({
mensagem: {
chave: params['chave'],
conteudo: params['conteudo'],
headers: params['headers'],
topico: params['topico'],
},
})
return super.buildResponse({
data: result,
})
}
}
No código visto acima, primeiramente você deve definir quais o códigos HTTP que devem ser retornados para cada exceções possíveis que seu controller retornar para o client, conforme abaixo:
const httpCodeMap: HttpCodeMap = {
RepositoryException: 400,
};
No construtor do seu controller você deve informar ao AbstractController as configurações dos seus responses HTTP, através da interface HttpResponseConfig
constructor() {
const httpResponseConfig: HttpResponseConfig = {
httpCodeMap,
defaultHttpCodeErrors: 500,
}
super(VendaController.name, VendaModule.name, httpResponseConfig)
}
A propriedade defaultHttpCodeError não é obrigatória, mas serve para indicar qual o http code que o seu controller retornará, caso a exceção não tenha sido mapeada pelo HttpCodeMap
. Por default, este valor será 500
Para finalizar, você deve retornar o resultado do seu controller através do método buildResponse
. O método buidResponse
pode receber, além do parâmetro result
, também headers
e um parâmetro chamado successStatusCode
que será utilizado como código http retornado pelo seu endpoint em caso de sucesso. Ambos os parâmetros são opcionais. Em caso de não informado o successStatusCode
, será retornado 200
.
@Post('postar-mensagem')
public async postarMensagem(@Body() params: any) {
const result = await this.postarMensagemUseCase.execute({
mensagem: {
chave: params['chave'],
conteudo: params['conteudo'],
headers: params['headers'],
topico: params['topico'],
},
})
return super.buildResponse({
result,
})
}
Em caso de sucesso o seu response será retornado para o client com o http code informado em successStatusCode
ou 200
(default) e em caso de exceção, ele retornará o httpcode configurado no HttpCodeMap
que foi passado no construtor.
Para finalizar, você deve adicionar ao seu projeto o HttpInterceptor
disponibilizado no qq-framework/http