Skip to content

Commit 50f101e

Browse files
committed
refactor(core): strip middleware of in-memory dependency injection
Removes all repository and service instantiation from the root middleware. This is a preparatory step for centralizing dependency injection in `server.dart`. The API is temporarily broken by this change.
1 parent e43c5f3 commit 50f101e

File tree

1 file changed

+11
-303
lines changed

1 file changed

+11
-303
lines changed

routes/_middleware.dart

Lines changed: 11 additions & 303 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,7 @@
11
import 'package:dart_frog/dart_frog.dart';
22
import 'package:ht_api/src/middlewares/error_handler.dart';
3-
import 'package:ht_api/src/rbac/permission_service.dart';
4-
import 'package:ht_api/src/registry/model_registry.dart';
5-
import 'package:ht_api/src/services/auth_service.dart';
6-
import 'package:ht_api/src/services/auth_token_service.dart';
7-
import 'package:ht_api/src/services/dashboard_summary_service.dart';
8-
import 'package:ht_api/src/services/default_user_preference_limit_service.dart';
9-
import 'package:ht_api/src/services/jwt_auth_token_service.dart';
10-
import 'package:ht_api/src/services/token_blacklist_service.dart';
11-
import 'package:ht_api/src/services/user_preference_limit_service.dart';
12-
import 'package:ht_api/src/services/verification_code_storage_service.dart';
13-
import 'package:ht_data_inmemory/ht_data_inmemory.dart';
14-
import 'package:ht_data_repository/ht_data_repository.dart';
15-
import 'package:ht_email_inmemory/ht_email_inmemory.dart';
16-
import 'package:ht_email_repository/ht_email_repository.dart';
17-
import 'package:ht_shared/ht_shared.dart';
183
import 'package:uuid/uuid.dart';
194

20-
// Assuming a fixed ID for the AppConfig document
21-
const String _appConfigId = 'app_config';
22-
235
// --- Request ID Wrapper ---
246

257
/// {@template request_id}
@@ -62,296 +44,22 @@ class RequestId {
6244
final String id;
6345
}
6446

