Skip to content

Commit 881c6b7

Browse files
committed
refactor(api): centralize DI in root middleware using singletons
Refactors the root middleware to use the new `AppDependencies` singleton for dependency injection. - The middleware now triggers a single, idempotent `init()` call on the `AppDependencies` instance. - It then provides all the pre-initialized services and repositories from the singleton into the request context. - This simplifies the middleware, improves performance by ensuring dependencies are created only once, and creates a more robust and maintainable initialization flow.
1 parent 8f55afb commit 881c6b7

File tree

1 file changed

+23
-139
lines changed

1 file changed

+23
-139
lines changed

routes/_middleware.dart

Lines changed: 23 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
import 'package:dart_frog/dart_frog.dart';
2-
import 'package:ht_api/src/config/database_connection.dart';
2+
import 'package:ht_api/src/config/app_dependencies.dart';
33
import 'package:ht_api/src/middlewares/error_handler.dart';
44
import 'package:ht_api/src/rbac/permission_service.dart';
55
import 'package:ht_api/src/services/auth_service.dart';
66
import 'package:ht_api/src/services/auth_token_service.dart';
77
import 'package:ht_api/src/services/dashboard_summary_service.dart';
8-
import 'package:ht_api/src/services/database_seeding_service.dart';
9-
import 'package:ht_api/src/services/default_user_preference_limit_service.dart';
10-
import 'package:ht_api/src/services/jwt_auth_token_service.dart';
118
import 'package:ht_api/src/services/token_blacklist_service.dart';
129
import 'package:ht_api/src/services/user_preference_limit_service.dart';
1310
import 'package:ht_api/src/services/verification_code_storage_service.dart';
14-
import 'package:ht_data_client/ht_data_client.dart';
15-
import 'package:ht_data_postgres/ht_data_postgres.dart';
1611
import 'package:ht_data_repository/ht_data_repository.dart';
17-
import 'package:ht_email_inmemory/ht_email_inmemory.dart';
1812
import 'package:ht_email_repository/ht_email_repository.dart';
1913
import 'package:ht_shared/ht_shared.dart';
2014
import 'package:logging/logging.dart';
21-
import 'package:postgres/postgres.dart';
2215
import 'package:uuid/uuid.dart';
2316

