Browse Source

Task/deprecate symbol endpoints in favor of symbols endpoints (#8333)

* Deprecate symbol endpoints in favor of symbols endpoints

* Update changelog
pull/8156/merge
Thomas Kaul 7 days ago
committed by GitHub
parent
commit
8606b3212c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 6
      CHANGELOG.md
  2. 26
      apps/api/src/app/__snapshots__/app.module.spec.ts.snap
  3. 4
      apps/api/src/app/app.module.ts
  4. 2
      apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts
  5. 2
      apps/api/src/app/endpoints/benchmarks/benchmarks.service.spec.ts
  6. 2
      apps/api/src/app/endpoints/benchmarks/benchmarks.service.time-zone.spec.ts
  7. 2
      apps/api/src/app/endpoints/benchmarks/benchmarks.service.ts
  8. 2
      apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.module.ts
  9. 2
      apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts
  10. 2
      apps/api/src/app/endpoints/market-data/market-data.controller.ts
  11. 2
      apps/api/src/app/endpoints/market-data/market-data.module.ts
  12. 2
      apps/api/src/app/endpoints/mcp/mcp.module.ts
  13. 2
      apps/api/src/app/endpoints/mcp/mcp.service.spec.ts
  14. 2
      apps/api/src/app/endpoints/mcp/mcp.service.ts
  15. 0
      apps/api/src/app/endpoints/symbols/get-lookup.dto.ts
  16. 14
      apps/api/src/app/endpoints/symbols/symbols.controller.ts
  17. 17
      apps/api/src/app/endpoints/symbols/symbols.module.ts
  18. 24
      apps/api/src/app/symbol/symbol.module.ts
  19. 14
      apps/api/src/services/symbol/symbol.module.ts
  20. 0
      apps/api/src/services/symbol/symbol.service.ts
  21. 2
      apps/api/src/services/twitter-bot/twitter-bot.module.ts
  22. 2
      apps/api/src/services/twitter-bot/twitter-bot.service.ts
  23. 2
      libs/common/src/lib/interfaces/index.ts
  24. 3
      libs/common/src/lib/interfaces/responses/symbol-response.interface.ts
  25. 2
      libs/ui/src/lib/services/admin.service.ts
  26. 8
      libs/ui/src/lib/services/data.service.ts
  27. 2
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.stories.ts

6
CHANGELOG.md

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Changed
- Deprecated the `api/v1/symbol` endpoints in favor of the `api/v1/symbols` endpoints
## 3.94.0 - 2026-10-28
### Changed

26
apps/api/src/app/__snapshots__/app.module.spec.ts.snap

@ -844,6 +844,32 @@ exports[`AppModule should keep the security of each route 1`] = `
"TransformDataSourceInResponseInterceptor",
],
},
"GET /symbols/:dataSource/:symbol": {
"guards": [
"AuthGuard('jwt')",
"HasPermissionGuard",
],
"interceptors": [
"TransformDataSourceInResponseInterceptor",
"TransformDataSourceInRequestInterceptor",
],
},
"GET /symbols/:dataSource/:symbol/:dateString": {
"guards": [
"AuthGuard('jwt')",
"HasPermissionGuard",
],
"interceptors": [],
},
"GET /symbols/lookup": {
"guards": [
"AuthGuard('jwt')",
"HasPermissionGuard",
],
"interceptors": [
"TransformDataSourceInResponseInterceptor",
],
},
"GET /tags": {
"allowDuringImpersonation": true,
"guards": [

4
apps/api/src/app/app.module.ts

@ -61,10 +61,10 @@ import { PlatformsModule } from './endpoints/platforms/platforms.module';
import { PublicModule } from './endpoints/public/public.module';
import { SitemapModule } from './endpoints/sitemap/sitemap.module';
import { SubscriptionModule } from './endpoints/subscription/subscription.module';
import { SymbolsModule } from './endpoints/symbols/symbols.module';
import { TagsModule } from './endpoints/tags/tags.module';
import { WatchlistModule } from './endpoints/watchlist/watchlist.module';
import { PortfolioModule } from './portfolio/portfolio.module';
import { SymbolModule } from './symbol/symbol.module';
import { UserModule } from './user/user.module';
@Module({
@ -150,7 +150,7 @@ import { UserModule } from './user/user.module';
}),
SitemapModule,
SubscriptionModule,
SymbolModule,
SymbolsModule,
TagsModule,
ThrottlerModule.forRootAsync({
imports: [ConfigurationModule],

2
apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts

@ -1,5 +1,4 @@
import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module';
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
@ -7,6 +6,7 @@ import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.mo
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { SymbolModule } from '@ghostfolio/api/services/symbol/symbol.module';
import { Module } from '@nestjs/common';

2
apps/api/src/app/endpoints/benchmarks/benchmarks.service.spec.ts

@ -1,8 +1,8 @@
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import { parseDate } from '@ghostfolio/common/helper';
import { DataSource } from '@prisma/client';

2
apps/api/src/app/endpoints/benchmarks/benchmarks.service.time-zone.spec.ts

@ -3,10 +3,10 @@
* @jest-environment-options {"timeZone": "America/New_York"}
*/
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import { parseDate } from '@ghostfolio/common/helper';
import { DataSource } from '@prisma/client';

2
apps/api/src/app/endpoints/benchmarks/benchmarks.service.ts

@ -1,8 +1,8 @@
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,

2
apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.module.ts

@ -1,4 +1,3 @@
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { CryptocurrencyModule } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.module';
import { AlphaVantageService } from '@ghostfolio/api/services/data-provider/alpha-vantage/alpha-vantage.service';
@ -18,6 +17,7 @@ import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { RedisCacheModule } from '@ghostfolio/api/services/redis-cache/redis-cache.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { SymbolModule } from '@ghostfolio/api/services/symbol/symbol.module';
import { Module } from '@nestjs/common';

2
apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts

@ -1,4 +1,3 @@
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { GhostfolioService as GhostfolioDataProviderService } from '@ghostfolio/api/services/data-provider/ghostfolio/ghostfolio.service';
@ -12,6 +11,7 @@ import {
import { FetchService } from '@ghostfolio/api/services/fetch/fetch.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import {
DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_SETUP_PERIOD,
DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_SETUP_PERIOD_MAX_REQUESTS_FACTOR,

2
apps/api/src/app/endpoints/market-data/market-data.controller.ts

@ -1,9 +1,9 @@
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-during-impersonation.decorator';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import { UpdateBulkMarketDataDto } from '@ghostfolio/common/dtos';
import { getCurrencyFromSymbol, isCurrency } from '@ghostfolio/common/helper';
import { MarketDataOfMarketsResponse } from '@ghostfolio/common/interfaces';

2
apps/api/src/app/endpoints/market-data/market-data.module.ts

@ -1,6 +1,6 @@
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
import { MarketDataModule as MarketDataServiceModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { SymbolModule } from '@ghostfolio/api/services/symbol/symbol.module';
import { Module } from '@nestjs/common';

2
apps/api/src/app/endpoints/mcp/mcp.module.ts

@ -1,4 +1,3 @@
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { environment } from '@ghostfolio/api/environments/environment';
import {
@ -14,6 +13,7 @@ import { ImportModule } from '@ghostfolio/api/services/import/import.module';
import { PortfolioTableModule } from '@ghostfolio/api/services/portfolio-table/portfolio-table.module';
import { PortfolioTableService } from '@ghostfolio/api/services/portfolio-table/portfolio-table.service';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { SymbolModule } from '@ghostfolio/api/services/symbol/symbol.module';
import { MCP_ENDPOINT } from '@ghostfolio/common/config';
import { Module } from '@nestjs/common';

2
apps/api/src/app/endpoints/mcp/mcp.service.spec.ts

@ -1,4 +1,3 @@
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { CallerFacingError } from '@ghostfolio/api/errors/caller-facing.error';
import { encodeDataSource } from '@ghostfolio/api/helper/data-source.helper';
@ -10,6 +9,7 @@ import { ImportValidationError } from '@ghostfolio/api/services/import/errors/im
import { ImportService } from '@ghostfolio/api/services/import/import.service';
import { PortfolioTableService } from '@ghostfolio/api/services/portfolio-table/portfolio-table.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import {
DEFAULT_LANGUAGE_CODE,
MCP_MAX_ACTIVITIES

2
apps/api/src/app/endpoints/mcp/mcp.service.ts

@ -1,4 +1,3 @@
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { CallerFacingError } from '@ghostfolio/api/errors/caller-facing.error';
import {
@ -12,6 +11,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { ImportService } from '@ghostfolio/api/services/import/import.service';
import { PortfolioTableService } from '@ghostfolio/api/services/portfolio-table/portfolio-table.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';

0
apps/api/src/app/symbol/get-lookup.dto.ts → apps/api/src/app/endpoints/symbols/get-lookup.dto.ts

14
apps/api/src/app/symbol/symbol.controller.ts → apps/api/src/app/endpoints/symbols/symbols.controller.ts

@ -1,10 +1,11 @@
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor';
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import {
DataProviderHistoricalResponse,
LookupResponse,
SymbolItem
SymbolResponse
} from '@ghostfolio/common/interfaces';
import type { RequestWithUser } from '@ghostfolio/common/types';
@ -28,10 +29,13 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { isEmpty } from 'lodash-es';
import { GetLookupDto } from './get-lookup.dto';
import { SymbolService } from './symbol.service';
@Controller('symbol')
export class SymbolController {
@Controller([
'symbols',
/** @deprecated */
'symbol'
])
export class SymbolsController {
public constructor(
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly symbolService: SymbolService
@ -72,7 +76,7 @@ export class SymbolController {
@Param('symbol') symbol: string,
@Query('includeHistoricalData', new ParseIntPipe({ optional: true }))
includeHistoricalData = 0
): Promise<SymbolItem> {
): Promise<SymbolResponse> {
if (!DataSource[dataSource]) {
throw new HttpException(
getReasonPhrase(StatusCodes.NOT_FOUND),

17
apps/api/src/app/endpoints/symbols/symbols.module.ts

@ -0,0 +1,17 @@
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module';
import { SymbolModule } from '@ghostfolio/api/services/symbol/symbol.module';
import { Module } from '@nestjs/common';
import { SymbolsController } from './symbols.controller';
@Module({
controllers: [SymbolsController],
imports: [
SymbolModule,
TransformDataSourceInRequestModule,
TransformDataSourceInResponseModule
]
})
export class SymbolsModule {}

24
apps/api/src/app/symbol/symbol.module.ts

@ -1,24 +0,0 @@
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { SymbolController } from './symbol.controller';
import { SymbolService } from './symbol.service';
@Module({
controllers: [SymbolController],
exports: [SymbolService],
imports: [
DataProviderModule,
MarketDataModule,
PrismaModule,
TransformDataSourceInRequestModule,
TransformDataSourceInResponseModule
],
providers: [SymbolService]
})
export class SymbolModule {}

14
apps/api/src/services/symbol/symbol.module.ts

@ -0,0 +1,14 @@
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { Module } from '@nestjs/common';
import { SymbolService } from './symbol.service';
@Module({
exports: [SymbolService],
imports: [DataProviderModule, MarketDataModule, PrismaModule],
providers: [SymbolService]
})
export class SymbolModule {}

0
apps/api/src/app/symbol/symbol.service.ts → apps/api/src/services/symbol/symbol.service.ts

2
apps/api/src/services/twitter-bot/twitter-bot.module.ts

@ -1,7 +1,7 @@
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { SymbolModule } from '@ghostfolio/api/services/symbol/symbol.module';
import { TwitterBotService } from '@ghostfolio/api/services/twitter-bot/twitter-bot.service';
import { Module } from '@nestjs/common';

2
apps/api/src/services/twitter-bot/twitter-bot.service.ts

@ -1,7 +1,7 @@
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { SymbolService } from '@ghostfolio/api/services/symbol/symbol.service';
import { ghostfolioFearAndGreedIndexSymbolStocks } from '@ghostfolio/common/config';
import {
resolveFearAndGreedIndex,

2
libs/common/src/lib/interfaces/index.ts

@ -90,6 +90,7 @@ import type { PortfolioReportResponse } from './responses/portfolio-report.inter
import type { PublicPortfolioResponse } from './responses/public-portfolio-response.interface';
import type { QuotesResponse } from './responses/quotes-response.interface';
import type { RedeemCouponResponse } from './responses/redeem-coupon-response.interface';
import type { SymbolResponse } from './responses/symbol-response.interface';
import type { WatchlistResponse } from './responses/watchlist-response.interface';
import type { RuleSettings } from './rule-settings.interface';
import type { ScraperConfiguration } from './scraper-configuration.interface';
@ -207,6 +208,7 @@ export {
Statistics,
SubscriptionOffer,
SymbolItem,
SymbolResponse,
SystemMessage,
User,
UserItem,

3
libs/common/src/lib/interfaces/responses/symbol-response.interface.ts

@ -0,0 +1,3 @@
import type { SymbolItem } from '../symbol-item.interface';
export interface SymbolResponse extends SymbolItem {}

2
libs/ui/src/lib/services/admin.service.ts

@ -172,7 +172,7 @@ export class AdminService {
dateString,
symbol
}: { dateString: string } & AssetProfileIdentifier) {
const url = `/api/v1/symbol/${dataSource}/${encodeURIComponent(symbol)}/${dateString}`;
const url = `/api/v1/symbols/${dataSource}/${encodeURIComponent(symbol)}/${dateString}`;
return this.http.get<DataProviderHistoricalResponse>(url);
}

8
libs/ui/src/lib/services/data.service.ts

@ -60,7 +60,7 @@ import {
PortfolioReportResponse,
PublicPortfolioResponse,
RedeemCouponResponse,
SymbolItem,
SymbolResponse,
User,
UserItem,
WatchlistResponse
@ -826,8 +826,8 @@ export class DataService {
params = params.append('includeHistoricalData', includeHistoricalData);
}
return this.http.get<SymbolItem>(
`/api/v1/symbol/${dataSource}/${encodeURIComponent(symbol)}`,
return this.http.get<SymbolResponse>(
`/api/v1/symbols/${dataSource}/${encodeURIComponent(symbol)}`,
{
params
}
@ -848,7 +848,7 @@ export class DataService {
}
return this.http
.get<LookupResponse>('/api/v1/symbol/lookup', { params })
.get<LookupResponse>('/api/v1/symbols/lookup', { params })
.pipe(
map(({ items }) => {
return items;

2
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.stories.ts

@ -91,7 +91,7 @@ export default {
useValue: new HttpClientMock(
new Map([
[
'/api/v1/symbol/lookup',
'/api/v1/symbols/lookup',
{
items: FILTERED_OPTIONS
}

Loading…
Cancel
Save