refactor(routes): analytics + tracker → throw pattern (batch 1)
Drop try/catch swallows + standardizeError; throw ValidationError/ApiError (tracker preserves result.status via ApiError). Test harness updated to simulate the terminal handler. 236/236. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
26d976e272
commit
59c2917e1d
|
|
@ -2,13 +2,12 @@
|
||||||
import type { Req, Res, Next } from '../types/http';
|
import type { Req, Res, Next } from '../types/http';
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { standardizeError } = require('../middleware/errorFormatter.cts');
|
const { ValidationError } = require('../utils/apiError.cts');
|
||||||
const { getAnalyticsSummary } = require('../services/analyticsService.cts');
|
const { getAnalyticsSummary } = require('../services/analyticsService.cts');
|
||||||
|
|
||||||
router.get('/summary', (req: Req, res: Res) => {
|
router.get('/summary', (req: Req, res: Res) => {
|
||||||
const result = getAnalyticsSummary(req.user.id, req.query);
|
const result = getAnalyticsSummary(req.user.id, req.query);
|
||||||
if (result.error)
|
if (result.error) throw ValidationError(result.error, 'month');
|
||||||
return res.status(400).json(standardizeError(result.error, 'VALIDATION_ERROR', 'month'));
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,42 +3,23 @@ import type { Req, Res, Next } from '../types/http';
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { getTracker, getUpcomingBills, getOverdueCount } = require('../services/trackerService.cts');
|
const { getTracker, getUpcomingBills, getOverdueCount } = require('../services/trackerService.cts');
|
||||||
const { standardizeError } = require('../middleware/errorFormatter.cts');
|
const { ApiError, ValidationError } = require('../utils/apiError.cts');
|
||||||
|
|
||||||
// GET /api/tracker/overdue-count — lightweight count for sidebar badge
|
// GET /api/tracker/overdue-count — lightweight count for sidebar badge
|
||||||
router.get('/overdue-count', (req: Req, res: Res) => {
|
router.get('/overdue-count', (req: Req, res: Res) => {
|
||||||
try {
|
res.json(getOverdueCount(req.user.id));
|
||||||
res.json(getOverdueCount(req.user.id));
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[tracker/overdue-count]', err.message);
|
|
||||||
res.status(500).json(standardizeError('Failed to load overdue count', 'INTERNAL_ERROR'));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// GET /api/tracker?year=2026&month=5
|
// GET /api/tracker?year=2026&month=5
|
||||||
router.get('/', (req: Req, res: Res) => {
|
router.get('/', (req: Req, res: Res) => {
|
||||||
try {
|
const result = getTracker(req.user.id, req.query);
|
||||||
const result = getTracker(req.user.id, req.query);
|
if (result.error) throw new ApiError('VALIDATION_ERROR', result.error, result.status || 400);
|
||||||
if (result.error) {
|
res.json(result);
|
||||||
return res
|
|
||||||
.status(result.status || 400)
|
|
||||||
.json(standardizeError(result.error, 'VALIDATION_ERROR'));
|
|
||||||
}
|
|
||||||
res.json(result);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[tracker]', err.message);
|
|
||||||
res.status(500).json(standardizeError('Failed to load tracker data', 'INTERNAL_ERROR'));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// GET /api/tracker/upcoming?days=30
|
// GET /api/tracker/upcoming?days=30
|
||||||
router.get('/upcoming', (req: Req, res: Res) => {
|
router.get('/upcoming', (req: Req, res: Res) => {
|
||||||
try {
|
res.json(getUpcomingBills(req.user.id, req.query));
|
||||||
res.json(getUpcomingBills(req.user.id, req.query));
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[tracker/upcoming]', err.message);
|
|
||||||
res.status(500).json(standardizeError('Failed to load upcoming bills', 'INTERNAL_ERROR'));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,15 @@ test('GET /tracker returns a standardized error for an invalid month', async ()
|
||||||
resolve({ status: this.statusCode, data: d });
|
resolve({ status: this.statusCode, data: d });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
handler(req, res);
|
// Handlers now throw ApiError; simulate the terminal error handler.
|
||||||
|
try {
|
||||||
|
handler(req, res);
|
||||||
|
} catch (err) {
|
||||||
|
resolve({
|
||||||
|
status: err.status || 500,
|
||||||
|
data: { error: err.code, message: err.message, code: err.code, field: err.field ?? null },
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
assert.equal(result.status, 400);
|
assert.equal(result.status, 400);
|
||||||
assert.equal(result.data.code, 'VALIDATION_ERROR', 'standardized shape, not a plain {error}');
|
assert.equal(result.data.code, 'VALIDATION_ERROR', 'standardized shape, not a plain {error}');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue