diff --git a/backend/todo-api/server.js b/backend/todo-api/server.js new file mode 100644 index 00000000..1d1c66de --- /dev/null +++ b/backend/todo-api/server.js @@ -0,0 +1,95 @@ +const express = require('express'); +const app = express(); +const PORT = 3000; + +// Middleware for parsing JSON +app.use(express.json()); + +// In-memory storage +let todos = []; +let nextId = 1; + +// GET /api/todos - list all todos +app.get('/api/todos', (req, res) => { + res.json(todos); +}); + +// GET /api/todos/:id - get single todo +app.get('/api/todos/:id', (req, res) => { + const id = parseInt(req.params.id); + const todo = todos.find(t => t.id === id); + + if (!todo) { + return res.status(404).json({ error: 'Todo not found' }); + } + + res.json(todo); +}); + +// POST /api/todos - create new todo +app.post('/api/todos', (req, res) => { + const { title, completed } = req.body; + + // Validation + if (!title || typeof title !== 'string' || !title.trim()) { + return res.status(400).json({ error: 'Title is required and must be a non-empty string' }); + } + + const newTodo = { + id: nextId++, + title: title.trim(), + completed: completed === true, // default false unless explicitly true + createdAt: new Date().toISOString(), + }; + + todos.push(newTodo); + res.status(201).json(newTodo); +}); + +// PUT /api/todos/:id - update todo +app.put('/api/todos/:id', (req, res) => { + const id = parseInt(req.params.id); + const { title, completed } = req.body; + const todo = todos.find(t => t.id === id); + + if (!todo) { + return res.status(404).json({ error: 'Todo not found' }); + } + + // Validation + if (title !== undefined && (typeof title !== 'string' || !title.trim())) { + return res.status(400).json({ error: 'Title must be a non-empty string if provided' }); + } + if (completed !== undefined && typeof completed !== 'boolean') { + return res.status(400).json({ error: 'Completed must be a boolean value' }); + } + + if (title !== undefined) todo.title = title.trim(); + if (completed !== undefined) todo.completed = completed; + + res.json(todo); +}); + +// DELETE /api/todos/:id - delete todo +app.delete('/api/todos/:id', (req, res) => { + const id = parseInt(req.params.id); + const index = todos.findIndex(t => t.id === id); + + if (index === -1) { + return res.status(404).json({ error: 'Todo not found' }); + } + + todos.splice(index, 1); + res.status(204).send(); // No content +}); + +// Generic error handler +app.use((err, req, res, next) => { + console.error('Unexpected error:', err); + res.status(500).json({ error: 'Internal server error' }); +}); + +// Start server +app.listen(PORT, () => { + console.log(`🚀 Server running at http://localhost:${PORT}`); +});