Skip to content

Commit 3747b47

Browse files
committed
refactor(api): simplify data item route with ResponseHelper
Updates the `/api/v1/data/[id]/index.dart` route handler to use the new `ResponseHelper.success` method for both GET and PUT requests. This change removes several lines of boilerplate code related to manually creating metadata and the success response object. It also removes the now-unnecessary `requestId` parameter from the internal handler functions, making the code cleaner and more focused on its core logic.
1 parent 1fc7c68 commit 3747b47

File tree

1 file changed

+18
-57
lines changed

1 file changed

+18
-57
lines changed

routes/api/v1/data/[id]/index.dart

Lines changed: 18 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
import 'dart:io';
22

33
import 'package:dart_frog/dart_frog.dart';
4+
import 'package:ht_api/src/helpers/response_helper.dart';
45
import 'package:ht_api/src/rbac/permission_service.dart';
56
import 'package:ht_api/src/registry/model_registry.dart';
67
import 'package:ht_api/src/services/dashboard_summary_service.dart';
78
import 'package:ht_api/src/services/user_preference_limit_service.dart'; // Import UserPreferenceLimitService
89
import 'package:ht_data_repository/ht_data_repository.dart';
910
import 'package:ht_shared/ht_shared.dart';
1011

11-
import '../../../../_middleware.dart'; // Assuming RequestId is here
12-
1312
/// Handles requests for the /api/v1/data/[id] endpoint.
1413
/// Dispatches requests to specific handlers based on the HTTP method.
1514
Future<Response> onRequest(RequestContext context, String id) async {
1615
// Read dependencies provided by middleware
1716
final modelName = context.read<String>();
1817
final modelConfig = context.read<ModelConfig<dynamic>>();
19-
final requestId = context.read<RequestId>().id;
2018
// User is guaranteed non-null by requireAuthentication() middleware
2119
final authenticatedUser = context.read<User>();
2220
final permissionService = context
@@ -35,7 +33,6 @@ Future<Response> onRequest(RequestContext context, String id) async {
3533
modelConfig,
3634
authenticatedUser,
3735
permissionService, // Pass PermissionService
38-
requestId,
3936
);
4037
case HttpMethod.put:
4138
return _handlePut(
@@ -46,7 +43,6 @@ Future<Response> onRequest(RequestContext context, String id) async {
4643
authenticatedUser,
4744
permissionService, // Pass PermissionService
4845
userPreferenceLimitService, // Pass the limit service
49-
requestId,
5046
);
5147
case HttpMethod.delete:
5248
return _handleDelete(
@@ -56,7 +52,6 @@ Future<Response> onRequest(RequestContext context, String id) async {
5652
modelConfig,
5753
authenticatedUser,
5854
permissionService, // Pass PermissionService
59-
requestId,
6055
);
6156
default:
6257
// Methods not allowed on the item endpoint
@@ -74,7 +69,6 @@ Future<Response> _handleGet(
7469
ModelConfig<dynamic> modelConfig,
7570
User authenticatedUser,
7671
PermissionService permissionService,
77-
String requestId,
7872
) async {
7973
// Authorization check is handled by authorizationMiddleware before this.
8074
// This handler only needs to perform the ownership check if required.
@@ -143,7 +137,7 @@ Future<Response> _handleGet(
143137
// Ensure getOwnerId is provided for models requiring ownership check
144138
if (modelConfig.getOwnerId == null) {
145139
print(
146-
'[ReqID: $requestId] Configuration Error: Model "$modelName" requires '
140+
'Configuration Error: Model "$modelName" requires '
147141
'ownership check for GET item but getOwnerId is not provided.',
148142
);
149143
// Throw an exception to be caught by the errorHandler
@@ -162,25 +156,11 @@ Future<Response> _handleGet(
162156
}
163157
}
164158

165-
// Create metadata including the request ID and current timestamp
166-
final metadata = ResponseMetadata(
167-
requestId: requestId,
168-
timestamp: DateTime.now().toUtc(), // Use UTC for consistency
169-
);
170-
171-
// Wrap the item in SuccessApiResponse with metadata
172-
final successResponse = SuccessApiResponse<dynamic>(
159+
return ResponseHelper.success(
160+
context: context,
173161
data: item,
174-
metadata: metadata, // Include the created metadata
162+
toJsonT: (data) => (data as dynamic).toJson() as Map<String, dynamic>,
175163
);
176-
177-
// Provide the correct toJsonT for the specific model type
178-
final responseJson = successResponse.toJson(
179-
(item) => (item as dynamic).toJson(), // Assuming all models have toJson
180-
);
181-
182-
// Return 200 OK with the wrapped and serialized response
183-
return Response.json(body: responseJson);
184164
}
185165

186166
// --- PUT Handler ---
@@ -195,7 +175,6 @@ Future<Response> _handlePut(
195175
PermissionService permissionService, // Receive PermissionService
196176
UserPreferenceLimitService
197177
userPreferenceLimitService, // Receive Limit Service
198-
String requestId,
199178
) async {
200179
// Authorization check is handled by authorizationMiddleware before this.
201180
// This handler only needs to perform the ownership check if required.
@@ -212,9 +191,8 @@ Future<Response> _handlePut(
212191
itemToUpdate = modelConfig.fromJson(requestBody);
213192
} on TypeError catch (e) {
214193
// Catch errors during deserialization (e.g., missing required fields)
215-
// Include requestId in the server log
216194
print(
217-
'[ReqID: $requestId] Deserialization TypeError in PUT /data/[id]: $e',
195+
'Deserialization TypeError in PUT /data/[id]: $e',
218196
);
219197
// Throw BadRequestException to be caught by the errorHandler
220198
throw const BadRequestException(
@@ -235,8 +213,7 @@ Future<Response> _handlePut(
235213
} catch (e) {
236214
// Ignore if getId throws, means ID might not be in the body,
237215
// which is acceptable depending on the model/client.
238-
// Log for debugging if needed.
239-
print('[ReqID: $requestId] Warning: Could not get ID from PUT body: $e');
216+
print('Warning: Could not get ID from PUT body: $e');
240217
}
241218

242219
// --- Handler-Level Limit Check (for UserContentPreferences PUT) ---
@@ -247,7 +224,7 @@ Future<Response> _handlePut(
247224
// Ensure the itemToUpdate is the correct type for the limit service
248225
if (itemToUpdate is! UserContentPreferences) {
249226
print(
250-
'[ReqID: $requestId] Type Error: Expected UserContentPreferences '
227+
'Type Error: Expected UserContentPreferences '
251228
'for limit check, but got ${itemToUpdate.runtimeType}.',
252229
);
253230
throw const OperationFailedException(
@@ -264,7 +241,7 @@ Future<Response> _handlePut(
264241
} catch (e) {
265242
// Catch unexpected errors from the limit service
266243
print(
267-
'[ReqID: $requestId] Unexpected error during limit check for '
244+
'Unexpected error during limit check for '
268245
'UserContentPreferences PUT: $e',
269246
);
270247
throw const OperationFailedException(
@@ -381,7 +358,7 @@ Future<Response> _handlePut(
381358
// Ensure getOwnerId is provided for models requiring ownership check
382359
if (modelConfig.getOwnerId == null) {
383360
print(
384-
'[ReqID: $requestId] Configuration Error: Model "$modelName" requires '
361+
'Configuration Error: Model "$modelName" requires '
385362
'ownership check for PUT but getOwnerId is not provided.',
386363
);
387364
// Throw an exception to be caught by the errorHandler
@@ -396,9 +373,8 @@ Future<Response> _handlePut(
396373
if (itemOwnerId != authenticatedUser.id) {
397374
// This scenario should ideally not happen if the repository correctly
398375
// enforced ownership during the update call when userId was passed.
399-
// But as a defense-in-depth, we check here.
400376
print(
401-
'[ReqID: $requestId] Ownership check failed AFTER PUT for item $id. '
377+
'Ownership check failed AFTER PUT for item $id. '
402378
'Item owner: $itemOwnerId, User: ${authenticatedUser.id}',
403379
);
404380
// Throw ForbiddenException to be caught by the errorHandler
@@ -408,25 +384,11 @@ Future<Response> _handlePut(
408384
}
409385
}
410386

411-
// Create metadata including the request ID and current timestamp
412-
final metadata = ResponseMetadata(
413-
requestId: requestId,
414-
timestamp: DateTime.now().toUtc(), // Use UTC for consistency
415-
);
416-
417-
// Wrap the updated item in SuccessApiResponse with metadata
418-
final successResponse = SuccessApiResponse<dynamic>(
387+
return ResponseHelper.success(
388+
context: context,
419389
data: updatedItem,
420-
metadata: metadata,
390+
toJsonT: (data) => (data as dynamic).toJson() as Map<String, dynamic>,
421391
);
422-
423-
// Provide the correct toJsonT for the specific model type
424-
final responseJson = successResponse.toJson(
425-
(item) => (item as dynamic).toJson(), // Assuming all models have toJson
426-
);
427-
428-
// Return 200 OK with the wrapped and serialized response
429-
return Response.json(body: responseJson);
430392
}
431393

432394
// --- DELETE Handler ---
@@ -438,7 +400,6 @@ Future<Response> _handleDelete(
438400
ModelConfig<dynamic> modelConfig,
439401
User authenticatedUser,
440402
PermissionService permissionService,
441-
String requestId,
442403
) async {
443404
// Authorization check is handled by authorizationMiddleware before this.
444405
// This handler only needs to perform the ownership check if required.
@@ -463,7 +424,7 @@ Future<Response> _handleDelete(
463424
// Ensure getOwnerId is provided for models requiring ownership check
464425
if (modelConfig.getOwnerId == null) {
465426
print(
466-
'[ReqID: $requestId] Configuration Error: Model "$modelName" requires '
427+
'Configuration Error: Model "$modelName" requires '
467428
'ownership check for DELETE but getOwnerId is not provided.',
468429
);
469430
// Throw an exception to be caught by the errorHandler
@@ -503,7 +464,7 @@ Future<Response> _handleDelete(
503464
); // userId should be null for AppConfig
504465
default:
505466
print(
506-
'[ReqID: $requestId] Error: Unsupported model type "$modelName" reached _handleDelete ownership check.',
467+
'Error: Unsupported model type "$modelName" reached _handleDelete ownership check.',
507468
);
508469
// Throw an exception to be caught by the errorHandler
509470
throw OperationFailedException(
@@ -571,9 +532,9 @@ Future<Response> _handleDelete(
571532
); // userId should be null for AppConfig
572533
default:
573534
// This case should ideally be caught by the data/_middleware.dart,
574-
// but added for safety. Consider logging this unexpected state.
535+
// but added for safety.
575536
print(
576-
'[ReqID: $requestId] Error: Unsupported model type "$modelName" reached _handleDelete.',
537+
'Error: Unsupported model type "$modelName" reached _handleDelete.',
577538
);
578539
// Throw an exception to be caught by the errorHandler
579540
throw OperationFailedException(

0 commit comments

Comments
 (0)