Skip to content

Commit

Permalink
Automatically type all network requests as Raw
Browse files Browse the repository at this point in the history
  • Loading branch information
iamacook committed Nov 26, 2024
1 parent cb3a3e7 commit 964c45b
Show file tree
Hide file tree
Showing 62 changed files with 2,913 additions and 2,002 deletions.
2 changes: 1 addition & 1 deletion src/datasources/balances-api/balances-api.manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ describe('Balances API Manager Tests', () => {
throw new Error(`Unexpected key: ${key}`);
});
configApiMock.getChain.mockResolvedValue(rawify(chain));
dataSourceMock.get.mockResolvedValue([]);
dataSourceMock.get.mockResolvedValue(rawify([]));
coingeckoApiMock.getTokenPrices.mockResolvedValue(rawify([]));
const balancesApiManager = new BalancesApiManager(
configurationService,
Expand Down
25 changes: 15 additions & 10 deletions src/datasources/balances-api/coingecko-api.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { sortBy } from 'lodash';
import type { ILoggingService } from '@/logging/logging.interface';
import { chainBuilder } from '@/domain/chains/entities/__tests__/chain.builder';
import { pricesProviderBuilder } from '@/domain/chains/entities/__tests__/prices-provider.builder';
import { rawify } from '@/validation/entities/raw.entity';

const mockCacheFirstDataSource = jest.mocked({
get: jest.fn(),
Expand Down Expand Up @@ -109,7 +110,9 @@ describe('CoingeckoAPI', () => {
});

it('should return fiat codes (using an API key)', async () => {
mockCacheFirstDataSource.get.mockResolvedValue(['usd', 'eur', 'eth']);
mockCacheFirstDataSource.get.mockResolvedValue(
rawify(['usd', 'eur', 'eth']),
);

const fiatCodes = await service.getFiatCodes();

Expand All @@ -128,7 +131,9 @@ describe('CoingeckoAPI', () => {
});

it('should return fiat codes (with no API key)', async () => {
mockCacheFirstDataSource.get.mockResolvedValue(['usd', 'eur', 'eth']);
mockCacheFirstDataSource.get.mockResolvedValue(
rawify(['usd', 'eur', 'eth']),
);
fakeConfigurationService.set('balances.providers.safe.prices.apiKey', null);
const service = new CoingeckoApi(
fakeConfigurationService,
Expand Down Expand Up @@ -187,7 +192,7 @@ describe('CoingeckoAPI', () => {
};
mockCacheService.hGet.mockResolvedValue(undefined);
mockNetworkService.get.mockResolvedValue({
data: coingeckoPrice,
data: rawify(coingeckoPrice),
status: 200,
});

Expand Down Expand Up @@ -238,7 +243,7 @@ describe('CoingeckoAPI', () => {
};
mockCacheService.hGet.mockResolvedValue(undefined);
mockNetworkService.get.mockResolvedValue({
data: coingeckoPrice,
data: rawify(coingeckoPrice),
status: 200,
});
const service = new CoingeckoApi(
Expand Down Expand Up @@ -298,7 +303,7 @@ describe('CoingeckoAPI', () => {
};
mockCacheService.hGet.mockResolvedValue(undefined);
mockNetworkService.get.mockResolvedValue({
data: coingeckoPrice,
data: rawify(coingeckoPrice),
status: 200,
});

Expand Down Expand Up @@ -399,7 +404,7 @@ describe('CoingeckoAPI', () => {
};
mockCacheService.hGet.mockResolvedValue(undefined);
mockNetworkService.get.mockResolvedValue({
data: coingeckoPrice,
data: rawify(coingeckoPrice),
status: 200,
});
fakeConfigurationService.set(
Expand Down Expand Up @@ -503,7 +508,7 @@ describe('CoingeckoAPI', () => {
);
mockCacheService.hGet.mockResolvedValueOnce(undefined);
mockNetworkService.get.mockResolvedValue({
data: coingeckoPrice,
data: rawify(coingeckoPrice),
status: 200,
});

Expand Down Expand Up @@ -607,7 +612,7 @@ describe('CoingeckoAPI', () => {
);
mockCacheService.hGet.mockResolvedValueOnce(undefined);
mockNetworkService.get.mockResolvedValue({
data: coingeckoPrice,
data: rawify(coingeckoPrice),
status: 200,
});

Expand Down Expand Up @@ -685,7 +690,7 @@ describe('CoingeckoAPI', () => {
const fiatCode = faker.finance.currencyCode();
const lowerCaseFiatCode = fiatCode.toLowerCase();
const expectedAssetPrice: AssetPrice = { gnosis: { eur: 98.86 } };
mockCacheFirstDataSource.get.mockResolvedValue(expectedAssetPrice);
mockCacheFirstDataSource.get.mockResolvedValue(rawify(expectedAssetPrice));

await service.getNativeCoinPrice({ chain, fiatCode });

Expand Down Expand Up @@ -714,7 +719,7 @@ describe('CoingeckoAPI', () => {
const fiatCode = faker.finance.currencyCode();
const lowerCaseFiatCode = fiatCode.toLowerCase();
const expectedAssetPrice: AssetPrice = { gnosis: { eur: 98.86 } };
mockCacheFirstDataSource.get.mockResolvedValue(expectedAssetPrice);
mockCacheFirstDataSource.get.mockResolvedValue(rawify(expectedAssetPrice));
fakeConfigurationService.set('balances.providers.safe.prices.apiKey', null);
const service = new CoingeckoApi(
fakeConfigurationService,
Expand Down
10 changes: 3 additions & 7 deletions src/datasources/balances-api/coingecko-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ import { Chain } from '@/domain/chains/entities/chain.entity';
import { z } from 'zod';
import { rawify, type Raw } from '@/validation/entities/raw.entity';

/**
* TODO: Move all usage of Raw to NetworkService/CacheFirstDataSource after fully migrated
* to "Raw" type implementation.
*/
@Injectable()
export class CoingeckoApi implements IPricesApi {
/**
Expand Down Expand Up @@ -134,7 +130,7 @@ export class CoingeckoApi implements IPricesApi {
});
const url = `${this.baseUrl}/simple/price`;
const result = await this.dataSource
.get<Raw<AssetPrice>>({
.get<AssetPrice>({
cacheDir,
url,
networkRequest: {
Expand Down Expand Up @@ -221,7 +217,7 @@ export class CoingeckoApi implements IPricesApi {
const cacheDir = CacheRouter.getPriceFiatCodesCacheDir();
const url = `${this.baseUrl}/simple/supported_vs_currencies`;
const result = await this.dataSource
.get<Raw<string[]>>({
.get<string[]>({
cacheDir,
url,
networkRequest: {
Expand Down Expand Up @@ -337,7 +333,7 @@ export class CoingeckoApi implements IPricesApi {
}): Promise<Raw<AssetPrice>> {
try {
const url = `${this.baseUrl}/simple/token_price/${args.chainName}`;
const { data } = await this.networkService.get<Raw<AssetPrice>>({
const { data } = await this.networkService.get<AssetPrice>({
url,
networkRequest: {
params: {
Expand Down
8 changes: 2 additions & 6 deletions src/datasources/balances-api/safe-balances-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ import { Chain } from '@/domain/chains/entities/chain.entity';
import { rawify, type Raw } from '@/validation/entities/raw.entity';
import { AssetPricesSchema } from '@/datasources/balances-api/entities/asset-price.entity';

/**
* TODO: Move all usage of Raw to NetworkService/CacheFirstDataSource after fully migrated
* to "Raw" type implementation.
*/
@Injectable()
export class SafeBalancesApi implements IBalancesApi {
private readonly defaultExpirationTimeInSeconds: number;
Expand Down Expand Up @@ -71,7 +67,7 @@ export class SafeBalancesApi implements IBalancesApi {
});
const url = `${this.baseUrl}/api/v1/safes/${args.safeAddress}/balances/`;
const data = await this.dataSource
.get<Raw<Balance[]>>({
.get<Balance[]>({
cacheDir,
url,
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
Expand Down Expand Up @@ -116,7 +112,7 @@ export class SafeBalancesApi implements IBalancesApi {
...args,
});
const url = `${this.baseUrl}/api/v2/safes/${args.safeAddress}/collectibles/`;
return await this.dataSource.get<Raw<Page<Collectible>>>({
return await this.dataSource.get<Page<Collectible>>({
cacheDir,
url,
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { INetworkService } from '@/datasources/network/network.service.inte
import { balancesProviderBuilder } from '@/domain/chains/entities/__tests__/balances-provider.builder';
import { chainBuilder } from '@/domain/chains/entities/__tests__/chain.builder';
import type { ILoggingService } from '@/logging/logging.interface';
import { rawify } from '@/validation/entities/raw.entity';
import { faker } from '@faker-js/faker';
import { getAddress } from 'viem';

Expand Down Expand Up @@ -115,7 +116,7 @@ describe('ZerionBalancesApiService', () => {
const safeAddress = getAddress(faker.finance.ethereumAddress());
const fiatCode = faker.helpers.arrayElement(supportedFiatCodes);
mockNetworkService.get.mockResolvedValue({
data: { data: [] },
data: rawify({ data: [] }),
status: 200,
});

Expand Down Expand Up @@ -149,7 +150,7 @@ describe('ZerionBalancesApiService', () => {
const safeAddress = getAddress(faker.finance.ethereumAddress());
const fiatCode = faker.helpers.arrayElement(supportedFiatCodes);
mockNetworkService.get.mockResolvedValue({
data: { data: [] },
data: rawify({ data: [] }),
status: 200,
});

Expand Down
27 changes: 13 additions & 14 deletions src/datasources/balances-api/zerion-balances-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ import { z } from 'zod';

export const IZerionBalancesApi = Symbol('IZerionBalancesApi');

/**
* TODO: Move all usage of Raw to NetworkService/CacheFirstDataSource after fully migrated
* to "Raw" type implementation.
*/
@Injectable()
export class ZerionBalancesApi implements IBalancesApi {
private static readonly COLLECTIBLES_SORTING = '-floor_price';
Expand Down Expand Up @@ -138,17 +134,18 @@ export class ZerionBalancesApi implements IBalancesApi {
sort: 'value',
},
};
const { data } = await this.networkService.get<ZerionBalances>({
url,
networkRequest,
});
const zerionBalances = ZerionBalancesSchema.parse(data);
const zerionBalances = await this.networkService
.get<ZerionBalances>({
url,
networkRequest,
})
.then(({ data }) => ZerionBalancesSchema.parse(data));
await this.cacheService.hSet(
cacheDir,
JSON.stringify(zerionBalances.data),
this.defaultExpirationTimeInSeconds,
);
return this._mapBalances(chainName, data.data);
return this._mapBalances(chainName, zerionBalances.data);
} catch (error) {
if (error instanceof LimitReachedError) {
throw error;
Expand Down Expand Up @@ -197,10 +194,12 @@ export class ZerionBalancesApi implements IBalancesApi {
...(pageAfter && { 'page[after]': pageAfter }),
},
};
const { data } = await this.networkService.get<ZerionCollectibles>({
url,
networkRequest,
});
const data = await this.networkService
.get<ZerionCollectibles>({
url,
networkRequest,
})
.then(({ data }) => ZerionCollectiblesSchema.parse(data));
await this.cacheService.hSet(
cacheDir,
JSON.stringify(data),
Expand Down
9 changes: 5 additions & 4 deletions src/datasources/cache/cache.first.data.source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { IConfigurationService } from '@/config/configuration.service.interface';
import { isArray } from 'lodash';
import { Safe } from '@/domain/safe/entities/safe.entity';
import { Raw } from '@/validation/entities/raw.entity';

/**
* A data source which tries to retrieve values from cache using
Expand Down Expand Up @@ -70,7 +71,7 @@ export class CacheFirstDataSource {
notFoundExpireTimeSeconds: number;
networkRequest?: NetworkRequest;
expireTimeSeconds?: number;
}): Promise<T> {
}): Promise<Raw<T>> {
const cached = await this.cacheService.hGet(args.cacheDir);
if (cached != null) return this._getFromCachedData(args.cacheDir, cached);

Expand Down Expand Up @@ -117,7 +118,7 @@ export class CacheFirstDataSource {
url: string;
networkRequest?: NetworkRequest;
expireTimeSeconds?: number;
}): Promise<T> {
}): Promise<Raw<T>> {
const { key, field } = args.cacheDir;
this.loggingService.debug({ type: 'cache_miss', key, field });
const startTimeMs = Date.now();
Expand All @@ -143,15 +144,15 @@ export class CacheFirstDataSource {
this.logTransactionsCacheWrite(
startTimeMs,
args.cacheDir,
data as Page<Transaction>,
data as unknown as Page<Transaction>,
);
}

if (this.areDebugLogsEnabled && args.cacheDir.key.includes('_safe_')) {
this.logSafeMetadataCacheWrite(
startTimeMs,
args.cacheDir,
data as Safe,
data as unknown as Safe,
);
}

Expand Down
13 changes: 7 additions & 6 deletions src/datasources/config-api/config-api.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { chainBuilder } from '@/domain/chains/entities/__tests__/chain.builder';
import { DataSourceError } from '@/domain/errors/data-source.error';
import { safeAppBuilder } from '@/domain/safe-apps/entities/__tests__/safe-app.builder';
import type { ILoggingService } from '@/logging/logging.interface';
import { rawify } from '@/validation/entities/raw.entity';
import { faker } from '@faker-js/faker';

const dataSource = {
Expand Down Expand Up @@ -79,7 +80,7 @@ describe('ConfigApi', () => {

it('should return the chains retrieved', async () => {
const data = [chainBuilder().build(), chainBuilder().build()];
mockDataSource.get.mockResolvedValue(data);
mockDataSource.get.mockResolvedValue(rawify(data));

const actual = await service.getChains({});

Expand All @@ -97,7 +98,7 @@ describe('ConfigApi', () => {

it('should return the chain retrieved', async () => {
const data = chainBuilder().build();
mockDataSource.get.mockResolvedValue(data);
mockDataSource.get.mockResolvedValue(rawify(data));

const actual = await service.getChain(data.chainId);

Expand All @@ -115,7 +116,7 @@ describe('ConfigApi', () => {
it('should return the safe apps retrieved by chainId', async () => {
const chainId = faker.string.numeric();
const data = [safeAppBuilder().build(), safeAppBuilder().build()];
mockDataSource.get.mockResolvedValue(data);
mockDataSource.get.mockResolvedValue(rawify(data));

const actual = await service.getSafeApps({ chainId });

Expand All @@ -140,7 +141,7 @@ describe('ConfigApi', () => {
const chainId = faker.string.numeric();
const url = faker.internet.url({ appendSlash: false });
const data = [safeAppBuilder().build(), safeAppBuilder().build()];
mockDataSource.get.mockResolvedValue(data);
mockDataSource.get.mockResolvedValue(rawify(data));

const actual = await service.getSafeApps({ chainId, url });

Expand All @@ -163,7 +164,7 @@ describe('ConfigApi', () => {
const chainId = faker.string.numeric();
const clientUrl = faker.internet.url({ appendSlash: false });
const data = [safeAppBuilder().build(), safeAppBuilder().build()];
mockDataSource.get.mockResolvedValue(data);
mockDataSource.get.mockResolvedValue(rawify(data));

const actual = await service.getSafeApps({ chainId, clientUrl });

Expand All @@ -187,7 +188,7 @@ describe('ConfigApi', () => {
const clientUrl = faker.internet.url({ appendSlash: false });
const onlyListed = faker.datatype.boolean();
const data = [safeAppBuilder().build(), safeAppBuilder().build()];
mockDataSource.get.mockResolvedValue(data);
mockDataSource.get.mockResolvedValue(rawify(data));

const actual = await service.getSafeApps({
chainId,
Expand Down
8 changes: 2 additions & 6 deletions src/datasources/config-api/config-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ import { ILoggingService, LoggingService } from '@/logging/logging.interface';
import { Raw } from '@/validation/entities/raw.entity';
import { Inject, Injectable } from '@nestjs/common';

/**
* TODO: Move all usage of Raw to CacheFirstDataSource after fully migrated
* to "Raw" type implementation.
*/
@Injectable()
export class ConfigApi implements IConfigApi {
private readonly baseUri: string;
Expand Down Expand Up @@ -57,7 +53,7 @@ export class ConfigApi implements IConfigApi {
const url = `${this.baseUri}/api/v1/chains`;
const params = { limit: args.limit, offset: args.offset };
const cacheDir = CacheRouter.getChainsCacheDir(args);
return await this.dataSource.get<Raw<Chain>>({
return await this.dataSource.get<Chain>({
cacheDir,
url,
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
Expand All @@ -73,7 +69,7 @@ export class ConfigApi implements IConfigApi {
try {
const url = `${this.baseUri}/api/v1/chains/${chainId}`;
const cacheDir = CacheRouter.getChainCacheDir(chainId);
return await this.dataSource.get<Raw<Chain>>({
return await this.dataSource.get<Chain>({
cacheDir,
url,
notFoundExpireTimeSeconds: this.defaultNotFoundExpirationTimeSeconds,
Expand Down
Loading

0 comments on commit 964c45b

Please sign in to comment.