Skip to content

Commit e2378d8

Browse files
authored
Merge pull request #3 from shenald-dev/fix-express-json-error-handling-16461518800795681364
fix(api): handle invalid JSON gracefully
2 parents 8bcb27d + d7d30b4 commit e2378d8

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

.jules/bolt.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,11 @@ Learning:
44
The API gateway was generating pseudo-random mock response IDs using `Math.random().toString(36).substr(2, 9)`. This approach is both slow under heavy load and fundamentally flawed for a large-scale system due to the high risk of ID collisions (non-cryptographic randomness, short string length).
55

66
Action:
7-
Switched to Node.js's native `crypto.randomUUID()` to generate mock response IDs. This provides mathematically guaranteed uniqueness (crucial for a unified API gateway) and is natively faster than the previous string manipulation approach. Tests were updated to reflect the increased length of UUIDs over the previous 9-character pseudo-random strings.
7+
Switched to Node.js's native `crypto.randomUUID()` to generate mock response IDs. This provides mathematically guaranteed uniqueness (crucial for a unified API gateway) and is natively faster than the previous string manipulation approach. Tests were updated to reflect the increased length of UUIDs over the previous 9-character pseudo-random strings.
8+
## 2026-03-18 — Handle Invalid JSON Gracefully
9+
10+
Learning:
11+
Express.js default `express.json()` middleware can leak server stack traces via HTML responses when it encounters malformed JSON input, which degrades API reliability and can expose internal structure.
12+
13+
Action:
14+
Added a custom error handling middleware immediately after `express.json()` to catch `SyntaxError` with status 400 and return a clean, standard JSON `400 Bad Request` payload instead of an HTML stack trace.

src/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ app.use(helmet());
2222
app.use(cors());
2323
app.use(express.json());
2424

25+
// Handle invalid JSON gracefully
26+
app.use((err, req, res, next) => {
27+
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
28+
return res.status(400).json({ error: 'Invalid JSON payload' });
29+
}
30+
next(err);
31+
});
32+
2533
// API endpoints
2634
app.post('/v1/chat/completions', (req, res) => {
2735
const { model, messages } = req.body;

tests/api.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,13 @@ test('POST /v1/chat/completions fails without model', async () => {
3535
assert.strictEqual(res.status, 400);
3636
assert.strictEqual(res.body.error, 'Missing model or messages');
3737
});
38+
39+
test('POST /v1/chat/completions fails with invalid JSON gracefully', async () => {
40+
const res = await request(app)
41+
.post('/v1/chat/completions')
42+
.set('Content-Type', 'application/json')
43+
.send('{invalid_json');
44+
45+
assert.strictEqual(res.status, 400);
46+
assert.strictEqual(res.body.error, 'Invalid JSON payload');
47+
});

0 commit comments

Comments
 (0)