Skip to content

Commit b05204b

Browse files
authored
Merge pull request #189 from AlvaroDavi5/develop
Develop
2 parents 9b1c5e1 + 532fa59 commit b05204b

File tree

11 files changed

+193
-85
lines changed

11 files changed

+193
-85
lines changed

src/dev/localstack/queues/SqsClient.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,20 @@ import { ConfigsInterface } from '@core/configs/envs.config';
99
import { LoggerInterface } from '@core/logging/logger';
1010

1111

12+
type ISendParams = {
13+
queueUrl: string;
14+
title: string;
15+
author: string;
16+
message: unknown;
17+
messageGroupId: string;
18+
messageDeduplicationId: string;
19+
};
20+
1221
export default class SqsClient {
13-
private readonly messageGroupId: string;
1422
private readonly sqsClient: SQSClient;
1523

1624
constructor(
1725
private readonly configService: ConfigService,
18-
private readonly cryptographyService: { generateUuid: () => string },
1926
private readonly logger: LoggerInterface,
2027
private readonly dataParserHelper: { toString: (data: unknown) => string },
2128
) {
@@ -24,8 +31,6 @@ export default class SqsClient {
2431
} } = this.configService.get<ConfigsInterface['integration']['aws']>('integration.aws')!;
2532
const showExternalLogs = this.configService.get<ConfigsInterface['application']['showExternalLogs']>('application.showExternalLogs')!;
2633

27-
this.messageGroupId = 'DefaultGroup';
28-
2934
this.sqsClient = new SQSClient({
3035
endpoint, region, apiVersion, maxAttempts,
3136
credentials: { accessKeyId, secretAccessKey, sessionToken },
@@ -39,7 +44,7 @@ export default class SqsClient {
3944
}
4045

4146
private createParams(queueName: string): CreateQueueCommandInput {
42-
const isFifoQueue: boolean = queueName?.includes('.fifo');
47+
const isFifoQueue = queueName?.endsWith('.fifo');
4348

4449
const params: CreateQueueCommandInput = {
4550
QueueName: queueName,
@@ -54,8 +59,9 @@ export default class SqsClient {
5459
return params;
5560
}
5661

57-
private msgParams(queueUrl: string, message: unknown, title: string, author: string): SendMessageCommandInput {
58-
const isFifoQueue: boolean = queueUrl?.includes('.fifo');
62+
private msgParams(params: ISendParams): SendMessageCommandInput {
63+
const { message, title, author, queueUrl, messageGroupId, messageDeduplicationId } = params;
64+
const isFifoQueue = queueUrl?.endsWith('.fifo');
5965
const messageBody = this.formatMessageBeforeSend(message);
6066

6167
return {
@@ -71,8 +77,9 @@ export default class SqsClient {
7177
StringValue: String(author)
7278
},
7379
},
74-
MessageDeduplicationId: isFifoQueue ? this.cryptographyService.generateUuid() : undefined,
75-
MessageGroupId: isFifoQueue ? this.messageGroupId : undefined, // Required for FIFO queues
80+
// NOTE - required for FIFO queues
81+
MessageDeduplicationId: isFifoQueue ? messageDeduplicationId : undefined,
82+
MessageGroupId: isFifoQueue ? messageGroupId : undefined,
7683
};
7784
}
7885

@@ -136,11 +143,9 @@ export default class SqsClient {
136143
}
137144
}
138145

139-
public async sendMessage(queueUrl: string, title: string, author: string, message: unknown): Promise<string> {
146+
public async sendMessage(params: ISendParams): Promise<string> {
140147
try {
141-
const result = await this.sqsClient.send(new SendMessageCommand(
142-
this.msgParams(queueUrl, message, title, author)
143-
));
148+
const result = await this.sqsClient.send(new SendMessageCommand(this.msgParams(params)));
144149

145150
if (!result?.MessageId)
146151
throw new Error('Message not sended');

src/dev/localstack/queues/createQueue.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { ConfigService } from '@nestjs/config';
2-
import { configServiceMock, cryptographyServiceMock, dataParserHelperMock, loggerProviderMock } from '@dev/mocks/mockedModules';
2+
import { configServiceMock, dataParserHelperMock, loggerProviderMock } from '@dev/mocks/mockedModules';
33
import SqsClient from './SqsClient';
44

55

66
export default (queueName: string, queueUrl: string): void => {
7-
const sqsClient = new SqsClient(configServiceMock as unknown as ConfigService, cryptographyServiceMock, loggerProviderMock, dataParserHelperMock);
7+
const sqsClient = new SqsClient(configServiceMock as unknown as ConfigService, loggerProviderMock, dataParserHelperMock);
88

99
try {
1010
sqsClient.createQueue(queueName).then((createdQueueUrl) => {

src/dev/localstack/queues/sendMessage.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import SqsClient from './SqsClient';
44

55

66
export default (queueName: string, queueUrl: string, payload: unknown, title: string, author: string): void => {
7-
const sqsClient = new SqsClient(configServiceMock as unknown as ConfigService, cryptographyServiceMock, loggerProviderMock, dataParserHelperMock);
7+
const sqsClient = new SqsClient(configServiceMock as unknown as ConfigService, loggerProviderMock, dataParserHelperMock);
88

99
const message = {
1010
id: cryptographyServiceMock.generateUuid(),
@@ -15,12 +15,14 @@ export default (queueName: string, queueUrl: string, payload: unknown, title: st
1515
timestamp: new Date('2024-06-10T03:52:50.885Z').toISOString(),
1616
};
1717

18-
sqsClient.sendMessage(
18+
sqsClient.sendMessage({
1919
queueUrl,
20+
message,
2021
title,
2122
author,
22-
message,
23-
).then(() => {
23+
messageGroupId: 'TEST',
24+
messageDeduplicationId: cryptographyServiceMock.generateUuid(),
25+
}).then(() => {
2426
console.debug(`Sended message to ${queueName}`);
2527
});
2628
};

src/modules/api/interceptors/Response.interceptor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ export default class ResponseInterceptor implements NestInterceptor {
4141
.pipe(
4242
tap((responseData: unknown): void => {
4343
const resData = this.dataParserHelper.toString(responseData);
44-
this.logger.http(`RESPONDING - ${timestamp} ms: [${method.toUpperCase()}] '${path}' ${resData}`);
44+
this.logger.http(`RESPONDING - ${timestamp} ms: [${method.toUpperCase()}] ${path} ${resData}`);
4545
}),
4646
catchError((responseError: Error): Observable<void> => {
4747
const resErr = this.dataParserHelper.toString(responseError);
48-
this.logger.http(`RESPONDING ERROR - ${timestamp} ms: [${method.toUpperCase()}] '${path}' ${resErr}`);
48+
this.logger.http(`RESPONDING ERROR - ${timestamp} ms: [${method.toUpperCase()}] ${path} ${resErr}`);
4949
throw responseError;
5050
})
5151
);

src/modules/common/utils/externalErrorParser.util.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AxiosError } from 'axios';
33
import Exceptions from '@core/errors/Exceptions';
44
import { ExceptionsEnum } from '@common/enums/exceptions.enum';
55
import { HttpStatusEnum } from '@common/enums/httpStatus.enum';
6+
import { ErrorInterface } from '@shared/internal/interfaces/errorInterface';
67

78

89
function exceptionsMapper(statusCode: number) {
@@ -22,17 +23,39 @@ function exceptionsMapper(statusCode: number) {
2223
}
2324

2425
export default function externalErrorParser(error: unknown): HttpException {
25-
26-
const exceptions = new Exceptions();
2726
let exceptionName: ExceptionsEnum;
27+
const errorStacks: string[] = [];
2828

29-
if (error instanceof HttpException)
29+
if (error instanceof HttpException) {
3030
exceptionName = exceptionsMapper(error.getStatus());
31-
else if (error instanceof AxiosError)
32-
exceptionName = exceptionsMapper(error.status ?? error.response?.status ?? 500);
33-
else // instanceof Error
34-
exceptionName = exceptionsMapper(500);
31+
const res = error.getResponse();
32+
if (typeof res === 'object') {
33+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34+
const response = res as Record<string, any>;
35+
const responseMessage = !!response.message ? JSON.stringify(response.message) : undefined;
36+
const responseMetadata = !!response.metadata
37+
? JSON.stringify({ message: response.metadata?.message, detail: response.metadata?.detail })
38+
: undefined;
3539

36-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
37-
return exceptions[String(exceptionName) as ExceptionsEnum](error as any, true);
40+
if (responseMessage)
41+
errorStacks.push(responseMessage);
42+
if (responseMetadata)
43+
errorStacks.push(responseMetadata);
44+
error.stack = [...errorStacks, error.stack].join('\n');
45+
}
46+
} else if (error instanceof AxiosError) {
47+
exceptionName = exceptionsMapper(error.status ?? 500);
48+
const { response } = error;
49+
if (typeof response === 'object') {
50+
const responseMessage = !!response.data ? JSON.stringify(response.data) : undefined;
51+
if (responseMessage)
52+
errorStacks.push(responseMessage);
53+
error.stack = [...errorStacks, error.stack].join('\n');
54+
}
55+
} else { // instanceof Error
56+
exceptionName = exceptionsMapper(HttpStatusEnum.INTERNAL_SERVER_ERROR);
57+
}
58+
59+
const exceptions = new Exceptions();
60+
return exceptions[String(exceptionName) as ExceptionsEnum](error as ErrorInterface, true);
3861
}

src/modules/core/infra/integration/aws/Sns.client.ts

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,48 @@ import {
77
CreateTopicCommandInput, SubscribeCommandInput, PublishCommandInput,
88
} from '@aws-sdk/client-sns';
99
import { ConfigsInterface } from '@core/configs/envs.config';
10-
import CryptographyService from '@core/security/Cryptography.service';
1110
import Exceptions from '@core/errors/Exceptions';
1211
import LoggerService from '@core/logging/Logger.service';
1312
import DataParserHelper from '@common/utils/helpers/DataParser.helper';
1413

1514

16-
export type protocolType = 'email' | 'sms' | 'http' | 'https' | 'sqs' | 'lambda' | 'application'
15+
interface EmailPublishTargets {
16+
protocol: 'email';
17+
subject: string;
18+
}
19+
interface SmsPublishTargets {
20+
protocol: 'sms';
21+
phoneNumber: string;
22+
}
23+
interface SqsPublishTargets {
24+
protocol: 'sqs';
25+
targetArn?: string;
26+
}
27+
interface LambdaPublishTargets {
28+
protocol: 'lambda';
29+
targetArn?: string;
30+
}
31+
32+
export type IPublishTargetsOptions =
33+
| EmailPublishTargets
34+
| SmsPublishTargets
35+
| SqsPublishTargets
36+
| LambdaPublishTargets;
37+
export type protocolType = IPublishTargetsOptions['protocol'];
38+
39+
type IPublishParams = IPublishTargetsOptions & {
40+
topicArn: string;
41+
message: unknown;
42+
messageGroupId: string;
43+
messageDeduplicationId: string;
44+
};
1745

1846
@Injectable()
1947
export default class SnsClient {
20-
private readonly messageGroupId: string;
2148
private readonly snsClient: SNSClient;
2249

2350
constructor(
2451
private readonly configService: ConfigService,
25-
private readonly cryptographyService: CryptographyService,
2652
private readonly exceptions: Exceptions,
2753
private readonly logger: LoggerService,
2854
private readonly dataParserHelper: DataParserHelper,
@@ -32,8 +58,6 @@ export default class SnsClient {
3258
} } = this.configService.get<ConfigsInterface['integration']['aws']>('integration.aws')!;
3359
const showExternalLogs = this.configService.get<ConfigsInterface['application']['showExternalLogs']>('application.showExternalLogs')!;
3460

35-
this.messageGroupId = 'DefaultGroup';
36-
3761
this.snsClient = new SNSClient({
3862
endpoint, region, apiVersion, maxAttempts,
3963
credentials: { accessKeyId, secretAccessKey, sessionToken },
@@ -47,7 +71,7 @@ export default class SnsClient {
4771
}
4872

4973
private createParams(topicName: string): CreateTopicCommandInput {
50-
const isFifoTopic: boolean = topicName?.includes('.fifo');
74+
const isFifoTopic = topicName?.endsWith('.fifo');
5175

5276
const params: CreateTopicCommandInput = {
5377
Name: topicName,
@@ -68,28 +92,36 @@ export default class SnsClient {
6892
};
6993
}
7094

71-
private publishParams(topicArn: string, topicName: string,
72-
protocol: protocolType, message: string, { subject, phoneNumber }: Record<string, string | undefined>): PublishCommandInput {
73-
const isFifoTopic: boolean = topicName?.includes('.fifo');
95+
private publishParams(params: IPublishParams): PublishCommandInput {
96+
const { message, protocol, topicArn, messageGroupId, messageDeduplicationId } = params;
97+
const isFifoTopic = topicArn?.endsWith('.fifo');
7498
const messageBody = this.formatMessageBeforeSend(message);
7599

76100
const publishData: PublishCommandInput = {
77-
TopicArn: topicArn,
78101
Message: messageBody,
79-
MessageDeduplicationId: isFifoTopic ? this.cryptographyService.generateUuid() : undefined,
80-
MessageGroupId: isFifoTopic ? this.messageGroupId : undefined, // Required for FIFO topics
102+
// NOTE - required for FIFO topics
103+
MessageDeduplicationId: isFifoTopic ? messageDeduplicationId : undefined,
104+
MessageGroupId: isFifoTopic ? messageGroupId : undefined,
81105
};
82106

83107
switch (protocol) {
108+
case 'sms':
109+
publishData.PhoneNumber = params.phoneNumber;
110+
break;
84111
case 'email':
85-
publishData.Subject = subject;
112+
publishData.TopicArn = topicArn;
113+
publishData.Subject = params.subject;
86114
break;
87-
case 'sms':
88-
publishData.PhoneNumber = phoneNumber;
115+
case 'lambda':
116+
case 'sqs':
117+
if (params.targetArn) {
118+
publishData.TargetArn = params.targetArn;
119+
} else {
120+
publishData.TopicArn = topicArn;
121+
}
89122
break;
90-
default: // application | sqs | lambda | http(s)
123+
default:
91124
publishData.TopicArn = topicArn;
92-
publishData.TargetArn = topicArn;
93125
break;
94126
}
95127

@@ -168,12 +200,9 @@ export default class SnsClient {
168200
}
169201
}
170202

171-
public async publishMessage(topicArn: string, topicName: string,
172-
protocol: protocolType, message: string, destination: Record<string, string | undefined>): Promise<string> {
203+
public async publishMessage(params: IPublishParams): Promise<string> {
173204
try {
174-
const result = await this.snsClient.send(new PublishCommand(
175-
this.publishParams(topicArn, topicName, protocol, message, destination)
176-
));
205+
const result = await this.snsClient.send(new PublishCommand(this.publishParams(params)));
177206

178207
if (!result?.MessageId)
179208
throw this.exceptions.internal({ message: 'Message not published' });

0 commit comments

Comments
 (0)