@cargolift-cdi/common
v1.0.93
Published
Common utilities and error handling for Cargolift CDI projects
Readme
@cargolift-cdi/common
Utilidades comuns e padronização de erros para projetos Cargolift CDI (NestJS).
Este pacote provê:
- Classes de erro de domínio (BusinessError) com código, dados adicionais e causa encadeada
- Filtro global de exceções para APIs (APIExceptionsFilter) já integrado ao util-logger
Instalação
Requisitos:
- Node.js LTS (18+) e npm
- Peer dependency:
@nestjs/common@^11
Instale:
npm i @cargolift-cdi/commonO pacote depende de @cargolift-cdi/util-logger (instalado automaticamente).
Uso rápido
1) Aplicar o filtro global de exceções (NestJS)
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { APIExceptionsFilter } from '@cargolift-cdi/common';
import { LoggerContextService } from '@cargolift-cdi/util-logger';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { bufferLogs: true });
// Usa o LoggerContextService já registrado no container
const logger = app.get(LoggerContextService);
app.useGlobalFilters(new APIExceptionsFilter(logger));
await app.listen(3000);
}
bootstrap();O filtro padroniza o payload de erro, enriquece logs com correlation_id e trata mensagens conhecidas (ex.: erros de rede).
Alternativa: registrar via provider global (APP_FILTER):
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { APIExceptionsFilter } from '@cargolift-cdi/common';
// Certifique-se de que o LoggerContextService esteja disponível no container
import { LoggerContextService } from '@cargolift-cdi/util-logger';
@Module({
providers: [
LoggerContextService, // ou importe o módulo que o fornece, se existir
{ provide: APP_FILTER, useClass: APIExceptionsFilter },
],
})
export class AppModule {}2) Lançar erros de negócio no seu código
import { NotFoundBusinessError, GenericBusinessError } from '@cargolift-cdi/common';
// Recurso não encontrado
throw new NotFoundBusinessError('Order', '12345');
// Erro de negócio genérico com código e dados extras
throw new GenericBusinessError('Falha no provedor', {
code: 'PAYMENT_PROVIDER_ERROR',
data: { context: 'Pagamento', errorCode: 'PX-999', provider: 'AcmePay' },
});API pública (exportada por index)
BusinessError(abstrata)- Base para erros de domínio. Suporta
code?: string,data?: Record<string, unknown>,cause?: unknowne serialização segura viatoJSON().
- Base para erros de domínio. Suporta
GenericBusinessError- Erro de negócio genérico (mensagem padrão "Generic Business error" quando não informada). Útil para normalizar exceções desconhecidas.
NotFoundBusinessError- Especialização para recursos não encontrados: construtor
(resourceType: string, resourceId: string|number, message?, options?).
- Especialização para recursos não encontrados: construtor
APIExceptionsFilter(NestJS)- Filtro global de exceções. Decide tipo do erro (business/application), aplica códigos padrão e registra logs estruturados via
LoggerContextService.
- Filtro global de exceções. Decide tipo do erro (business/application), aplica códigos padrão e registra logs estruturados via
Observação: existem classes internas adicionais (ex.: ApplicationError, GenericApplicationError) que podem evoluir; utilize apenas a API pública acima para evitar quebras.
Contexto de Logs com AsyncLocalStorage (v2)
A partir da versão que introduz esta seção, o LoggerContextService passou a ser singleton (escopo DEFAULT) e o isolamento por requisição/mensagem é garantido via AsyncLocalStorage.
Benefícios:
- Menos alocações de instâncias (melhor para alto throughput)
- Propagação automática de contexto por callbacks/promises sem passar manualmente
- Publishers/clients apenas usam
logger.getContext()
Helpers exportados:
import { runWithLoggerContext, getLoggerContext, updateLoggerContext } from '@cargolift-cdi/common';
runWithLoggerContext({ correlation_id: 'abc' }, () => {
// Tudo aqui dentro (e awaits) mantém o contexto
});Fluxo HTTP (middleware APILoggerMiddleware):
- Abre
runWithLoggerContext({}) - Chama
logger.setContextRequest(req)(gera/propagacorrelation_idetrace) - Todos os logs subsequentes compartilham o mesmo contexto
Fluxo RabbitMQ (consumer):
- Cria um child logger a partir dos headers da mensagem (
childFromRabbit) - Semeia o ALS com
runWithLoggerContext(child.getContext(), processMessage) - Dentro do processamento usa-se o
loggerbase normalmente
Caso precise anexar dados adicionais no meio da execução:
updateLoggerContext({ caller_info: { type: 'user', id: 'u-1' } });Se um log for emitido fora de um escopo ALS (ex.: antes de bootstrap), o logger ainda funcionará, porém sem correlation_id fixo (um novo poderá ser gerado quando o contexto for definido).
Detalhes das classes
BusinessError
Contrato básico:
name: string— Nome da classe (ex.:NotFoundBusinessError)message?: string— Mensagem humanacode?: string— Ex.:BUSINESS_RESOURCE_NOT_FOUND,INVALID_PAYLOADdata?: Record<string, unknown>— Dados serializáveis extrascause?: unknown— Erro original para encadeamentotoJSON()— Retorna objeto serializável, inclusive comstackenumerável ecausesegura
BusinessErrorOptions:
type BusinessErrorOptions = {
code?: string;
cause?: unknown;
data?: Record<string, unknown>;
};NotFoundBusinessError
- Código padrão:
BUSINESS_RESOURCE_NOT_FOUND data:{ resourceType: string, resourceId: string|number }
GenericBusinessError
- Código padrão:
BUSINESS_ERROR - Permite enviar
dataadicional e causa original (cause).
APIExceptionsFilter
- Inspeciona exceções do NestJS (
HttpException) e erros comuns de infraestrutura (ex.:ECONNREFUSED,ETIMEDOUT) - Cria/propaga
correlation_idno contexto de log - Resposta JSON padrão:
{
"message": "<mensagem>",
"error": {
"statusCode": 500,
"timestamp": "2025-01-01T00:00:00.000Z",
"path": "/rota",
"errorCode": "INTERNAL_ERROR"
}
}App Logger (Global)
Use AppLoggerModule para configurar um log global com contexto.
import { AppLoggerModule, APP_LOGGER, LoggerContextService } from '@cargolift-cdi/common';
@Module({
imports: [
AppLoggerModule.forRoot({
application: {
name: 'middleware-esb',
function: 'service',
},
}),
],
})
export class AppModule {}
@Injectable()
export class SomeService {
constructor(@Inject(APP_LOGGER) private readonly appLogger: LoggerContextService) {}
doStuff() {
this.appLogger.log('App level log');
}
}Notes:
- Este log possui um contexto único; não chame
setContext. - Para logs por mensagem/requisição , use a versão de escopo TRANSIENT
LoggerContextServicee chamesetContextRabbitMQ/setContextRequest.
Scripts do projeto
npm run build— Compila TypeScript paradist/npm publish— Publica (executabuildnoprepublishOnly)
Contribuição
- Abra issues e PRs no GitHub: https://github.com/cargolift-cdi/common
- Padrões: TypeScript, NestJS 11, commits claros, linters/formatters do seu editor
Licença
MIT © Cargolift CDI
