getting aligned and refactored

This commit is contained in:
Boki 2025-06-22 18:27:48 -04:00
parent 60ada5f6a3
commit a3459f5865
16 changed files with 296 additions and 273 deletions

View file

@ -3,7 +3,7 @@
* Configures dependency injection for the web API service
*/
import type { ServiceContainer } from '@stock-bot/di';
import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { AppConfig } from '@stock-bot/config';
@ -14,8 +14,8 @@ const logger = getLogger('web-api-container');
*/
export function setupServiceContainer(
config: AppConfig,
container: ServiceContainer
): ServiceContainer {
container: IServiceContainer
): IServiceContainer {
logger.info('Configuring web API service container...');
// Web API specific configuration

View file

@ -4,17 +4,15 @@
*/
import { Hono } from 'hono';
import type { ServiceContainer } from '@stock-bot/di';
import { healthRoutes, exchangeRoutes } from './index';
import type { IServiceContainer } from '@stock-bot/handlers';
import { healthRoutes } from './health.routes';
import { createExchangeRoutes } from './exchange.routes';
export function createRoutes(container: ServiceContainer): Hono {
export function createRoutes(container: IServiceContainer): Hono {
const app = new Hono();
// Add container to context for all routes
app.use('*', async (c, next) => {
c.set('container', container);
await next();
});
// Create routes with container
const exchangeRoutes = createExchangeRoutes(container);
// Mount routes
app.route('/health', healthRoutes);

View file

@ -3,7 +3,8 @@
*/
import { Hono } from 'hono';
import { getLogger } from '@stock-bot/logger';
import { exchangeService } from '../services/exchange.service';
import type { IServiceContainer } from '@stock-bot/handlers';
import { createExchangeService } from '../services/exchange.service';
import { createSuccessResponse, handleError } from '../utils/error-handler';
import {
validateCreateExchange,
@ -13,243 +14,249 @@ import {
} from '../utils/validation';
const logger = getLogger('exchange-routes');
export const exchangeRoutes = new Hono();
// Get all exchanges with provider mapping counts and mappings
exchangeRoutes.get('/', async c => {
logger.debug('Getting all exchanges');
try {
const exchanges = await exchangeService.getAllExchanges();
logger.info('Successfully retrieved exchanges', { count: exchanges.length });
return c.json(createSuccessResponse(exchanges, undefined, exchanges.length));
} catch (error) {
logger.error('Failed to get exchanges', { error });
return handleError(c, error, 'to get exchanges');
}
});
export function createExchangeRoutes(container: IServiceContainer) {
const exchangeRoutes = new Hono();
const exchangeService = createExchangeService(container);
// Get exchange by ID with detailed provider mappings
exchangeRoutes.get('/:id', async c => {
const exchangeId = c.req.param('id');
logger.debug('Getting exchange by ID', { exchangeId });
try {
const result = await exchangeService.getExchangeById(exchangeId);
if (!result) {
logger.warn('Exchange not found', { exchangeId });
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
// Get all exchanges with provider mapping counts and mappings
exchangeRoutes.get('/', async c => {
logger.debug('Getting all exchanges');
try {
const exchanges = await exchangeService.getAllExchanges();
logger.info('Successfully retrieved exchanges', { count: exchanges.length });
return c.json(createSuccessResponse(exchanges, undefined, exchanges.length));
} catch (error) {
logger.error('Failed to get exchanges', { error });
return handleError(c, error, 'to get exchanges');
}
});
logger.info('Successfully retrieved exchange details', {
exchangeId,
exchangeCode: result.exchange.code,
mappingCount: result.provider_mappings.length,
});
return c.json(createSuccessResponse(result));
} catch (error) {
logger.error('Failed to get exchange details', { error, exchangeId });
return handleError(c, error, 'to get exchange details');
}
});
// Get exchange by ID with detailed provider mappings
exchangeRoutes.get('/:id', async c => {
const exchangeId = c.req.param('id');
logger.debug('Getting exchange by ID', { exchangeId });
// Create new exchange
exchangeRoutes.post('/', async c => {
logger.debug('Creating new exchange');
try {
const result = await exchangeService.getExchangeById(exchangeId);
try {
const body = await c.req.json();
logger.debug('Received exchange creation request', { requestBody: body });
if (!result) {
logger.warn('Exchange not found', { exchangeId });
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
}
const validatedData = validateCreateExchange(body);
logger.debug('Exchange data validated successfully', { validatedData });
const exchange = await exchangeService.createExchange(validatedData);
logger.info('Exchange created successfully', {
exchangeId: exchange.id,
code: exchange.code,
name: exchange.name,
});
return c.json(createSuccessResponse(exchange, 'Exchange created successfully'), 201);
} catch (error) {
logger.error('Failed to create exchange', { error });
return handleError(c, error, 'to create exchange');
}
});
// Update exchange (activate/deactivate, rename, etc.)
exchangeRoutes.patch('/:id', async c => {
const exchangeId = c.req.param('id');
logger.debug('Updating exchange', { exchangeId });
try {
const body = await c.req.json();
logger.debug('Received exchange update request', { exchangeId, updates: body });
const validatedUpdates = validateUpdateExchange(body);
logger.debug('Exchange update data validated', { exchangeId, validatedUpdates });
const exchange = await exchangeService.updateExchange(exchangeId, validatedUpdates);
if (!exchange) {
logger.warn('Exchange not found for update', { exchangeId });
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
logger.info('Successfully retrieved exchange details', {
exchangeId,
exchangeCode: result.exchange.code,
mappingCount: result.provider_mappings.length,
});
return c.json(createSuccessResponse(result));
} catch (error) {
logger.error('Failed to get exchange details', { error, exchangeId });
return handleError(c, error, 'to get exchange details');
}
});
logger.info('Exchange updated successfully', {
exchangeId,
code: exchange.code,
updates: validatedUpdates,
});
// Create new exchange
exchangeRoutes.post('/', async c => {
logger.debug('Creating new exchange');
// Log special actions
if (validatedUpdates.visible === false) {
logger.warn('Exchange marked as hidden - provider mappings will be deleted', {
try {
const body = await c.req.json();
logger.debug('Received exchange creation request', { requestBody: body });
const validatedData = validateCreateExchange(body);
logger.debug('Exchange data validated successfully', { validatedData });
const exchange = await exchangeService.createExchange(validatedData);
logger.info('Exchange created successfully', {
exchangeId: exchange.id,
code: exchange.code,
name: exchange.name,
});
return c.json(createSuccessResponse(exchange, 'Exchange created successfully'), 201);
} catch (error) {
logger.error('Failed to create exchange', { error });
return handleError(c, error, 'to create exchange');
}
});
// Update exchange (activate/deactivate, rename, etc.)
exchangeRoutes.patch('/:id', async c => {
const exchangeId = c.req.param('id');
logger.debug('Updating exchange', { exchangeId });
try {
const body = await c.req.json();
logger.debug('Received exchange update request', { exchangeId, updates: body });
const validatedUpdates = validateUpdateExchange(body);
logger.debug('Exchange update data validated', { exchangeId, validatedUpdates });
const exchange = await exchangeService.updateExchange(exchangeId, validatedUpdates);
if (!exchange) {
logger.warn('Exchange not found for update', { exchangeId });
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
}
logger.info('Exchange updated successfully', {
exchangeId,
code: exchange.code,
updates: validatedUpdates,
});
// Log special actions
if (validatedUpdates.visible === false) {
logger.warn('Exchange marked as hidden - provider mappings will be deleted', {
exchangeId,
code: exchange.code,
});
}
return c.json(createSuccessResponse(exchange, 'Exchange updated successfully'));
} catch (error) {
logger.error('Failed to update exchange', { error, exchangeId });
return handleError(c, error, 'to update exchange');
}
});
return c.json(createSuccessResponse(exchange, 'Exchange updated successfully'));
} catch (error) {
logger.error('Failed to update exchange', { error, exchangeId });
return handleError(c, error, 'to update exchange');
}
});
// Get all provider mappings
exchangeRoutes.get('/provider-mappings/all', async c => {
logger.debug('Getting all provider mappings');
// Get all provider mappings
exchangeRoutes.get('/provider-mappings/all', async c => {
logger.debug('Getting all provider mappings');
try {
const mappings = await exchangeService.getAllProviderMappings();
logger.info('Successfully retrieved all provider mappings', { count: mappings.length });
return c.json(createSuccessResponse(mappings, undefined, mappings.length));
} catch (error) {
logger.error('Failed to get provider mappings', { error });
return handleError(c, error, 'to get provider mappings');
}
});
// Get provider mappings by provider
exchangeRoutes.get('/provider-mappings/:provider', async c => {
const provider = c.req.param('provider');
logger.debug('Getting provider mappings by provider', { provider });
try {
const mappings = await exchangeService.getProviderMappingsByProvider(provider);
logger.info('Successfully retrieved provider mappings', { provider, count: mappings.length });
return c.json(createSuccessResponse(mappings, undefined, mappings.length));
} catch (error) {
logger.error('Failed to get provider mappings', { error, provider });
return handleError(c, error, 'to get provider mappings');
}
});
// Update provider mapping (activate/deactivate, verify, change confidence)
exchangeRoutes.patch('/provider-mappings/:id', async c => {
const mappingId = c.req.param('id');
logger.debug('Updating provider mapping', { mappingId });
try {
const body = await c.req.json();
logger.debug('Received provider mapping update request', { mappingId, updates: body });
const validatedUpdates = validateUpdateProviderMapping(body);
logger.debug('Provider mapping update data validated', { mappingId, validatedUpdates });
const mapping = await exchangeService.updateProviderMapping(mappingId, validatedUpdates);
if (!mapping) {
logger.warn('Provider mapping not found for update', { mappingId });
return c.json(createSuccessResponse(null, 'Provider mapping not found'), 404);
try {
const mappings = await exchangeService.getAllProviderMappings();
logger.info('Successfully retrieved all provider mappings', { count: mappings.length });
return c.json(createSuccessResponse(mappings, undefined, mappings.length));
} catch (error) {
logger.error('Failed to get provider mappings', { error });
return handleError(c, error, 'to get provider mappings');
}
});
logger.info('Provider mapping updated successfully', {
mappingId,
provider: mapping.provider,
providerExchangeCode: mapping.provider_exchange_code,
updates: validatedUpdates,
});
// Get provider mappings by provider
exchangeRoutes.get('/provider-mappings/:provider', async c => {
const provider = c.req.param('provider');
logger.debug('Getting provider mappings by provider', { provider });
return c.json(createSuccessResponse(mapping, 'Provider mapping updated successfully'));
} catch (error) {
logger.error('Failed to update provider mapping', { error, mappingId });
return handleError(c, error, 'to update provider mapping');
}
});
try {
const mappings = await exchangeService.getProviderMappingsByProvider(provider);
logger.info('Successfully retrieved provider mappings', { provider, count: mappings.length });
// Create new provider mapping
exchangeRoutes.post('/provider-mappings', async c => {
logger.debug('Creating new provider mapping');
return c.json(createSuccessResponse(mappings, undefined, mappings.length));
} catch (error) {
logger.error('Failed to get provider mappings', { error, provider });
return handleError(c, error, 'to get provider mappings');
}
});
try {
const body = await c.req.json();
logger.debug('Received provider mapping creation request', { requestBody: body });
// Update provider mapping (activate/deactivate, verify, change confidence)
exchangeRoutes.patch('/provider-mappings/:id', async c => {
const mappingId = c.req.param('id');
logger.debug('Updating provider mapping', { mappingId });
const validatedData = validateCreateProviderMapping(body);
logger.debug('Provider mapping data validated successfully', { validatedData });
try {
const body = await c.req.json();
logger.debug('Received provider mapping update request', { mappingId, updates: body });
const mapping = await exchangeService.createProviderMapping(validatedData);
logger.info('Provider mapping created successfully', {
mappingId: mapping.id,
provider: mapping.provider,
providerExchangeCode: mapping.provider_exchange_code,
masterExchangeId: mapping.master_exchange_id,
});
const validatedUpdates = validateUpdateProviderMapping(body);
logger.debug('Provider mapping update data validated', { mappingId, validatedUpdates });
return c.json(createSuccessResponse(mapping, 'Provider mapping created successfully'), 201);
} catch (error) {
logger.error('Failed to create provider mapping', { error });
return handleError(c, error, 'to create provider mapping');
}
});
const mapping = await exchangeService.updateProviderMapping(mappingId, validatedUpdates);
// Get all available providers
exchangeRoutes.get('/providers/list', async c => {
logger.debug('Getting providers list');
if (!mapping) {
logger.warn('Provider mapping not found for update', { mappingId });
return c.json(createSuccessResponse(null, 'Provider mapping not found'), 404);
}
try {
const providers = await exchangeService.getProviders();
logger.info('Successfully retrieved providers list', { count: providers.length, providers });
return c.json(createSuccessResponse(providers));
} catch (error) {
logger.error('Failed to get providers list', { error });
return handleError(c, error, 'to get providers list');
}
});
logger.info('Provider mapping updated successfully', {
mappingId,
provider: mapping.provider,
providerExchangeCode: mapping.provider_exchange_code,
updates: validatedUpdates,
});
// Get unmapped provider exchanges by provider
exchangeRoutes.get('/provider-exchanges/unmapped/:provider', async c => {
const provider = c.req.param('provider');
logger.debug('Getting unmapped provider exchanges', { provider });
return c.json(createSuccessResponse(mapping, 'Provider mapping updated successfully'));
} catch (error) {
logger.error('Failed to update provider mapping', { error, mappingId });
return handleError(c, error, 'to update provider mapping');
}
});
try {
const exchanges = await exchangeService.getUnmappedProviderExchanges(provider);
logger.info('Successfully retrieved unmapped provider exchanges', {
provider,
count: exchanges.length,
});
// Create new provider mapping
exchangeRoutes.post('/provider-mappings', async c => {
logger.debug('Creating new provider mapping');
return c.json(createSuccessResponse(exchanges, undefined, exchanges.length));
} catch (error) {
logger.error('Failed to get unmapped provider exchanges', { error, provider });
return handleError(c, error, 'to get unmapped provider exchanges');
}
});
try {
const body = await c.req.json();
logger.debug('Received provider mapping creation request', { requestBody: body });
// Get exchange statistics
exchangeRoutes.get('/stats/summary', async c => {
logger.debug('Getting exchange statistics');
const validatedData = validateCreateProviderMapping(body);
logger.debug('Provider mapping data validated successfully', { validatedData });
try {
const stats = await exchangeService.getExchangeStats();
logger.info('Successfully retrieved exchange statistics', { stats });
return c.json(createSuccessResponse(stats));
} catch (error) {
logger.error('Failed to get exchange statistics', { error });
return handleError(c, error, 'to get exchange statistics');
}
});
const mapping = await exchangeService.createProviderMapping(validatedData);
logger.info('Provider mapping created successfully', {
mappingId: mapping.id,
provider: mapping.provider,
providerExchangeCode: mapping.provider_exchange_code,
masterExchangeId: mapping.master_exchange_id,
});
return c.json(createSuccessResponse(mapping, 'Provider mapping created successfully'), 201);
} catch (error) {
logger.error('Failed to create provider mapping', { error });
return handleError(c, error, 'to create provider mapping');
}
});
// Get all available providers
exchangeRoutes.get('/providers/list', async c => {
logger.debug('Getting providers list');
try {
const providers = await exchangeService.getProviders();
logger.info('Successfully retrieved providers list', { count: providers.length, providers });
return c.json(createSuccessResponse(providers));
} catch (error) {
logger.error('Failed to get providers list', { error });
return handleError(c, error, 'to get providers list');
}
});
// Get unmapped provider exchanges by provider
exchangeRoutes.get('/provider-exchanges/unmapped/:provider', async c => {
const provider = c.req.param('provider');
logger.debug('Getting unmapped provider exchanges', { provider });
try {
const exchanges = await exchangeService.getUnmappedProviderExchanges(provider);
logger.info('Successfully retrieved unmapped provider exchanges', {
provider,
count: exchanges.length,
});
return c.json(createSuccessResponse(exchanges, undefined, exchanges.length));
} catch (error) {
logger.error('Failed to get unmapped provider exchanges', { error, provider });
return handleError(c, error, 'to get unmapped provider exchanges');
}
});
// Get exchange statistics
exchangeRoutes.get('/stats/summary', async c => {
logger.debug('Getting exchange statistics');
try {
const stats = await exchangeService.getExchangeStats();
logger.info('Successfully retrieved exchange statistics', { stats });
return c.json(createSuccessResponse(stats));
} catch (error) {
logger.error('Failed to get exchange statistics', { error });
return handleError(c, error, 'to get exchange statistics');
}
});
return exchangeRoutes;
}

View file

@ -1,5 +1,5 @@
/**
* Routes index - exports all route modules
*/
export { exchangeRoutes } from './exchange.routes';
export { createExchangeRoutes } from './exchange.routes';
export { healthRoutes } from './health.routes';

View file

@ -1,5 +1,5 @@
import { getLogger } from '@stock-bot/logger';
import { getMongoDBClient, getPostgreSQLClient } from '../clients';
import type { IServiceContainer } from '@stock-bot/handlers';
import {
CreateExchangeRequest,
CreateProviderMappingRequest,
@ -15,12 +15,14 @@ import {
const logger = getLogger('exchange-service');
export class ExchangeService {
constructor(private container: IServiceContainer) {}
private get postgresClient() {
return getPostgreSQLClient();
return this.container.postgres;
}
private get mongoClient() {
return getMongoDBClient();
return this.container.mongodb;
}
// Exchanges
@ -375,5 +377,7 @@ export class ExchangeService {
}
}
// Export singleton instance
export const exchangeService = new ExchangeService();
// Export function to create service instance with container
export function createExchangeService(container: IServiceContainer): ExchangeService {
return new ExchangeService(container);
}