From 23e56c8071a1fe3199f46004e9a82cf9f79fab40 Mon Sep 17 00:00:00 2001 From: Augusto Alvarenga Date: Mon, 17 Feb 2025 10:37:56 -0300 Subject: [PATCH 1/3] fix: update midaz id to x-request-id into midaz requests --- src/core/infrastructure/utils/http-fetch-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/infrastructure/utils/http-fetch-utils.ts b/src/core/infrastructure/utils/http-fetch-utils.ts index d2dc012e..ae31e664 100644 --- a/src/core/infrastructure/utils/http-fetch-utils.ts +++ b/src/core/infrastructure/utils/http-fetch-utils.ts @@ -67,7 +67,7 @@ export class MidazHttpFetchUtils { const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${access_token}`, - 'Midaz-Id': this.midazRequestContext.getMidazId(), + 'X-Request-Id': this.midazRequestContext.getMidazId(), ...httpFetchOptions.headers } From 99533145f3aed166e3b4d2f92974d234ae1e2185 Mon Sep 17 00:00:00 2001 From: Augusto Alvarenga Date: Mon, 17 Feb 2025 12:11:17 -0300 Subject: [PATCH 2/3] fix: include status code into midaz reponse log --- .env.example | 2 +- ...midaz-fetch-all-transactions-repository.ts | 10 ++--- .../infrastructure/utils/http-fetch-utils.ts | 43 ++++++------------- 3 files changed, 16 insertions(+), 39 deletions(-) diff --git a/.env.example b/.env.example index 444367ff..61673ecd 100644 --- a/.env.example +++ b/.env.example @@ -21,7 +21,7 @@ NEXTAUTH_CASDOOR_ORGANIZATION_NAME=lerian NEXTAUTH_CASDOOR_APPLICATION_NAME=app-midaz # Midaz API Configuration -MIDAZ_API_HOST='ledger' +MIDAZ_API_HOST='midaz-onboarding' MIDAZ_API_PORT=3000 MIDAZ_BASE_PATH='http://${MIDAZ_API_HOST}:${MIDAZ_API_PORT}/v1' MIDAZ_TRANSACTION_BASE_HOST='transaction' diff --git a/src/core/infrastructure/midaz/transactions/midaz-fetch-all-transactions-repository.ts b/src/core/infrastructure/midaz/transactions/midaz-fetch-all-transactions-repository.ts index 023f5028..a0dd58c3 100644 --- a/src/core/infrastructure/midaz/transactions/midaz-fetch-all-transactions-repository.ts +++ b/src/core/infrastructure/midaz/transactions/midaz-fetch-all-transactions-repository.ts @@ -1,13 +1,9 @@ import { PaginationEntity } from '@/core/domain/entities/pagination-entity' -import { - httpMidazAuthFetch, - HTTP_METHODS, - MidazHttpFetchUtils -} from '../../utils/http-fetch-utils' -import { inject, injectable } from 'inversify' -import { FetchAllTransactionsRepository } from '@/core/domain/repositories/transactions/fetch-all-transactions-repository' import { TransactionEntity } from '@/core/domain/entities/transaction-entity' +import { FetchAllTransactionsRepository } from '@/core/domain/repositories/transactions/fetch-all-transactions-repository' +import { inject, injectable } from 'inversify' import { ContainerTypeMidazHttpFetch } from '../../container-registry/midaz-http-fetch-module' +import { HTTP_METHODS, MidazHttpFetchUtils } from '../../utils/http-fetch-utils' @injectable() export class MidazFetchAllTransactionsRepository diff --git a/src/core/infrastructure/utils/http-fetch-utils.ts b/src/core/infrastructure/utils/http-fetch-utils.ts index ae31e664..e21597b4 100644 --- a/src/core/infrastructure/utils/http-fetch-utils.ts +++ b/src/core/infrastructure/utils/http-fetch-utils.ts @@ -21,36 +21,6 @@ export type HttpFetchOptions = { body?: string } -export async function httpMidazAuthFetch( - httpFetchOptions: HttpFetchOptions -): Promise { - const session = await getServerSession(nextAuthCasdoorOptions) - const { access_token } = session?.user - - const headers = { - 'Content-Type': 'application/json', - Authorization: `Bearer ${access_token}`, - ...httpFetchOptions.headers - } - - const response = await fetch(httpFetchOptions.url, { - method: httpFetchOptions.method, - body: httpFetchOptions.body, - headers: { - ...headers - } - }) - - const midazResponse = !isNil(response.body) ? await response.json() : {} - - if (!response.ok) { - console.error('[ERROR] - httpMidazAuthFetch ', midazResponse) - throw await handleMidazError(midazResponse) - } - - return midazResponse -} - @injectable() export class MidazHttpFetchUtils { constructor( @@ -82,10 +52,21 @@ export class MidazHttpFetchUtils { const midazResponse = !isNil(response.body) ? await response.json() : {} if (!response.ok) { - this.midazLogger.error('[ERROR] - httpMidazAuthFetch ', midazResponse) + this.midazLogger.error('[ERROR] - httpMidazAuthFetch ', { + url: httpFetchOptions.url, + method: httpFetchOptions.method, + status: response.status, + response: midazResponse + }) throw await handleMidazError(midazResponse) } + this.midazLogger.info('[INFO] - httpMidazAuthFetch ', { + url: httpFetchOptions.url, + method: httpFetchOptions.method, + status: response.status + }) + return midazResponse } } From 0da1a49a6e256319bd4a4eb2d78dbef1f2c7d4b0 Mon Sep 17 00:00:00 2001 From: Augusto Alvarenga Date: Mon, 17 Feb 2025 14:23:12 -0300 Subject: [PATCH 3/3] fix: http fetch utils unit test --- .../utils/http-fetch-utils.test.ts | 298 +++++++++--------- 1 file changed, 146 insertions(+), 152 deletions(-) diff --git a/src/core/infrastructure/utils/http-fetch-utils.test.ts b/src/core/infrastructure/utils/http-fetch-utils.test.ts index 0d8c71bf..f95f86df 100644 --- a/src/core/infrastructure/utils/http-fetch-utils.test.ts +++ b/src/core/infrastructure/utils/http-fetch-utils.test.ts @@ -1,152 +1,146 @@ -import { getServerSession } from 'next-auth' -import { nextAuthCasdoorOptions } from '../next-auth/casdoor/next-auth-casdoor-provider' -import { handleMidazError } from './midaz-error-handler' -import { - httpMidazAuthFetch, - HTTP_METHODS, - HttpFetchOptions -} from './http-fetch-utils' - -jest.mock('next-auth', () => ({ - getServerSession: jest.fn() -})) - -jest.mock('../next-auth/casdoor/next-auth-casdoor-provider', () => ({ - nextAuthCasdoorOptions: {} -})) - -jest.mock('./midaz-error-handler', () => ({ - handleMidazError: jest.fn(() => { - throw new Error('Error occurred') - }) -})) - -global.fetch = jest.fn() - -describe('httpMidazAuthFetch', () => { - const mockSession = { - user: { - access_token: 'mock_access_token' - } - } - - beforeEach(() => { - jest.clearAllMocks() - ;(getServerSession as jest.Mock).mockResolvedValue(mockSession) - }) - - it('should fetch data successfully', async () => { - const mockResponse = { data: 'test' } - ;(fetch as jest.Mock).mockResolvedValue({ - body: '', - json: jest.fn().mockResolvedValue(mockResponse), - ok: true - }) - - const httpFetchOptions: HttpFetchOptions = { - url: 'https://api.example.com/data', - method: HTTP_METHODS.GET - } - - const result = await httpMidazAuthFetch(httpFetchOptions) - - expect(getServerSession).toHaveBeenCalledWith(nextAuthCasdoorOptions) - expect(fetch).toHaveBeenCalledWith(httpFetchOptions.url, { - method: httpFetchOptions.method, - body: httpFetchOptions.body, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${mockSession.user.access_token}` - } - }) - expect(result).toEqual(mockResponse) - }) - - it('should make a POST request with the correct headers and body', async () => { - const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({}) } - ;(fetch as jest.Mock).mockResolvedValue({ - body: '', - json: jest.fn().mockResolvedValue(mockResponse), - ok: true - }) - - const options: HttpFetchOptions = { - url: 'https://api.example.com/data', - method: HTTP_METHODS.POST, - body: JSON.stringify({ key: 'value' }) - } - - const response = await httpMidazAuthFetch(options) - - expect(getServerSession).toHaveBeenCalledWith(nextAuthCasdoorOptions) - expect(fetch).toHaveBeenCalledWith(options.url, { - method: options.method, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${mockSession.user.access_token}` - }, - body: options.body - }) - expect(response).toBe(mockResponse) - }) - - it('should include additional headers if provided', async () => { - const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({}) } - ;(fetch as jest.Mock).mockResolvedValue({ - body: '', - json: jest.fn().mockResolvedValue(mockResponse), - ok: true - }) - - const options: HttpFetchOptions = { - url: 'https://api.example.com/data', - method: HTTP_METHODS.GET, - headers: { - 'Custom-Header': 'CustomValue' - } - } - - const response = await httpMidazAuthFetch(options) - - expect(getServerSession).toHaveBeenCalledWith(nextAuthCasdoorOptions) - expect(fetch).toHaveBeenCalledWith(options.url, { - method: options.method, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${mockSession.user.access_token}`, - 'Custom-Header': 'CustomValue' - }, - body: undefined - }) - expect(response).toBe(mockResponse) - }) - - it('should handle errors when fetching data', async () => { - const mockErrorResponse = { message: 'Error occurred' } - ;(fetch as jest.Mock).mockResolvedValue({ - body: '', - json: jest.fn().mockResolvedValue(mockErrorResponse), - ok: false - }) - - const httpFetchOptions: HttpFetchOptions = { - url: 'https://api.example.com/data', - method: HTTP_METHODS.GET - } - - await expect(httpMidazAuthFetch(httpFetchOptions)).rejects.toThrow( - 'Error occurred' - ) - - expect(getServerSession).toHaveBeenCalledWith(nextAuthCasdoorOptions) - expect(fetch).toHaveBeenCalledWith(httpFetchOptions.url, { - method: httpFetchOptions.method, - body: httpFetchOptions.body, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${mockSession.user.access_token}` - } - }) - expect(handleMidazError).toHaveBeenCalledWith(mockErrorResponse) - }) -}) +import { LoggerAggregator } from '@/core/application/logger/logger-aggregator' +import { getServerSession } from 'next-auth' +import { MidazRequestContext } from '../logger/decorators/midaz-id' +import { HTTP_METHODS, MidazHttpFetchUtils } from './http-fetch-utils' +import { handleMidazError } from './midaz-error-handler' + +jest.mock('next-auth', () => ({ + getServerSession: jest.fn() +})) + +jest.mock('./midaz-error-handler', () => ({ + handleMidazError: jest.fn(() => { + throw new Error('Error occurred') + }) +})) + +jest.mock('../next-auth/casdoor/next-auth-casdoor-provider', () => ({ + nextAuthCasdoorOptions: {} +})) + +describe('MidazHttpFetchUtils', () => { + let midazHttpFetchUtils: MidazHttpFetchUtils + let midazRequestContext: MidazRequestContext + let midazLogger: LoggerAggregator + + beforeEach(() => { + midazRequestContext = { + getMidazId: jest.fn().mockReturnValue('test-request-id') + } as unknown as MidazRequestContext + + midazLogger = { + error: jest.fn(), + info: jest.fn() + } as unknown as LoggerAggregator + + midazHttpFetchUtils = new MidazHttpFetchUtils( + midazRequestContext, + midazLogger + ) + }) + + afterEach(() => { + jest.clearAllMocks() + }) + + it('should successfully fetch data', async () => { + const mockResponse = { data: 'test' } + const mockFetch = jest.fn().mockResolvedValue({ + ok: true, + json: jest.fn().mockResolvedValue(mockResponse), + body: true, + status: 200 + }) + global.fetch = jest.fn().mockResolvedValue({ + ok: true, + json: jest.fn().mockResolvedValue(mockResponse), + body: true, + status: 200 + }) + ;(getServerSession as jest.Mock).mockResolvedValue({ + user: { access_token: 'test-token' } + }) + + const result = await midazHttpFetchUtils.httpMidazAuthFetch({ + url: 'https://api.example.com/test', + method: HTTP_METHODS.GET + }) + + expect(result).toEqual(mockResponse) + expect(midazLogger.info).toHaveBeenCalledWith( + '[INFO] - httpMidazAuthFetch ', + { + url: 'https://api.example.com/test', + method: 'GET', + status: 200 + } + ) + }) + + it('should handle fetch error', async () => { + const mockErrorResponse = { error: 'test error' } + const mockFetch = jest.fn().mockResolvedValue({ + ok: false, + json: jest.fn().mockResolvedValue(mockErrorResponse), + body: true, + status: 400 + }) + global.fetch = mockFetch + ;(getServerSession as jest.Mock).mockResolvedValue({ + user: { access_token: 'test-token' } + }) + ;(handleMidazError as jest.Mock).mockImplementation(() => { + throw new Error('Handled error') + }) + + await expect( + midazHttpFetchUtils.httpMidazAuthFetch({ + url: 'https://api.example.com/test', + method: HTTP_METHODS.GET + }) + ).rejects.toThrow('Handled error') + + expect(midazLogger.error).toHaveBeenCalledWith( + '[ERROR] - httpMidazAuthFetch ', + { + url: 'https://api.example.com/test', + method: 'GET', + status: 400, + response: mockErrorResponse + } + ) + }) + + it('should set the correct headers', async () => { + const mockResponse = { data: 'test' } + const mockFetch = jest.fn().mockResolvedValue({ + ok: true, + json: jest.fn().mockResolvedValue(mockResponse), + body: true, + status: 200 + }) + global.fetch = mockFetch + ;(getServerSession as jest.Mock).mockResolvedValue({ + user: { access_token: 'test-token' } + }) + + await midazHttpFetchUtils.httpMidazAuthFetch({ + url: 'https://api.example.com/test', + method: HTTP_METHODS.GET, + headers: { + 'Custom-Header': 'CustomValue' + } + }) + + expect(mockFetch).toHaveBeenCalledWith('https://api.example.com/test', { + method: 'GET', + body: undefined, + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer test-token', + 'X-Request-Id': 'test-request-id', + 'Custom-Header': 'CustomValue' + } + }) + }) +})