Skip to content

Commit

Permalink
add fetch with cache
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistevam committed Oct 24, 2024
1 parent dc11726 commit b968841
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 22 deletions.
44 changes: 29 additions & 15 deletions app/scripts/lib/ppom/security-alerts-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import {
BlockaidReason,
BlockaidResultType,
} from '../../../../shared/constants/security-provider';
import fetchWithCache from '../../../../shared/lib/fetch-with-cache';
import {
getSecurityAlertsAPISupportedChainIds,
isSecurityAlertsAPIEnabled,
validateWithSecurityAlertsAPI,
} from './security-alerts-api';

jest.mock('../../../../shared/lib/fetch-with-cache', () => ({
__esModule: true,
default: jest.fn(),
}));

const CHAIN_ID_MOCK = '0x1';

const REQUEST_MOCK = {
Expand All @@ -27,6 +33,8 @@ const RESPONSE_MOCK = {
description: 'Test Description',
};

const BASE_URL = 'https://example.com';

describe('Security Alerts API', () => {
const fetchMock = jest.fn();

Expand All @@ -40,7 +48,7 @@ describe('Security Alerts API', () => {
json: async () => RESPONSE_MOCK,
});

process.env.SECURITY_ALERTS_API_URL = 'https://example.com';
process.env.SECURITY_ALERTS_API_URL = BASE_URL;
});

describe('validateWithSecurityAlertsAPI', () => {
Expand All @@ -54,8 +62,14 @@ describe('Security Alerts API', () => {

expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith(
`https://example.com/validate/${CHAIN_ID_MOCK}`,
expect.any(Object),
`${BASE_URL}/validate/${CHAIN_ID_MOCK}`,
expect.objectContaining({
method: 'POST',
body: JSON.stringify(REQUEST_MOCK),
headers: {
'Content-Type': 'application/json',
},
}),
);
});

Expand Down Expand Up @@ -89,28 +103,28 @@ describe('Security Alerts API', () => {
});

describe('getSecurityAlertsAPISupportedChainIds', () => {
it('sends GET request', async () => {
it('sends GET request with cache', async () => {
const SUPPORTED_CHAIN_IDS_MOCK = ['0x1', '0x2'];
fetchMock.mockResolvedValue({
ok: true,
json: async () => SUPPORTED_CHAIN_IDS_MOCK,
});
(fetchWithCache as jest.Mock).mockResolvedValue(SUPPORTED_CHAIN_IDS_MOCK);

const response = await getSecurityAlertsAPISupportedChainIds();

expect(response).toEqual(SUPPORTED_CHAIN_IDS_MOCK);

expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith(
`https://example.com/supportedChains`,
undefined,
);
expect(fetchWithCache).toHaveBeenCalledTimes(1);
expect(fetchWithCache).toHaveBeenCalledWith({
cacheOptions: { cacheRefreshTime: 300000 },
fetchOptions: { method: 'GET' },
functionName: 'getSecurityAlertsAPISupportedChainIds',
url: `${BASE_URL}/supportedChains`,
});
});

it('throws an error if response is not ok', async () => {
fetchMock.mockResolvedValue({ ok: false, status: 404 });
(fetchWithCache as jest.Mock).mockResolvedValue(null);

await expect(getSecurityAlertsAPISupportedChainIds()).rejects.toThrow(
'Security alerts API request failed with status: 404',
'Security alerts API request failed: No response received',
);
});
});
Expand Down
54 changes: 47 additions & 7 deletions app/scripts/lib/ppom/security-alerts-api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Hex, JsonRpcRequest } from '@metamask/utils';
import fetchWithCache from '../../../../shared/lib/fetch-with-cache';
import { MINUTE } from '../../../../shared/constants/time';
import { SecurityAlertResponse } from './types';

const ENDPOINT_VALIDATE = 'validate';
const ENDPOINT_SUPPORTED_CHAINS = 'supportedChains';
const CACHE_REFRESH_FIVE_MINUTES = MINUTE * 5;

type SecurityAlertsAPIRequestBody = {
method: string;
Expand All @@ -15,7 +18,13 @@ export type SecurityAlertsAPIRequest = Omit<
> &
SecurityAlertsAPIRequestBody;

export function isSecurityAlertsAPIEnabled() {
type RequestOptions = {
useCache?: boolean;
functionName?: string;
cacheOptions?: Record<string, unknown>;
};

export function isSecurityAlertsAPIEnabled(): boolean {
const isEnabled = process.env.SECURITY_ALERTS_API_ENABLED;
return isEnabled?.toString() === 'true';
}
Expand All @@ -37,24 +46,55 @@ export async function validateWithSecurityAlertsAPI(
}

export async function getSecurityAlertsAPISupportedChainIds(): Promise<Hex[]> {
return request(ENDPOINT_SUPPORTED_CHAINS);
return request(
ENDPOINT_SUPPORTED_CHAINS,
{ method: 'GET' },
{
useCache: true,
functionName: 'getSecurityAlertsAPISupportedChainIds',
cacheOptions: { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
},
);
}

async function request(endpoint: string, options?: RequestInit) {
async function request(
endpoint: string,
options?: RequestInit,
requestOptions?: RequestOptions,
) {
const {
useCache = false,
functionName = 'SecurityAlertsAPI',
cacheOptions,
} = requestOptions ?? {};
const url = getUrl(endpoint);

const response = await fetch(url, options);
let response;
if (useCache) {
response = await fetchWithCache({
url,
fetchOptions: options,
cacheOptions,
functionName,
});
if (!response) {
throw new Error(
'Security alerts API request failed: No response received',
);
}
return response;
}

response = await fetch(url, options);
if (!response.ok) {
throw new Error(
`Security alerts API request failed with status: ${response.status}`,
);
}

return response.json();
return await response.json();
}

function getUrl(endpoint: string) {
function getUrl(endpoint: string): string {
const host = process.env.SECURITY_ALERTS_API_URL;

if (!host) {
Expand Down
13 changes: 13 additions & 0 deletions test/e2e/mock-e2e.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const fs = require('fs');

const {
SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS,
} = require('../../shared/constants/security-provider');
const {
BRIDGE_DEV_API_BASE_URL,
BRIDGE_PROD_API_BASE_URL,
Expand All @@ -13,6 +16,7 @@ const {
SWAPS_API_V2_BASE_URL,
TOKEN_API_BASE_URL,
} = require('../../shared/constants/swaps');
const { SECURITY_ALERTS_PROD_API_BASE_URL } = require('./tests/ppom/constants');
const {
DEFAULT_FEATURE_FLAGS_RESPONSE: BRIDGE_DEFAULT_FEATURE_FLAGS_RESPONSE,
} = require('./tests/bridge/constants');
Expand Down Expand Up @@ -683,6 +687,15 @@ async function setupMocking(
};
});

await server
.forGet(`${SECURITY_ALERTS_PROD_API_BASE_URL}/supportedChains`)
.thenCallback(() => {
return {
statusCode: 200,
json: SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS,
};
});

await mockLensNameProvider(server);
await mockTokenNameProvider(server, chainId);

Expand Down

0 comments on commit b968841

Please sign in to comment.