Ответ
Да, унификация CRUD (Create, Read, Update, Delete) — это распространенная и хорошая практика в Node.js, которая снижает дублирование кода и упрощает поддержку. Вот основные подходы:
1. Унифицированный роутинг (например, в Express):
Использование router.route() позволяет группировать обработчики для одного ресурса.
const express = require('express');
const router = express.Router();
// Унифицированный маршрут для ресурса 'items'
router.route('/items')
.get(async (req, res) => { // READ (множество)
const items = await ItemModel.find(req.query);
res.json(items);
})
.post(async (req, res) => { // CREATE
const newItem = await ItemModel.create(req.body);
res.status(201).json(newItem);
});
router.route('/items/:id')
.get(async (req, res) => { // READ (один)
const item = await ItemModel.findById(req.params.id);
res.json(item);
})
.put(async (req, res) => { // UPDATE (полное)
const updatedItem = await ItemModel.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json(updatedItem);
})
.delete(async (req, res) => { // DELETE
await ItemModel.findByIdAndDelete(req.params.id);
res.status(204).send();
});
2. Базовый сервисный класс (Service/Repository Layer): Создание абстрактного класса, который инкапсулирует общую логику работы с моделью данных.
class BaseService {
constructor(model) {
this.model = model;
}
async create(data) {
return await this.model.create(data);
}
async findById(id) {
return await this.model.findById(id);
}
async findAll(filter = {}) {
return await this.model.find(filter);
}
async update(id, data) {
return await this.model.findByIdAndUpdate(id, data, { new: true });
}
async delete(id) {
return await this.model.findByIdAndDelete(id);
}
}
// Использование
const UserService = new BaseService(UserModel);
const newUser = await UserService.create({ name: 'John' });
3. Использование возможностей ORM/ODM (Mongoose, TypeORM): Эти библиотеки уже предоставляют унифицированные методы для CRUD.
// Mongoose предоставляет стандартизированные методы
const item = await Item.findById('someId'); // Read
const items = await Item.find({ active: true }); // Read All
const newItem = await Item.create({ name: 'New' }); // Create
await Item.findByIdAndUpdate('someId', { name: 'Updated' }); // Update
await Item.findByIdAndDelete('someId'); // Delete
Преимущества: Согласованность API, меньше повторяющегося кода, легче вводить общие улучшения (например, пагинацию, логирование). Предостережение: Не стоит чрезмерно абстрагировать уникальную бизнес-логику, которая не вписывается в шаблон CRUD.
Ответ 18+ 🔞
Э, слушай, ну это ж классика, ебать мои старые костыли! Каждый второй проект на Node.js через это проходит. Все эти CRUD-ы — Create, Read, Update, Delete — они как назойливые родственники, везде лезут. И каждый раз одно и то же писать — это же пиздец какой-то, удивление пиздец, честно. Ну не может же быть, чтобы нельзя было это как-то унифицировать, чтобы не копипастить одно и то же до овердохуища раз.
Так вот, есть несколько проверенных способов не сойти с ума.
Первый, самый простой — роутинг в Express привести в божеский вид. Вместо того чтобы раскидывать кучу отдельных маршрутов, можно собрать их в кучу. Смотри, как красивше:
const express = require('express');
const router = express.Router();
// Всё для сущности 'items' в одном месте, ёпта!
router.route('/items')
.get(async (req, res) => { // Достаём всё (Read)
const items = await ItemModel.find(req.query);
res.json(items);
})
.post(async (req, res) => { // Создаём (Create)
const newItem = await ItemModel.create(req.body);
res.status(201).json(newItem);
});
router.route('/items/:id')
.get(async (req, res) => { // Достаём один (Read one)
const item = await ItemModel.findById(req.params.id);
res.json(item);
})
.put(async (req, res) => { // Обновляем целиком (Update)
const updatedItem = await ItemModel.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json(updatedItem);
})
.delete(async (req, res) => { // Удаляем нахуй (Delete)
await ItemModel.findByIdAndDelete(req.params.id);
res.status(204).send();
});
Видишь? Всё аккуратно, по полочкам. Не размазано по десяти файлам. Читать приятно, понимаешь, где что искать.
Второй подход — сделать какого-нибудь универсального солдата, сервисный класс. Это когда ты выносишь всю рутину в отдельное место, а в контроллерах только вызываешь. Типа так:
class BaseService {
constructor(model) {
this.model = model; // Подсовываем любую модель — и работает!
}
async create(data) {
return await this.model.create(data);
}
async findById(id) {
return await this.model.findById(id);
}
async findAll(filter = {}) {
return await this.model.find(filter);
}
async update(id, data) {
return await this.model.findByIdAndUpdate(id, data, { new: true });
}
async delete(id) {
return await this.model.findByIdAndDelete(id);
}
}
// Используем — просто праздник какой-то!
const UserService = new BaseService(UserModel);
const newUser = await UserService.create({ name: 'Васян' });
Получается, что для каждой новой сущности ты не пишешь сервис с нуля, а просто создаёшь инстанс этого базового класса. Экономия времени — просто ядрёна вошь!
Ну и третий вариант — просто пользоваться тем, что дают библиотеки. Возьмём Mongoose — он же из коробки всё умеет. Зачем изобретать велосипед?
// Всё уже есть, ёпта! Бери и пользуйся.
const item = await Item.findById('someId'); // Нашли один
const items = await Item.find({ active: true }); // Нашли все активные
const newItem = await Item.create({ name: 'Новый' }); // Создали
await Item.findByIdAndUpdate('someId', { name: 'Обновлённый' }); // Поправили
await Item.findByIdAndDelete('someId'); // Отправили в утиль
В чём профит, спросишь? Да всё просто: код становится предсказуемым. Зашёл в любой контроллер — там одинаковая структура. Хочешь добавить пагинацию или логирование — поправил в одном месте, и оно везде применилось. Не надо бегать по всем файлам, как угорелый.
Но! Есть одно важное «но», чувак. Не надо сходить с ума и пытаться впихнуть в эту унификацию всю свою бизнес-логику. Если у тебя есть какая-то хитрая жопа операция, которая в стандартный CRUD ну никак не лезет — вынеси её отдельно. Не делай из базового сервиса монстра с сотней методов, а то потом сам от себя охуеешь, когда его поддерживать придётся. Всё должно быть в меру.