Skip to content

Commit

Permalink
Fix(packages/massa-web3): removed axios to use fetch in BaseClient (#608
Browse files Browse the repository at this point in the history
)

Co-authored-by: 0xSwapFeeder <[email protected]>
  • Loading branch information
0xmemorygrinder and 0xSwapFeeder authored May 22, 2024
1 parent 2cf44f3 commit 8ce13bf
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 71 deletions.
50 changes: 24 additions & 26 deletions packages/massa-web3/src/web3/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Buffer } from 'buffer'
import { varintEncode } from '../utils/Xbqcrypto'
import { IContractData } from '../interfaces/IContractData'
import { JsonRpcResponseData } from '../interfaces/JsonRpcResponseData'
import axios, { AxiosResponse, AxiosRequestHeaders } from 'axios'
import { JSON_RPC_REQUEST_METHOD } from '../interfaces/JsonRpcMethods'
import { ITransactionData } from '../interfaces/ITransactionData'
import { OperationTypeId } from '../interfaces/OperationTypes'
Expand All @@ -14,13 +13,11 @@ import { Address } from '../utils/keyAndAddresses'

export type DataType = IContractData | ITransactionData | IRollsData | ICallData

export const requestHeaders = {
export const fetchRequestHeaders = {
Accept:
'application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
} as AxiosRequestHeaders
'Content-Type': 'application/json',
}

export const PERIOD_OFFSET = 5

