From bb57fee3ab98a50167cdc2f8e0e463a113805579 Mon Sep 17 00:00:00 2001 From: AJ Enns Date: Fri, 26 Jun 2026 14:13:47 -0500 Subject: [PATCH] Add input validation to POST /tasks Reject a missing, non-string, or whitespace-only title with HTTP 400 and a clear JSON error instead of creating an invalid task. Add tests covering the invalid cases and that no task is created. Fixes: #1 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- sample-app/src/app.test.ts | 33 +++++++++++++++++++++++++++++++++ sample-app/src/tasks/routes.ts | 7 +++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/sample-app/src/app.test.ts b/sample-app/src/app.test.ts index c2d8dfe..d7263fd 100644 --- a/sample-app/src/app.test.ts +++ b/sample-app/src/app.test.ts @@ -39,4 +39,37 @@ describe('Task API', () => { const res = await request(createApp()).get('/tasks/does-not-exist'); expect(res.status).toBe(404); }); + + it('rejects a missing title with 400 and does not create a task', async () => { + const app = createApp(); + + const res = await request(app).post('/tasks').send({}); + expect(res.status).toBe(400); + expect(res.body.error).toBeTruthy(); + + const list = await request(app).get('/tasks'); + expect(list.body).toHaveLength(0); + }); + + it('rejects a non-string title with 400 and does not create a task', async () => { + const app = createApp(); + + const res = await request(app).post('/tasks').send({ title: 42 }); + expect(res.status).toBe(400); + expect(res.body.error).toBeTruthy(); + + const list = await request(app).get('/tasks'); + expect(list.body).toHaveLength(0); + }); + + it('rejects a whitespace-only title with 400 and does not create a task', async () => { + const app = createApp(); + + const res = await request(app).post('/tasks').send({ title: ' ' }); + expect(res.status).toBe(400); + expect(res.body.error).toBeTruthy(); + + const list = await request(app).get('/tasks'); + expect(list.body).toHaveLength(0); + }); }); diff --git a/sample-app/src/tasks/routes.ts b/sample-app/src/tasks/routes.ts index e3eabca..9d4f799 100644 --- a/sample-app/src/tasks/routes.ts +++ b/sample-app/src/tasks/routes.ts @@ -10,9 +10,12 @@ export function createTaskRouter(store: TaskStore): Router { }); router.post('/', (req, res) => { - // Exercise 1: validate that req.body.title is a non-empty string and - // return 400 with a helpful message when it is not. const { title } = req.body ?? {}; + if (typeof title !== 'string' || title.trim() === '') { + return res.status(400).json({ + error: 'title is required and must be a non-empty string', + }); + } const task = store.create(title); res.status(201).json(task); });