Browse Source

Feature/improve various functions of data providers (#5418)

* Improve various functions of data providers

* Reuse request timeout
* Handle exception in getQuotes() of FinancialModelingPrepService

* Update changelog
pull/5424/head
Thomas Kaul 5 days ago
committed by GitHub
parent
commit
f3fb123309
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      CHANGELOG.md
  2. 9
      apps/api/src/services/data-provider/coingecko/coingecko.service.ts
  3. 29
      apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts
  4. 18
      apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
  5. 4
      apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts

5
CHANGELOG.md

@ -9,9 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Reused the request timeout in various functions of the data providers
- Refactored the _ZEN_ page to standalone
- Upgraded `chart.js` from version `4.4.9` to `4.5.0`
### Fixed
- Handled an exception in the get quotes functionality of the _Financial Modeling Prep_ service
## 2.194.0 - 2025-08-27
### Added

9
apps/api/src/services/data-provider/coingecko/coingecko.service.ts

@ -214,15 +214,16 @@ export class CoinGeckoService implements DataProviderInterface {
return 'bitcoin';
}
public async search({ query }: GetSearchParams): Promise<LookupResponse> {
public async search({
query,
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT')
}: GetSearchParams): Promise<LookupResponse> {
let items: LookupItem[] = [];
try {
const { coins } = await fetch(`${this.apiUrl}/search?query=${query}`, {
headers: this.headers,
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
signal: AbortSignal.timeout(requestTimeout)
}).then((res) => res.json());
items = coins.map(({ id: symbol, name }) => {

29
apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts

@ -51,9 +51,13 @@ export class EodHistoricalDataService implements DataProviderInterface {
}
public async getAssetProfile({
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'),
symbol
}: GetAssetProfileParams): Promise<Partial<SymbolProfile>> {
const [searchResult] = await this.getSearchResult(symbol);
const [searchResult] = await this.getSearchResult({
requestTimeout,
query: symbol
});
if (!searchResult) {
return undefined;
@ -304,8 +308,11 @@ export class EodHistoricalDataService implements DataProviderInterface {
return 'AAPL.US';
}
public async search({ query }: GetSearchParams): Promise<LookupResponse> {
const searchResult = await this.getSearchResult(query);
public async search({
query,
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT')
}: GetSearchParams): Promise<LookupResponse> {
const searchResult = await this.getSearchResult({ query, requestTimeout });
return {
items: searchResult
@ -394,7 +401,13 @@ export class EodHistoricalDataService implements DataProviderInterface {
return name;
}
private async getSearchResult(aQuery: string) {
private async getSearchResult({
query,
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT')
}: {
query: string;
requestTimeout?: number;
}) {
let searchResult: (LookupItem & {
assetClass: AssetClass;
assetSubClass: AssetSubClass;
@ -403,11 +416,9 @@ export class EodHistoricalDataService implements DataProviderInterface {
try {
const response = await fetch(
`${this.URL}/search/${aQuery}?api_token=${this.apiKey}`,
`${this.URL}/search/${query}?api_token=${this.apiKey}`,
{
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
signal: AbortSignal.timeout(requestTimeout)
}
).then((res) => res.json());
@ -433,7 +444,7 @@ export class EodHistoricalDataService implements DataProviderInterface {
let message = error;
if (['AbortError', 'TimeoutError'].includes(error?.name)) {
message = `RequestError: The operation to search for ${aQuery} was aborted because the request to the data provider took more than ${(
message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${(
this.configurationService.get('REQUEST_TIMEOUT') / 1000
).toFixed(3)} seconds`;
}

18
apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts

@ -365,8 +365,13 @@ export class FinancialModelingPrepService implements DataProviderInterface {
await Promise.all(
quotes.map(({ symbol }) => {
return this.getAssetProfile({ symbol }).then(({ currency }) => {
currencyBySymbolMap[symbol] = { currency };
return this.getAssetProfile({
requestTimeout,
symbol
}).then((assetProfile) => {
if (assetProfile?.currency) {
currencyBySymbolMap[symbol] = { currency: assetProfile.currency };
}
});
})
);
@ -411,7 +416,10 @@ export class FinancialModelingPrepService implements DataProviderInterface {
return 'AAPL';
}
public async search({ query }: GetSearchParams): Promise<LookupResponse> {
public async search({
query,
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT')
}: GetSearchParams): Promise<LookupResponse> {
const assetProfileBySymbolMap: {
[symbol: string]: Partial<SymbolProfile>;
} = {};
@ -422,9 +430,7 @@ export class FinancialModelingPrepService implements DataProviderInterface {
const result = await fetch(
`${this.getUrl({ version: 'stable' })}/search-isin?isin=${query.toUpperCase()}&apikey=${this.apiKey}`,
{
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
signal: AbortSignal.timeout(requestTimeout)
}
).then((res) => res.json());

4
apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts

@ -284,8 +284,8 @@ export class GhostfolioService implements DataProviderInterface {
}
public async search({
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'),
query
query,
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT')
}: GetSearchParams): Promise<LookupResponse> {
let searchResult: LookupResponse = { items: [] };

Loading…
Cancel
Save