2417
// --- Request ID Wrapper ---
@@ -66,24 +59,6 @@ class RequestId {
6659
// --- Middleware Definition ---
6760
final _log = Logger('RootMiddleware');
6861

69-
/// Creates a data repository for a given type [T].
70-
HtDataRepository<T> _createRepository<T>({
71-
required Connection connection,
72-
required String tableName,
73-
required FromJson<T> fromJson,
74-
required ToJson<T> toJson,
75-
}) {
76-
return HtDataRepository<T>(
77-
dataClient: HtDataPostgresClient<T>(
78-
connection: connection,
79-
tableName: tableName,
80-
fromJson: fromJson,
81-
toJson: toJson,
82-
log: _log,
83-
),
84-
);
85-
}
86-
8762
Handler middleware(Handler handler) {
8863
// This is the root middleware for the entire API. It's responsible for
8964
// providing all shared dependencies to the request context.
@@ -112,127 +87,36 @@ Handler middleware(Handler handler) {
11287
// dependencies for the request.
11388
.use((handler) {
11489
return (context) async {
115-
// 1. Ensure the database connection is initialized.
116-
await DatabaseConnectionManager.instance.init();
117-
final connection = await DatabaseConnectionManager.instance.connection;
118-
119-
// 2. Run database seeding (idempotent).
120-
final seedingService = DatabaseSeedingService(
121-
connection: connection,
122-
log: _log,
123-
);
124-
await seedingService.createTables();
125-
await seedingService.seedGlobalFixtureData();
126-
await seedingService.seedInitialAdminAndConfig();
90+
// 1. Ensure all dependencies are initialized (idempotent).
91+
_log.info('Ensuring all application dependencies are initialized...');
92+
await AppDependencies.instance.init();
93+
_log.info('Dependencies are ready.');
12794

128-
// 3. Initialize Repositories.
129-
final headlineRepository = _createRepository<Headline>(
130-
connection: connection,
131-
tableName: 'headlines',
132-
fromJson: Headline.fromJson,
133-
toJson: (h) => h.toJson(),
134-
);
135-
final categoryRepository = _createRepository<Category>(
136-
connection: connection,
137-
tableName: 'categories',
138-
fromJson: Category.fromJson,
139-
toJson: (c) => c.toJson(),
140-
);
141-
final sourceRepository = _createRepository<Source>(
142-
connection: connection,
143-
tableName: 'sources',
144-
fromJson: Source.fromJson,
145-
toJson: (s) => s.toJson(),
146-
);
147-
final countryRepository = _createRepository<Country>(
148-
connection: connection,
149-
tableName: 'countries',
150-
fromJson: Country.fromJson,
151-
toJson: (c) => c.toJson(),
152-
);
153-
final userRepository = _createRepository<User>(
154-
connection: connection,
155-
tableName: 'users',
156-
fromJson: User.fromJson,
157-
toJson: (u) => u.toJson(),
158-
);
159-
final userAppSettingsRepository = _createRepository<UserAppSettings>(
160-
connection: connection,
161-
tableName: 'user_app_settings',
162-
fromJson: UserAppSettings.fromJson,
163-
toJson: (s) => s.toJson(),
164-
);
165-
final userContentPreferencesRepository =
166-
_createRepository<UserContentPreferences>(
167-
connection: connection,
168-
tableName: 'user_content_preferences',
169-
fromJson: UserContentPreferences.fromJson,
170-
toJson: (p) => p.toJson(),
171-
);
172-
final appConfigRepository = _createRepository<AppConfig>(
173-
connection: connection,
174-
tableName: 'app_config',
175-
fromJson: AppConfig.fromJson,
176-
toJson: (c) => c.toJson(),
177-
);
178-
179-
// 4. Initialize Services.
180-
const emailRepository = HtEmailRepository(
181-
emailClient: HtEmailInMemoryClient(),
182-
);
183-
final tokenBlacklistService = InMemoryTokenBlacklistService();
184-
final AuthTokenService authTokenService = JwtAuthTokenService(
185-
userRepository: userRepository,
186-
blacklistService: tokenBlacklistService,
187-
uuidGenerator: const Uuid(),
188-
);
189-
final verificationCodeStorageService =
190-
InMemoryVerificationCodeStorageService();
191-
final authService = AuthService(
192-
userRepository: userRepository,
193-
authTokenService: authTokenService,
194-
verificationCodeStorageService: verificationCodeStorageService,
195-
emailRepository: emailRepository,
196-
userAppSettingsRepository: userAppSettingsRepository,
197-
userContentPreferencesRepository: userContentPreferencesRepository,
198-
uuidGenerator: const Uuid(),
199-
);
200-
final dashboardSummaryService = DashboardSummaryService(
201-
headlineRepository: headlineRepository,
202-
categoryRepository: categoryRepository,
203-
sourceRepository: sourceRepository,
204-
);
205-
const permissionService = PermissionService();
206-
final UserPreferenceLimitService userPreferenceLimitService =
207-
DefaultUserPreferenceLimitService(
208-
appConfigRepository: appConfigRepository,
209-
);
210-
211-
// 5. Provide all dependencies to the inner handler.
95+
// 2. Provide all dependencies to the inner handler.
96+
final deps = AppDependencies.instance;
21297
return handler
21398
.use(provider<Uuid>((_) => const Uuid()))
214-
.use(provider<HtDataRepository<Headline>>((_) => headlineRepository))
215-
.use(provider<HtDataRepository<Category>>((_) => categoryRepository))
216-
.use(provider<HtDataRepository<Source>>((_) => sourceRepository))
217-
.use(provider<HtDataRepository<Country>>((_) => countryRepository))
218-
.use(provider<HtDataRepository<User>>((_) => userRepository))
99+
.use(provider<HtDataRepository<Headline>>((_) => deps.headlineRepository))
100+
.use(provider<HtDataRepository<Category>>((_) => deps.categoryRepository))
101+
.use(provider<HtDataRepository<Source>>((_) => deps.sourceRepository))
102+
.use(provider<HtDataRepository<Country>>((_) => deps.countryRepository))
103+
.use(provider<HtDataRepository<User>>((_) => deps.userRepository))
219104
.use(provider<HtDataRepository<UserAppSettings>>(
220-
(_) => userAppSettingsRepository))
105+
(_) => deps.userAppSettingsRepository))
221106
.use(provider<HtDataRepository<UserContentPreferences>>(
222-
(_) => userContentPreferencesRepository))
223-
.use(provider<HtDataRepository<AppConfig>>((_) => appConfigRepository))
224-
.use(provider<HtEmailRepository>((_) => emailRepository))
225-
.use(provider<TokenBlacklistService>((_) => tokenBlacklistService))
226-
.use(provider<AuthTokenService>((_) => authTokenService))
107+
(_) => deps.userContentPreferencesRepository))
108+
.use(provider<HtDataRepository<AppConfig>>((_) => deps.appConfigRepository))
109+
.use(provider<HtEmailRepository>((_) => deps.emailRepository))
110+
.use(provider<TokenBlacklistService>((_) => deps.tokenBlacklistService))
111+
.use(provider<AuthTokenService>((_) => deps.authTokenService))
227112
.use(provider<VerificationCodeStorageService>(
228-
(_) => verificationCodeStorageService))
229-
.use(provider<AuthService>((_) => authService))
230-
.use(provider<DashboardSummaryService>((_) => dashboardSummaryService))
231-
.use(provider<PermissionService>((_) => permissionService))
113+
(_) => deps.verificationCodeStorageService))
114+
.use(provider<AuthService>((_) => deps.authService))
115+
.use(provider<DashboardSummaryService>((_) => deps.dashboardSummaryService))
116+
.use(provider<PermissionService>((_) => deps.permissionService))
232117
.use(provider<UserPreferenceLimitService>(
233-
(_) => userPreferenceLimitService))
118+
(_) => deps.userPreferenceLimitService))
234119
.call(context);
235120
};
236121
});
237122
}
238-

0 commit comments

Comments
 (0)