65-
// --- Repository Creation Logic ---
66-
HtDataRepository<Headline> _createHeadlineRepository() {
67-
print('Initializing Headline Repository...');
68-
final initialData = headlinesFixturesData.map(Headline.fromJson).toList();
69-
final client = HtDataInMemory<Headline>(
70-
toJson: (i) => i.toJson(),
71-
getId: (i) => i.id,
72-
initialData: initialData,
73-
);
74-
print('Headline Repository Initialized with ${initialData.length} items.');
75-
return HtDataRepository<Headline>(dataClient: client);
76-
}
77-
78-
HtDataRepository<Category> _createCategoryRepository() {
79-
print('Initializing Category Repository...');
80-
final initialData = categoriesFixturesData.map(Category.fromJson).toList();
81-
final client = HtDataInMemory<Category>(
82-
toJson: (i) => i.toJson(),
83-
getId: (i) => i.id,
84-
initialData: initialData,
85-
);
86-
print('Category Repository Initialized with ${initialData.length} items.');
87-
return HtDataRepository<Category>(dataClient: client);
88-
}
89-
90-
HtDataRepository<Source> _createSourceRepository() {
91-
print('Initializing Source Repository...');
92-
final initialData = sourcesFixturesData.map(Source.fromJson).toList();
93-
final client = HtDataInMemory<Source>(
94-
toJson: (i) => i.toJson(),
95-
getId: (i) => i.id,
96-
initialData: initialData,
97-
);
98-
print('Source Repository Initialized with ${initialData.length} items.');
99-
return HtDataRepository<Source>(dataClient: client);
100-
}
101-
102-
HtDataRepository<Country> _createCountryRepository() {
103-
print('Initializing Country Repository...');
104-
final initialData = countriesFixturesData.map(Country.fromJson).toList();
105-
final client = HtDataInMemory<Country>(
106-
toJson: (i) => i.toJson(),
107-
getId: (i) => i.id,
108-
initialData: initialData,
109-
);
110-
print('Country Repository Initialized with ${initialData.length} items.');
111-
return HtDataRepository<Country>(dataClient: client);
112-
}
113-
114-
HtDataRepository<User> _createAdminUserRepository() {
115-
print('Initializing User Repository with Admin...');
116-
// This assumes `adminUserFixtureData` is available from `ht_shared`.
117-
final initialData = usersFixturesData;
118-
final client = HtDataInMemory<User>(
119-
toJson: (u) => u.toJson(),
120-
getId: (u) => u.id,
121-
initialData: initialData,
122-
);
123-
print('User Repository Initialized with admin user.');
124-
return HtDataRepository<User>(dataClient: client);
125-
}
126-
127-
// New repositories for user settings and preferences
128-
HtDataRepository<UserAppSettings> _createUserAppSettingsRepository() {
129-
print('Initializing UserAppSettings Repository...');
130-
final client = HtDataInMemory<UserAppSettings>(
131-
toJson: (i) => i.toJson(),
132-
getId: (i) => i.id,
133-
// User settings are created on demand, no initial fixture needed
134-
);
135-
print('UserAppSettings Repository Initialized.');
136-
return HtDataRepository<UserAppSettings>(dataClient: client);
137-
}
138-
139-
HtDataRepository<UserContentPreferences>
140-
_createUserContentPreferencesRepository() {
141-
print('Initializing UserContentPreferences Repository...');
142-
final client = HtDataInMemory<UserContentPreferences>(
143-
toJson: (i) => i.toJson(),
144-
getId: (i) => i.id,
145-
// User preferences are created on demand, no initial fixture needed
146-
);
147-
print('UserContentPreferences Repository Initialized.');
148-
return HtDataRepository<UserContentPreferences>(dataClient: client);
149-
}
150-
151-
HtDataRepository<AppConfig> _createAppConfigRepository() {
152-
print('Initializing AppConfig Repository...');
153-
final initialData = [
154-
AppConfig.fromJson(appConfigFixtureData),
155-
]; // Assuming one config
156-
final client = HtDataInMemory<AppConfig>(
157-
toJson: (i) => i.toJson(),
158-
getId: (i) => i.id,
159-
initialData: initialData,
160-
);
161-
print('AppConfig Repository Initialized.');
162-
return HtDataRepository<AppConfig>(dataClient: client);
163-
}
164-
165-
/// Middleware to asynchronously load and provide the AppConfig.
166-
Middleware _appConfigProviderMiddleware() {
167-
return (handler) {
168-
return (context) async {
169-
// Read the AppConfigRepository from the context
170-
final appConfigRepository = context.read<HtDataRepository<AppConfig>>();
171-
// Read the AppConfig instance
172-
final appConfig = await appConfigRepository.read(id: _appConfigId);
173-
// Provide the AppConfig instance to downstream handlers/middleware
174-
return handler(context.provide<AppConfig>(() => appConfig));
175-
};
176-
};
177-
}
178-
17947
// --- Middleware Definition ---
18048
Handler middleware(Handler handler) {
181-
// Initialize repositories when middleware is first created
182-
// This ensures they are singletons for the server instance.
183-
final headlineRepository = _createHeadlineRepository();
184-
final categoryRepository = _createCategoryRepository();
185-
final sourceRepository = _createSourceRepository();
186-
final countryRepository = _createCountryRepository();
187-
final userSettingsRepository = _createUserAppSettingsRepository(); // New
188-
final userContentPreferencesRepository =
189-
_createUserContentPreferencesRepository();
190-
final appConfigRepository = _createAppConfigRepository();
191-
192-
// Instantiate the new DashboardSummaryService with its dependencies
193-
final dashboardSummaryService = DashboardSummaryService(
194-
headlineRepository: headlineRepository,
195-
categoryRepository: categoryRepository,
196-
sourceRepository: sourceRepository,
197-
);
198-
print('[MiddlewareSetup] DashboardSummaryService instantiated.');
199-
200-
const uuid = Uuid();
201-
202-
// --- Auth Dependencies ---
203-
// User Repo with pre-loaded admin user
204-
final userRepository = _createAdminUserRepository();
205-
print('[MiddlewareSetup] HtDataRepository<User> with admin user instantiated.');
206-
// Email Repo (using InMemory)
207-
const emailRepository = HtEmailRepository(
208-
emailClient: HtEmailInMemoryClient(),
209-
);
210-
print('[MiddlewareSetup] HtEmailRepository instantiated.');
211-
// Auth Services (using JWT and in-memory implementations)
212-
final tokenBlacklistService = InMemoryTokenBlacklistService();
213-
print('[MiddlewareSetup] InMemoryTokenBlacklistService instantiated.');
214-
// Instantiate the JWT service, passing its dependencies
215-
final authTokenService = JwtAuthTokenService(
216-
userRepository: userRepository,
217-
blacklistService: tokenBlacklistService,
218-
uuidGenerator: uuid,
219-
);
220-
print('[MiddlewareSetup] JwtAuthTokenService instantiated.');
221-
final verificationCodeStorageService =
222-
InMemoryVerificationCodeStorageService();
223-
print(
224-
'[MiddlewareSetup] InMemoryVerificationCodeStorageService instantiated.',
225-
);
226-
final authService = AuthService(
227-
userRepository: userRepository,
228-
authTokenService: authTokenService,
229-
verificationCodeStorageService: verificationCodeStorageService,
230-
emailRepository: emailRepository,
231-
userAppSettingsRepository: userSettingsRepository,
232-
userContentPreferencesRepository: userContentPreferencesRepository,
233-
uuidGenerator: uuid,
234-
);
235-
print('[MiddlewareSetup] AuthService instantiated.');
236-
237-
// --- RBAC Dependencies ---
238-
const permissionService = PermissionService();
239-
240-
// --- User Preference Limit Service ---
241-
final userPreferenceLimitService = DefaultUserPreferenceLimitService(
242-
appConfigRepository: appConfigRepository,
243-
);
244-
print('[MiddlewareSetup] DefaultUserPreferenceLimitService instantiated.');
245-
246-
// ==========================================================================
247-
// IMPORTANT: The order of middleware matters significantly!
248-
// Middleware is applied in layers (like an onion). A request flows "in"
249-
// through the chain, hits the route handler, and the response flows "out".
250-
// Providers must be added *before* the middleware/handlers that read them.
251-
// Error handlers should typically be placed late in the "request" phase
252-
// (or early in the "response" phase) to catch errors from upstream.
253-
// ==========================================================================
49+
// This middleware chain will be rebuilt in a later step.
50+
// For now, it only provides a request ID and basic error handling.
25451
return handler
255-
// Add the asynchronous AppConfig provider middleware here
256-
.use(_appConfigProviderMiddleware())
257-
// --- 1. Request ID Provider (Early Setup) ---
258-
// PURPOSE: Generates a unique ID (UUID v4) for each incoming request.
259-
// Provides `RequestId` instance via context.
260-
// ORDER: Placed *very early* so the ID is available for logging and
261-
// tracing throughout the entire request lifecycle in all
262-
// subsequent middleware and handlers.
263-
.use((innerHandler) {
264-
return (context) {
265-
final requestIdValue = uuid.v4();
266-
final requestId = RequestId(requestIdValue);
267-
// Provide the RequestId instance to downstream handlers/middleware
268-
return innerHandler(context.provide<RequestId>(() => requestId));
269-
};
270-
})
271-
// --- 2. Model Registry Provider (Early Setup) ---
272-
// PURPOSE: Provides the `ModelRegistry` map for dynamic JSON
273-
// serialization/deserialization lookups.
274-
// ORDER: Needed by some repository clients or handlers dealing with
275-
// generic data types. Placed early, after RequestId.
276-
.use(modelRegistryProvider)
277-
// --- 3. Repository Providers (Core Data Access) ---
278-
// PURPOSE: Provide singleton instances of all data repositories.
279-
// ORDER: These MUST be provided BEFORE any middleware or route handlers
280-
// that need to interact with data (e.g., AuthService,
281-
// authenticationProvider indirectly via AuthService/TokenService,
282-
// specific route logic).
283-
.use(provider<HtDataRepository<Headline>>((_) => headlineRepository))
284-
.use(provider<HtDataRepository<Category>>((_) => categoryRepository))
285-
.use(provider<HtDataRepository<Source>>((_) => sourceRepository))
286-
.use(provider<HtDataRepository<Country>>((_) => countryRepository))
287-
.use(
288-
provider<HtDataRepository<User>>((_) => userRepository),
289-
) // Used by Auth services
290-
.use(
291-
provider<HtEmailRepository>((_) => emailRepository),
292-
) // Used by AuthService
293-
// New Repositories for User Settings and Preferences
294-
.use(
295-
provider<HtDataRepository<UserAppSettings>>(
296-
(_) => userSettingsRepository,
297-
),
298-
)
299-
.use(
300-
provider<HtDataRepository<UserContentPreferences>>(
301-
(_) => userContentPreferencesRepository,
302-
),
303-
)
304-
.use(provider<HtDataRepository<AppConfig>>((_) => appConfigRepository))
305-
// ORDER: These MUST be provided BEFORE `authenticationProvider` and
306-
// any route handlers that perform authentication/authorization.
307-
// - `Uuid` is used by `AuthService` and `JwtAuthTokenService`.
308-
// - `AuthTokenService` is read by `authenticationProvider`.
309-
// - `AuthService` uses several repositories and `AuthTokenService`.
310-
// - `VerificationCodeStorageService` is used by `AuthService`.
311-
// - `TokenBlacklistService` is used by `JwtAuthTokenService`.
312-
.use(provider<Uuid>((_) => uuid)) // Read by AuthService & TokenService
313-
.use(
314-
provider<TokenBlacklistService>((_) => tokenBlacklistService),
315-
) // Read by AuthTokenService
316-
.use(
317-
provider<AuthTokenService>((_) => authTokenService),
318-
) // Read by AuthService
319-
.use(
320-
provider<VerificationCodeStorageService>(
321-
(_) => verificationCodeStorageService,
322-
),
323-
) // Read by AuthService
324-
.use(
325-
provider<AuthService>((_) => authService),
326-
) // Reads other services/repos
327-
.use(provider<DashboardSummaryService>((_) => dashboardSummaryService))
328-
// --- 5. RBAC Service Provider ---
329-
// PURPOSE: Provides the PermissionService for authorization checks.
330-
// ORDER: Must be provided before any middleware or handlers that use it
331-
// (e.g., authorizationMiddleware).
332-
.use(provider<PermissionService>((_) => permissionService))
333-
// --- 6. User Preference Limit Service Provider --- // New
334-
// PURPOSE: Provides the service for enforcing user preference limits.
335-
// ORDER: Must be provided before any handlers that use it (specifically
336-
// the generic data route handlers for UserContentPreferences).
33752
.use(
338-
provider<UserPreferenceLimitService>((_) => userPreferenceLimitService),
53+
(innerHandler) {
54+
return (context) {
55+
// In a later step, the Uuid instance will be provided from server.dart
56+
// For now, we create it here.
57+
const uuid = Uuid();
58+
final requestId = RequestId(uuid.v4());
59+
return innerHandler(context.provide<RequestId>(() => requestId));
60+
};
61+
},
33962
)
340-
// --- 7. Request Logger (Logging) ---
341-
// PURPOSE: Logs details about the incoming request and outgoing response.
342-
// ORDER: Often placed late in the request phase / early in the response
343-
// phase. Placing it here logs the request *before* the handler
344-
// runs and the response *after* the handler (and error handler)
345-
// completes. Can access `RequestId` and potentially `User?`.
34663
.use(requestLogger())
347-
// --- 8. Error Handler (Catch-All) ---
348-
// PURPOSE: Catches exceptions thrown by upstream middleware or route
349-
// handlers and converts them into standardized JSON error responses.
350-
// ORDER: MUST be placed *late* in the chain (typically last before the
351-
// actual handler is invoked by the framework, or first in the
352-
// response processing flow) so it can catch errors from
353-
// everything that came before it (providers, auth middleware,
354-
// route handlers). If placed too early, it won't catch errors
355-
// from middleware/handlers defined after it.
35664
.use(errorHandler());
35765
}

0 commit comments

Comments
 (0)