Skip to content

Commit 5866408

Browse files
authored
Making the switch to a BFF structure (#20)
1 parent 1ce9a92 commit 5866408

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1089
-831
lines changed

Sources/Grodt/Application/routes.swift

Lines changed: 5 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -2,141 +2,9 @@ import Vapor
22
import AlphaSwiftage
33

44
func routes(_ app: Application) async throws {
5-
6-
let alphavantage = try await AlphaVantageService(serviceType: .rapidAPI(apiKey: app.config.alphavantageAPIKey()) )
7-
8-
let currencyDTOMapper = CurrencyDTOMapper()
9-
let tickerDTOMapper = TickerDTOMapper()
10-
let loginResponseDTOMapper = LoginResponseDTOMapper()
11-
let transactionDTOMapper = TransactionDTOMapper(currencyDTOMapper: currencyDTOMapper, database: app.db)
12-
let tickerRepository = PostgresTickerRepository(database: app.db)
13-
let livePriceService = LivePriceService(alphavantage: alphavantage)
14-
let quoteCache = PostgresQuoteRepository(database: app.db)
15-
let priceService = CachedPriceService(priceService: livePriceService, cache: quoteCache)
16-
let performanceCalculator = HoldingsPerformanceCalculator(priceService: priceService)
17-
let investmentDTOMapper = InvestmentDTOMapper(currencyDTOMapper: currencyDTOMapper,
18-
transactionDTOMapper: transactionDTOMapper,
19-
tickerRepository: tickerRepository,
20-
priceService: priceService)
21-
22-
let userRepository = PostgresUserRepository(database: app.db)
23-
let portfolioRepository = PostgresPortfolioRepository(database: app.db)
24-
let transactionRepository = PostgresTransactionRepository(database: app.db)
25-
let brokerageRepository = PostgresBrokerageRepository(database: app.db)
26-
let brokerageAccountRepository = PostgresBrokerageAccountRepository(database: app.db)
27-
let brokerageAccountDailyPerformanceRepository = PostgresBrokerageAccountDailyPerformanceRepository(database: app.db)
28-
let brokerageDailyPerformanceRepository = PostgresBrokerageDailyPerformanceRepository(database: app.db)
29-
30-
let portfolioDTOMapper = PortfolioDTOMapper(investmentDTOMapper: investmentDTOMapper,
31-
transactionDTOMapper: transactionDTOMapper,
32-
performanceDTOMapper: DatedPerformanceDTOMapper(),
33-
currencyDTOMapper: currencyDTOMapper)
34-
let currencyRepository = PostgresCurrencyRepository(database: app.db)
35-
let portfolioPerformanceUpdater = PortfolioPerformanceUpdater(
36-
userRepository: userRepository,
37-
portfolioRepository: portfolioRepository,
38-
tickerRepository: PostgresTickerRepository(database: app.db),
39-
quoteCache: quoteCache,
40-
priceService: priceService,
41-
performanceCalculator: performanceCalculator,
42-
portfolioDailyRepo: PostgresPortfolioDailyPerformanceRepository(db: app.db))
43-
let transactionChangedHandler = TransactionChangedHandler(portfolioRepository: PostgresPortfolioRepository(database: app.db),
44-
historicalPerformanceUpdater: portfolioPerformanceUpdater)
45-
46-
var tickersController = TickersController(tickerRepository: tickerRepository,
47-
dataMapper: tickerDTOMapper,
48-
tickerService: alphavantage)
49-
let tickerChangeHandler = TickerChangeHandler(priceService: priceService)
50-
tickersController.delegate = tickerChangeHandler
51-
52-
let investmentsController = InvestmentController(portfolioRepository: portfolioRepository,
53-
dataMapper: investmentDTOMapper)
54-
55-
let accountController = AccountController(userRepository: userRepository, dataMapper: UserDTOMapper())
56-
57-
let globalRateLimiter = RateLimiterMiddleware(maxRequests: 100, perSeconds: 60)
58-
let loginRateLimiter = RateLimiterMiddleware(maxRequests: 3, perSeconds: 60)
59-
60-
app.middleware.use(app.sessions.middleware)
61-
app.middleware.use(globalRateLimiter)
62-
63-
let tokenAuthMiddleware = UserToken.authenticator()
64-
let guardAuthMiddleware = User.guardMiddleware()
65-
66-
try app.group("api") { api in
67-
// Public routes
68-
try api
69-
.grouped(loginRateLimiter)
70-
.register(collection: UserController(dtoMapper: loginResponseDTOMapper))
71-
72-
// Protected routes
73-
let protected = api.grouped([
74-
UserTokenCookieAuthenticator(),
75-
tokenAuthMiddleware,
76-
OriginRefererCheckMiddleware(),
77-
guardAuthMiddleware
78-
])
79-
try protected.register(collection:
80-
PortfoliosController(
81-
portfolioRepository: PostgresPortfolioRepository(database: app.db),
82-
currencyRepository: currencyRepository,
83-
historicalPortfolioPerformanceUpdater: portfolioPerformanceUpdater,
84-
portfolioDailyRepo: PostgresPortfolioDailyPerformanceRepository(db: app.db),
85-
dataMapper: portfolioDTOMapper)
86-
)
87-
88-
let transactionController = TransactionsController(transactionsRepository: transactionRepository,
89-
currencyRepository: currencyRepository,
90-
dataMapper: transactionDTOMapper)
91-
transactionController.delegate = transactionChangedHandler
92-
try protected.register(collection: transactionController)
93-
try protected.register(collection: tickersController)
94-
try protected.register(collection: investmentsController)
95-
try protected.register(collection: accountController)
96-
try protected.register(collection: BrokerageController(brokerageRepository: brokerageRepository,
97-
dtoMapper: BrokerageDTOMapper(brokerageRepository: brokerageRepository,
98-
accountDTOMapper: BrokerageAccountDTOMapper(brokerageAccountRepository: brokerageAccountRepository,
99-
currencyMapper: currencyDTOMapper, database: app.db),
100-
database: app.db),
101-
accounts: brokerageAccountRepository,
102-
currencyMapper: currencyDTOMapper,
103-
performanceRepository: brokerageDailyPerformanceRepository,
104-
performanceDTOMapper: DatedPerformanceDTOMapper()))
105-
try protected.register(collection: BrokerageAccountController(brokerageAccountRepository: brokerageAccountRepository,
106-
performanceRepository: brokerageAccountDailyPerformanceRepository,
107-
performanceDTOMapper: DatedPerformanceDTOMapper(),
108-
currencyMapper: currencyDTOMapper,
109-
transactionDTOMapper: transactionDTOMapper,
110-
currencyRepository: currencyRepository))
111-
}
112-
113-
if app.environment != .testing {
114-
let nightlyUpdaterJob = NightlyUpdaterJob(
115-
tickerPriceUpdater: TickerPriceUpdater(tickerRepository: tickerRepository,
116-
quoteCache: quoteCache,
117-
priceService: priceService),
118-
portfolioPerformanceUpdater: portfolioPerformanceUpdater,
119-
brokerageAccountPerformanceUpdater: BrokerageAccountPerformanceUpdater(transactionRepository: transactionRepository,
120-
brokerageAccountRepository: brokerageAccountRepository,
121-
accountDailyRepository: brokerageAccountDailyPerformanceRepository,
122-
userRepository: userRepository,
123-
calculator: performanceCalculator),
124-
brokeragePerformanceUpdater: BrokeragePerformanceUpdater(userRepository: userRepository,
125-
brokerageAccountRepository: brokerageAccountRepository,
126-
accountDailyRepository: brokerageAccountDailyPerformanceRepository,
127-
brokerageDailyRepository: brokerageDailyPerformanceRepository)
128-
)
129-
app.queues.schedule(nightlyUpdaterJob)
130-
.daily()
131-
.at(3, 0)
132-
133-
app.queues.add(LoggingJobEventDelegate(logger: app.logger))
134-
135-
let userTokenCleanerJob = UserTokenClearUpJob(userTokenClearing: UserTokenClearer(database: app.db))
136-
app.queues.schedule(userTokenCleanerJob)
137-
.daily()
138-
139-
try app.queues.startScheduledJobs()
140-
try app.queues.startInProcessJobs()
141-
}
5+
let container = try await buildAppContainer(app)
6+
installGlobalMiddleware(app)
7+
try registerLoginRoutes(app, container)
8+
try registerSkiRoutes(app, container)
9+
try scheduleNightlyJobs(app, container)
14210
}
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
import Vapor
2+
import AlphaSwiftage
3+
4+
struct AppContainer {
5+
// External services
6+
let alphavantage: AlphaVantageService
7+
8+
// Mappers
9+
let currencyDTOMapper: CurrencyDTOMapper
10+
let tickerDTOMapper: TickerDTOMapper
11+
let loginResponseDTOMapper: LoginResponseDTOMapper
12+
let transactionDTOMapper: TransactionDTOMapper
13+
let portfolioDTOMapper: PortfolioDTOMapper
14+
let performanceDTOMapper: DatedPerformanceDTOMapper
15+
16+
// Core repos/services
17+
let tickerRepository: PostgresTickerRepository
18+
let livePriceService: LivePriceService
19+
let quoteCache: PostgresQuoteRepository
20+
let priceService: CachedPriceService
21+
22+
let userRepository: PostgresUserRepository
23+
let portfolioRepository: PostgresPortfolioRepository
24+
let transactionRepository: PostgresTransactionRepository
25+
let brokerageRepository: PostgresBrokerageRepository
26+
let brokerageAccountRepository: PostgresBrokerageAccountRepository
27+
let brokerageAccountDailyPerformanceRepository: PostgresBrokerageAccountDailyPerformanceRepository
28+
let brokerageDailyPerformanceRepository: PostgresBrokerageDailyPerformanceRepository
29+
30+
let currencyRepository: PostgresCurrencyRepository
31+
32+
// Calculators / updaters
33+
let performanceCalculator: HoldingsPerformanceCalculating
34+
let portfolioPerformanceUpdater: PortfolioPerformanceUpdater
35+
36+
let portfolioService: PortfolioService
37+
let accountService: AccountService
38+
let brokerageService: BrokerageService
39+
let investmentService: InvestmentService
40+
let transactionService: TransactionService
41+
let tickersService: TickersService
42+
let brokerageAccountsService: BrokerageAccountsService
43+
}
44+
45+
func buildAppContainer(_ app: Application) async throws -> AppContainer {
46+
let alphavantage = try await AlphaVantageService(
47+
serviceType: .rapidAPI(apiKey: app.config.alphavantageAPIKey())
48+
)
49+
50+
let currencyDTOMapper = CurrencyDTOMapper()
51+
let tickerDTOMapper = TickerDTOMapper()
52+
let loginResponseDTOMapper = LoginResponseDTOMapper()
53+
54+
let tickerRepository = PostgresTickerRepository(database: app.db)
55+
let livePriceService = LivePriceService(alphavantage: alphavantage)
56+
let quoteCache = PostgresQuoteRepository(database: app.db)
57+
let priceService = CachedPriceService(priceService: livePriceService, cache: quoteCache)
58+
59+
let transactionDTOMapper = TransactionDTOMapper(
60+
currencyDTOMapper: currencyDTOMapper,
61+
database: app.db
62+
)
63+
64+
let investmentDTOMapper = InvestmentDTOMapper(
65+
currencyDTOMapper: currencyDTOMapper,
66+
transactionDTOMapper: transactionDTOMapper,
67+
tickerRepository: tickerRepository,
68+
priceService: priceService
69+
)
70+
71+
let userRepository = PostgresUserRepository(database: app.db)
72+
let portfolioRepository = PostgresPortfolioRepository(database: app.db)
73+
let transactionRepository = PostgresTransactionRepository(database: app.db)
74+
let brokerageRepository = PostgresBrokerageRepository(database: app.db)
75+
let brokerageAccountRepository = PostgresBrokerageAccountRepository(database: app.db)
76+
77+
let brokerageAccountDailyPerformanceRepository = PostgresBrokerageAccountDailyPerformanceRepository(database: app.db)
78+
let brokerageDailyPerformanceRepository = PostgresBrokerageDailyPerformanceRepository(database: app.db)
79+
80+
let performanceDTOMapper = DatedPerformanceDTOMapper()
81+
82+
let portfolioDTOMapper = PortfolioDTOMapper(
83+
investmentDTOMapper: investmentDTOMapper,
84+
transactionDTOMapper: transactionDTOMapper,
85+
performanceDTOMapper: performanceDTOMapper,
86+
currencyDTOMapper: currencyDTOMapper
87+
)
88+
89+
let currencyRepository = PostgresCurrencyRepository(database: app.db)
90+
91+
let performanceCalculator = HoldingsPerformanceCalculator(priceService: priceService)
92+
93+
let portfolioPerformanceUpdater = PortfolioPerformanceUpdater(
94+
userRepository: userRepository,
95+
portfolioRepository: portfolioRepository,
96+
tickerRepository: PostgresTickerRepository(database: app.db),
97+
quoteCache: quoteCache,
98+
priceService: priceService,
99+
performanceCalculator: performanceCalculator,
100+
portfolioDailyRepo: PostgresPortfolioDailyPerformanceRepository(db: app.db)
101+
)
102+
103+
let portfolioService = PortfolioService(portfolioRepository: portfolioRepository,
104+
currencyRepository: currencyRepository,
105+
historicalPortfolioPerformanceUpdater: portfolioPerformanceUpdater,
106+
portfolioDailyRepo: PostgresPortfolioDailyPerformanceRepository(db: app.db),
107+
dataMapper: portfolioDTOMapper)
108+
109+
let accountService = AccountService(userRepository: userRepository, userDataMapper: UserDTOMapper())
110+
111+
let brokerageService = BrokerageService(
112+
brokerageRepository: brokerageRepository,
113+
dtoMapper: BrokerageDTOMapper(
114+
brokerageRepository: brokerageRepository,
115+
accountDTOMapper: BrokerageAccountDTOMapper(
116+
brokerageAccountRepository: brokerageAccountRepository,
117+
currencyMapper: currencyDTOMapper,
118+
database: app.db
119+
),
120+
performanceRepository: brokerageDailyPerformanceRepository,
121+
performanceDTOMapper: performanceDTOMapper,
122+
database: app.db
123+
),
124+
accounts: brokerageAccountRepository,
125+
currencyMapper: currencyDTOMapper
126+
)
127+
128+
let investmentService = InvestmentService(
129+
portfolioRepository: portfolioRepository,
130+
dataMapper: InvestmentDTOMapper(
131+
currencyDTOMapper: currencyDTOMapper,
132+
transactionDTOMapper: transactionDTOMapper,
133+
tickerRepository: tickerRepository,
134+
priceService: priceService
135+
)
136+
)
137+
138+
let transactionService = TransactionService(transactionsRepository: transactionRepository,
139+
currencyRepository: currencyRepository,
140+
dataMapper: transactionDTOMapper)
141+
142+
let tickersService = TickersService(
143+
tickerRepository: tickerRepository,
144+
dataMapper: tickerDTOMapper,
145+
tickerService: alphavantage
146+
)
147+
148+
let tickerChangeHandler = TickerChangeHandler(priceService: priceService)
149+
tickersService.delegate = tickerChangeHandler
150+
151+
let brokerageAccountsService = BrokerageAccountsService(
152+
brokerageRepository: brokerageRepository,
153+
brokerageAccountRepository: brokerageAccountRepository,
154+
performanceRepository: brokerageAccountDailyPerformanceRepository,
155+
performanceDTOMapper: performanceDTOMapper,
156+
currencyMapper: currencyDTOMapper,
157+
transactionDTOMapper: transactionDTOMapper,
158+
currencyRepository: currencyRepository
159+
)
160+
161+
162+
return AppContainer(
163+
alphavantage: alphavantage,
164+
currencyDTOMapper: currencyDTOMapper,
165+
tickerDTOMapper: tickerDTOMapper,
166+
loginResponseDTOMapper: loginResponseDTOMapper,
167+
transactionDTOMapper: transactionDTOMapper,
168+
portfolioDTOMapper: portfolioDTOMapper,
169+
performanceDTOMapper: performanceDTOMapper,
170+
tickerRepository: tickerRepository,
171+
livePriceService: livePriceService,
172+
quoteCache: quoteCache,
173+
priceService: priceService,
174+
userRepository: userRepository,
175+
portfolioRepository: portfolioRepository,
176+
transactionRepository: transactionRepository,
177+
brokerageRepository: brokerageRepository,
178+
brokerageAccountRepository: brokerageAccountRepository,
179+
brokerageAccountDailyPerformanceRepository: brokerageAccountDailyPerformanceRepository,
180+
brokerageDailyPerformanceRepository: brokerageDailyPerformanceRepository,
181+
currencyRepository: currencyRepository,
182+
performanceCalculator: performanceCalculator,
183+
portfolioPerformanceUpdater: portfolioPerformanceUpdater,
184+
portfolioService: portfolioService,
185+
accountService: accountService,
186+
brokerageService: brokerageService,
187+
investmentService: investmentService,
188+
transactionService: transactionService,
189+
tickersService: tickersService,
190+
brokerageAccountsService: brokerageAccountsService
191+
)
192+
}
193+
194+
func installGlobalMiddleware(_ app: Application) {
195+
let globalRateLimiter = RateLimiterMiddleware(maxRequests: 100, perSeconds: 60)
196+
app.middleware.use(app.sessions.middleware)
197+
app.middleware.use(globalRateLimiter)
198+
}
199+
200+
func scheduleNightlyJobs(_ app: Application, _ container: AppContainer) throws {
201+
if app.environment == .testing { return }
202+
203+
let nightlyUpdaterJob = NightlyUpdaterJob(
204+
tickerPriceUpdater: TickerPriceUpdater(
205+
tickerRepository: container.tickerRepository,
206+
quoteCache: container.quoteCache,
207+
priceService: container.priceService
208+
),
209+
portfolioPerformanceUpdater: container.portfolioPerformanceUpdater,
210+
brokerageAccountPerformanceUpdater: BrokerageAccountPerformanceUpdater(
211+
transactionRepository: container.transactionRepository,
212+
brokerageAccountRepository: container.brokerageAccountRepository,
213+
accountDailyRepository: container.brokerageAccountDailyPerformanceRepository,
214+
userRepository: container.userRepository,
215+
calculator: container.performanceCalculator
216+
),
217+
brokeragePerformanceUpdater: BrokeragePerformanceUpdater(
218+
userRepository: container.userRepository,
219+
brokerageAccountRepository: container.brokerageAccountRepository,
220+
accountDailyRepository: container.brokerageAccountDailyPerformanceRepository,
221+
brokerageDailyRepository: container.brokerageDailyPerformanceRepository
222+
)
223+
)
224+
225+
app.queues.schedule(nightlyUpdaterJob)
226+
.daily()
227+
.at(3, 0)
228+
229+
app.queues.add(LoggingJobEventDelegate(logger: app.logger))
230+
231+
let userTokenCleanerJob = UserTokenClearUpJob(userTokenClearing: UserTokenClearer(database: app.db))
232+
app.queues.schedule(userTokenCleanerJob)
233+
.daily()
234+
235+
try app.queues.startScheduledJobs()
236+
try app.queues.startInProcessJobs()
237+
}

0 commit comments

Comments
 (0)