Проблема в обработчике создания пользователя Node.js
Возникла проблема с "app.post" пытаюсь реализовать роут создания пользователя. Должно получиться так, что-бы при добавлении пользователя c переданными данными ему присваивался свой id, но получается так, что создается только один пользователь и все. Все остальное работает корректно, проверка, изменение, удаление и поиск по id (пользуюсь Postman)
const express = require('express');
const Joi = require('joi');
const fs = require('fs');
const path = require('path');
const app = express();
const users = [];
let uniqueID = 0;
const userScheme = Joi.object({
firstName: Joi.string().min(2).required(),
secondName: Joi.string().min(2).required(),
age: Joi.number().min(0).max(150).required(),
city: Joi.string().min(3)
})
app.use(express.json())
app.get('/users', (req, res) => {
const pathUsers = path.join(__dirname, 'users.json');
const usersData = JSON.parse(fs.readFileSync(pathUsers, 'utf-8'));
res.send({usersData});
});
app.post('/users', (req, res) => {
uniqueID += 1;
users.push({
id: uniqueID,
...req.body
});
fs.writeFileSync(path.join(__dirname, 'users.json'), JSON.stringify(users, null, 2));
res.send({id: uniqueID});
});
app.put('/users/:id', (req, res) => {
const pathUsers = path.join(__dirname, 'users.json');
const usersData = JSON.parse(fs.readFileSync(pathUsers, 'utf-8'));
const result = userScheme.validate(req.body);
if (result.error) {
return res.status(404).send({error: result.error.details})
}
const userId = +req.params.id;
const user = usersData.find((user) => user.id === userId);
if(user) {
const {firstName, secondName, age, city} = req.body;
user.firstName = firstName,
user.secondName = secondName,
user.age = age,
user.city = city
fs.writeFileSync(path.join(__dirname, 'users.json'), JSON.stringify(usersData, null, 2));
res.send({user})
} else {
res.status(404);
res.send({user: null});
}
});
app.get('/users/:id', (req, res) => {
const pathUsers = path.join(__dirname, 'users.json');
const usersData = JSON.parse(fs.readFileSync(pathUsers, 'utf-8'));
const userId = +req.params.id;
const user = usersData.find((user) => user.id === userId);
if(user) {
res.send({user})
} else {
res.status(404);
res.send({user: null});
}
});
app.delete('/users/:id', (req, res) => {
const pathUsers = path.join(__dirname, 'users.json');
const usersData = JSON.parse(fs.readFileSync(pathUsers, 'utf-8'));
const userId = +req.params.id;
const user = usersData.find((user) => user.id === userId);
if(user) {
const usrIndex = users.indexOf(user);
usersData.splice(usrIndex, 1);
fs.writeFileSync(path.join(__dirname, 'users.json'), JSON.stringify(usersData, null, 2));
res.send({user})
} else {
res.status(404);
res.send({user: null});
}
});
app.listen(3000);
Так-же пробовал:
app.post('/users', (req, res) => {
const pathUsers = path.join(__dirname, 'users.json');
const usersData = JSON.parse(fs.readFileSync(pathUsers, 'utf-8'));
uniqueID += 1;
usersData.push({
id: uniqueID,
...req.body
});
fs.writeFileSync(path.join(__dirname, 'users.json'), JSON.stringify(usersData, null, 2));
res.send({id: uniqueID});
});
Но в данном случае он добавляет пользователей(если файл users.json существует), но с одинаковым id и при том, что если файла users.json нет, то он не создает его и выдает ошибку
Ответы (2 шт):
получается так, что создается только один пользователь и все
У меня все нормально инкрементируется и создается... Для простоты все делается без учета протокола, только анализ УРЛа.
const http = require('http');
let id = 0
const arr = []
http.createServer(function (request, response) {
const url = request.url
response.setHeader(
'Content-Type',
'text/html; charset=utf-8;'
);
response.write('<!DOCTYPE html>');
response.write('<html>');
response.write('<body>');
if (url == '/add') {
arr.push({
id: ++id,
date: new Date()
})
response.write(`<p>Пользователь добавлен. ИД ${id}</p>`);
} else {
response.write('<p>Пользователи</p>');
response.write('<ul>');
arr.forEach(o => {
response.write('<ll>');
response.write(`ИД ${o.id} дата ${o.date.toString()}`);
response.write('</ll>');
})
response.write('</ul>');
}
response.write('</body>');
response.write('</html>');
response.end();
}).listen(3000);
В вашем коде есть две проблемы.
Первая, простая проблема, состоит в том, что счётчик uniqueID обнуляется при каждом рестарте сервиса. Решается эта проблема тоже просто - нужно хранить последнее значение счётчика в файле users.json.
Вторая, сложная проблема. В каждом обработчике запроса вы делаете одно и то же: открываете файл, совершаете магию с данными, записываете в файл что-то. Такой подход даже на ваших 5 обработчиках приводит к тому, что каждое изменение бизнес-логики должно дублироваться, что является прямой дорогой к ошибкам. Короче, запросы должны быть отдельно, работа с хранилищем данных должна быть отдельно. Посмотрите, как я написал getRepository, даже в нём работа с файлом отделена от работы с данными:
// @ts-check
/**
* @typedef {{
* firstName: string;
* secondName: string;
* age: number;
* city?: string;
* }} IUserModel
*/
/**
* @template [T = Record<string, any> & { id: number }]
* @typedef {{
* seq: number;
* records: Record<string, T & { id: number }>;
* }} IRecordsStorage
*/
const fs = require('node:fs');
const path = require('node:path');
const express = require('express');
const Joi = require('joi');
const app = express();
app.use(express.json());
/** @type {import('joi').ObjectSchema<IUserModel>} */
const userScheme = Joi.object({
firstName: Joi.string().min(2).required(),
secondName: Joi.string().min(2).required(),
age: Joi.number().min(0).max(150).required(),
city: Joi.string().min(3)
});
/** @type {ReturnType<typeof getRepository<IUserModel>>} */
const UsersStorage = repositoryFactory('users.json');
app.get('/users', (req, res) => {
res.json({ data: UsersStorage.findMany() });
});
app.post('/users', (req, res) => {
const record = UsersStorage.insert(req.body);
res.json(record);
});
app.put('/users/:id', (req, res) => {
const { error } = userScheme.validate(req.body);
if (error) {
return res.status(404).send({ error: error.details })
}
const userId = +req.params.id;
if (!UsersStorage.findOne(userId)) {
return res.status(404).send();
}
const record = UsersStorage.update({ ...req.body, id: userId });
res.json(record);
});
app.get('/users/:id', (req, res) => {
const record = UsersStorage.findOne(+req.params.id);
if (!record) {
return res.status(404).send();
}
res.json(record);
});
app.delete('/users/:id', (req, res) => {
const userId = +req.params.id;
UsersStorage.delete(userId);
res.status(204).send();
});
app.listen(3000, () => console.log('server started...'));
/**
* @template [T = Record<string, any>]
* @param {string} filename
* @returns {ReturnType<typeof getRepository<T>>}
*/
function repositoryFactory(filename) {
/** @type {Map<string, ReturnType<typeof getRepository<T>>>} */
const repositoryMap = new Map();
const result = repositoryMap.get(filename) || getRepository(filename);
if (!repositoryMap.has(filename)) {
repositoryMap.set(filename, result);
}
return result;
}
/**
* @template [T = Record<string, any> & { id: number }]
* @param {string} filename
*/
function getRepository(filename) {
const filepath = path.join(__dirname, filename);
/** @type {IRecordsStorage<T>} */
let storage = { seq: 0, records: {} };
try {
storage = JSON.parse(fs.readFileSync(filepath, 'utf-8'));
storage.seq ||= 0;
storage.records ||= {};
} catch { }
const sync = () => fs.writeFileSync(filepath, JSON.stringify(storage, null, 2));
return {
findOne(/** @type {string | number} */ id) {
const record = storage.records?.[id];
return record || null;
},
findMany() {
const records = Object.values(storage.records);
records.sort((a, b) => a.id - b.id);
return records;
},
insert(/** @type {T} */ data) {
const record = { ...data, id: ++storage.seq };
storage.records[record.id] = record;
sync();
return record;
},
update(/** @type {IRecordsStorage<T>['records'][string]} */ item) {
const record = storage.records[item.id] = item;
sync();
return record;
},
delete(/** @type {IRecordsStorage<T>['records'][string] | number | string} */ itemOrId) {
const id = typeof itemOrId === 'number' || typeof itemOrId === 'string'
? itemOrId
: itemOrId.id;
delete storage.records[id];
sync();
},
};
}