Expand Down Expand Up @@ -182,44 +179,45 @@ export class BaseClient {
resource: JSON_RPC_REQUEST_METHOD,
params: object
): Promise<JsonRpcResponseData<T>> {
let resp: AxiosResponse<JsonRpcResponseData<T>> = null
let resp: Response = null

const body = {
const bodyData = {
jsonrpc: '2.0',
method: resource,
params: params,
id: 0,
}

let body;
try {
resp = await axios.post(
this.getProviderForRpcMethod(resource).url,
body,
requestHeaders
)
body = JSON.stringify(bodyData)
} catch (ex) {
return {
isError: true,
result: null,
error: new Error('JSON.parse error: ' + String(ex)),
error: new Error('JSON.stringify error: ' + String(ex)),
} as JsonRpcResponseData<T>
}

const responseData: JsonRpcResponseData<T> = resp.data

if (responseData.error) {
try {
resp = await fetch(this.getProviderForRpcMethod(resource).url, {
headers: fetchRequestHeaders,
body: body,
method: 'POST',
})

const responseData: JsonRpcResponseData<T> = await resp.json()

return {
isError: !!responseData.error,
result: responseData.error ? null : responseData.result as T,
error: responseData.error ? new Error(responseData.error.message) : null,
} as JsonRpcResponseData<T>;
} catch (ex) {
return {
isError: true,
result: null,
error: new Error(responseData.error.message),
error: new Error('Fetch error: ' + String(ex)),
} as JsonRpcResponseData<T>
}

return {
isError: false,
result: responseData.result as T,
error: null,
} as JsonRpcResponseData<T>
}

/**
Expand Down
115 changes: 70 additions & 45 deletions packages/massa-web3/test/web3/baseClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IProvider, ProviderType } from '../../src/interfaces/IProvider'
import { IClientConfig } from '../../src/interfaces/IClientConfig'
import { JSON_RPC_REQUEST_METHOD } from '../../src/interfaces/JsonRpcMethods'
import axios from 'axios'
import { requestHeaders } from '../../src/web3/BaseClient'
import { fetchRequestHeaders } from '../../src/web3/BaseClient'

jest.mock('axios')

Expand Down Expand Up @@ -226,72 +226,90 @@ describe('BaseClient', () => {

test('should use public provider for public RPC methods', async () => {
const mockResponse = {
data: {
result: {
ok: true,
status: 200,
json: () =>
Promise.resolve({
result: {
error: null,
isError: false,
result: 'some data returned from the API',
},
error: null,
isError: false,
result: 'some data returned from the API',
},
error: null,
isError: false,
},
}),
}

mockAxios.post.mockResolvedValueOnce(mockResponse)
const mockFetch = jest
.spyOn(global, 'fetch')
.mockImplementation(
jest.fn(() => Promise.resolve(mockResponse)) as jest.Mock
)

const result = await baseClient.getSendJsonRPCRequest(
JSON_RPC_REQUEST_METHOD.GET_STATUS, // public method
{}
)

expect(mockAxios.post).toHaveBeenCalledTimes(1)
expect(mockAxios.post).toHaveBeenCalledWith(
expect(mockFetch).toHaveBeenCalledTimes(1)
expect(mockFetch).toHaveBeenCalledWith(
publicApi, // <-- We check here that the public API is used
{
jsonrpc: '2.0',
id: 0,
method: JSON_RPC_REQUEST_METHOD.GET_STATUS,
params: {},
},
requestHeaders
body: JSON.stringify({
jsonrpc: '2.0',
method: JSON_RPC_REQUEST_METHOD.GET_STATUS,
params: {},
id: 0,
}),
method: 'POST',
headers: fetchRequestHeaders,
}
)

expect(result).toEqual(mockResponse.data.result)
expect(result).toEqual((await mockResponse.json()).result)
})

test('should use private provider for private RPC methods', async () => {
const mockResponse = {
data: {
result: {
json: () =>
Promise.resolve({
result: {
error: null,
isError: false,
result: 'some data returned from the API',
},
error: null,
isError: false,
result: 'some data returned from the API',
},
error: null,
isError: false,
},
}),
}

mockAxios.post.mockResolvedValueOnce(mockResponse)
const mockFetch = jest
.spyOn(global, 'fetch')
.mockImplementation(
jest.fn(() => Promise.resolve(mockResponse)) as jest.Mock
)

const result = await baseClient.getSendJsonRPCRequest(
JSON_RPC_REQUEST_METHOD.STOP_NODE, // private method
{}
)

expect(mockAxios.post).toHaveBeenCalledTimes(1)
expect(mockAxios.post).toHaveBeenCalledWith(
expect(mockFetch).toHaveBeenCalledTimes(1)
expect(mockFetch).toHaveBeenCalledWith(
privateApi, // <-- We check here that the private API is used
{
jsonrpc: '2.0',
id: 0,
method: JSON_RPC_REQUEST_METHOD.STOP_NODE,
params: {},
},
requestHeaders
body: JSON.stringify({
jsonrpc: '2.0',
method: JSON_RPC_REQUEST_METHOD.STOP_NODE,
params: {},
id: 0,
}),
headers: fetchRequestHeaders,
method: 'POST',
}
)

expect(result).toEqual(mockResponse.data.result)
expect(result).toEqual((await mockResponse.json()).result)
})

test('should throw an error for unknown RPC methods', async () => {
Expand Down Expand Up @@ -338,18 +356,25 @@ describe('BaseClient', () => {

test('should handle JSON-RPC error responses', async () => {
const mockResponse = {
data: {
result: null,
error: {
code: -32600,
message: 'Invalid Request',
},
id: null,
jsonrpc: '2.0',
},
ok: true,
status: 200,
json: () =>
Promise.resolve({
result: null,
error: {
code: -32600,
message: 'Invalid Request',
},
id: null,
jsonrpc: '2.0',
}),
}

mockAxios.post.mockResolvedValueOnce(mockResponse)
jest
.spyOn(global, 'fetch')
.mockImplementation(
jest.fn(() => Promise.resolve(mockResponse)) as jest.Mock
)

await expect(
baseClient.getSendJsonRPCRequest(JSON_RPC_REQUEST_METHOD.GET_STATUS, {})
Expand Down

0 comments on commit 8ce13bf

Please sign in to comment.