From 503b96970edeb36c3f533acaa478176378b8e7cb Mon Sep 17 00:00:00 2001 From: Omar Tentouch Date: Sat, 7 Mar 2026 02:48:51 +0100 Subject: [PATCH] fix: return 400 for invalid JSON request bodies --- src/app.test.ts | 33 +++++++++++++++++++++++++++++++++ src/app.ts | 12 ++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/app.test.ts b/src/app.test.ts index 904ece8..a336b54 100644 --- a/src/app.test.ts +++ b/src/app.test.ts @@ -142,4 +142,37 @@ await test('createApp', async (t) => { const data = await response.json() assert.deepEqual(data, [{ id: '1', title: 'foo' }]) }) + + await t.test('POST /posts with array body returns 400', async () => { + const response = await fetch(`http://localhost:${port}/posts`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify([{ title: 'foo' }]), + }) + assert.equal(response.status, 400) + const data = await response.json() + assert.deepEqual(data, { error: 'Body must be a JSON object' }) + }) + + await t.test('PATCH /posts/1 with string body returns 400', async () => { + const response = await fetch(`http://localhost:${port}/posts/1`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify('hello'), + }) + assert.equal(response.status, 400) + const data = await response.json() + assert.deepEqual(data, { error: 'Body must be a JSON object' }) + }) + + await t.test('PUT /posts/1 with null body returns 400', async () => { + const response = await fetch(`http://localhost:${port}/posts/1`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(null), + }) + assert.equal(response.status, 400) + const data = await response.json() + assert.deepEqual(data, { error: 'Body must be a JSON object' }) + }) }) diff --git a/src/app.ts b/src/app.ts index 78f90e7..45bf073 100644 --- a/src/app.ts +++ b/src/app.ts @@ -68,9 +68,11 @@ function parseListParams(req: any) { function withBody(action: (name: string, body: Record) => Promise) { return async (req: any, res: any, next: any) => { const { name = '' } = req.params - if (isItem(req.body)) { - res.locals['data'] = await action(name, req.body) + if (!isItem(req.body)) { + res.status(400).json({ error: 'Body must be a JSON object' }) + return } + res.locals['data'] = await action(name, req.body) next?.() } } @@ -80,9 +82,11 @@ function withIdAndBody( ) { return async (req: any, res: any, next: any) => { const { name = '', id = '' } = req.params - if (isItem(req.body)) { - res.locals['data'] = await action(name, id, req.body) + if (!isItem(req.body)) { + res.status(400).json({ error: 'Body must be a JSON object' }) + return } + res.locals['data'] = await action(name, id, req.body) next?.() } }