Files
simplenote-web/src/routes/folders.js
Hiro 2d91e17c3e fix: resolve API inconsistencies found by Mokoto
- Bug 1: No fix needed - frontend already uses PUT for document updates
- Bug 2: Changed folders API to use 'project' param (matches documents)
- Bug 3: GET /folders now works without project filter (lists all folders)

Changes:
- folders.js: Accept 'project' instead of 'projectId', make it optional
- folderService.js: Support listing all folders when projectId is null
- api.js: Updated getFolders() to use 'project' param consistently
2026-03-28 17:36:58 +00:00

136 lines
4.6 KiB
JavaScript

/**
* SimpleNote Web - Folders Routes
* CRUD + tree for folders
*/
import { Router } from 'express';
import { authMiddleware } from '../middleware/auth.js';
import { getFolderService } from '../services/folderService.js';
import { NotFoundError, ValidationError } from '../utils/errors.js';
const router = Router();
router.use(authMiddleware);
// GET /folders?project=X&parentId=Y - List folders (project is optional, matches documents API)
router.get('/', async (req, res) => {
try {
const { project, parentId } = req.query;
const folderService = getFolderService();
const folders = await folderService.getFolders(project || null, parentId || null);
res.json({ folders });
} catch (err) {
if (err instanceof ValidationError) {
return res.status(400).json({ error: err.message, code: err.code });
}
if (err instanceof NotFoundError) {
return res.status(404).json({ error: err.message, code: err.code });
}
console.error('Error listing folders:', err);
res.status(500).json({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
}
});
// POST /folders - Create folder
router.post('/', async (req, res) => {
try {
const { name, projectId, parentId } = req.body;
if (!name) {
throw new ValidationError('name is required');
}
if (!projectId) {
throw new ValidationError('projectId is required');
}
const folderService = getFolderService();
const folder = await folderService.createFolder({ name, projectId, parentId: parentId || null });
res.status(201).json(folder);
} catch (err) {
if (err instanceof ValidationError || err instanceof NotFoundError) {
const status = err instanceof ValidationError ? 400 : 404;
return res.status(status).json({ error: err.message, code: err.code });
}
console.error('Error creating folder:', err);
res.status(500).json({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
}
});
// GET /folders/:id - Get folder contents
router.get('/:id', async (req, res) => {
try {
const folderService = getFolderService();
const folder = await folderService.getFolder(req.params.id);
res.json(folder);
} catch (err) {
if (err instanceof NotFoundError) {
return res.status(404).json({ error: err.message, code: err.code });
}
console.error('Error getting folder:', err);
res.status(500).json({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
}
});
// PUT /folders/:id - Update folder
router.put('/:id', async (req, res) => {
try {
const { name } = req.body;
const folderService = getFolderService();
const folder = await folderService.updateFolder(req.params.id, { name });
res.json(folder);
} catch (err) {
if (err instanceof NotFoundError) {
return res.status(404).json({ error: err.message, code: err.code });
}
if (err instanceof ValidationError) {
return res.status(400).json({ error: err.message, code: err.code });
}
console.error('Error updating folder:', err);
res.status(500).json({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
}
});
// DELETE /folders/:id - Delete folder
router.delete('/:id', async (req, res) => {
try {
const folderService = getFolderService();
const result = await folderService.deleteFolder(req.params.id);
res.json(result);
} catch (err) {
if (err instanceof NotFoundError) {
return res.status(404).json({ error: err.message, code: err.code });
}
console.error('Error deleting folder:', err);
res.status(500).json({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
}
});
// GET /folders/:id/documents - List documents in folder
router.get('/:id/documents', async (req, res) => {
try {
const folderService = getFolderService();
const result = await folderService.getFolderDocuments(req.params.id);
res.json(result);
} catch (err) {
if (err instanceof NotFoundError) {
return res.status(404).json({ error: err.message, code: err.code });
}
console.error('Error listing folder documents:', err);
res.status(500).json({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
}
});
// GET /folders/:id/tree - Get full folder tree
router.get('/:id/tree', async (req, res) => {
try {
const folderService = getFolderService();
const tree = await folderService.getFolderTree(req.params.id);
res.json(tree);
} catch (err) {
if (err instanceof NotFoundError) {
return res.status(404).json({ error: err.message, code: err.code });
}
console.error('Error getting folder tree:', err);
res.status(500).json({ error: 'Internal server error', code: 'INTERNAL_ERROR' });
}
});
export default router;