В данной записке будут рассмотрены необходимые действия для запуска сервера/клиента и дополнительные библиотеки с примерами использования 😊
- Возможно потребуется VPN.
- Зарегистрироваться на сайте MongoDB и выбрать бесплатный тариф.
- Создать кластер.
- Чтобы подключить БД к приложению, требуется ссылка на эту БД. Чтобы её взять надо:
- выбрать в списке DEPLOYMENT -> Database
- В созданном кластере нажать на кнопку
Connect
- После чего в пункте Connect to your application нажать на кнопку
Drivers
- Внизу будет код следующего вида:
где надо поменять данные в строке: admin на имя пользователя кластера, и password на его пароль.
mongodb+srv://admin:<password>@cluster228.hdf1337.mongodb.net/?retryWrites=true&w=majority
- Для удобной работы с POST/GET/PUT/DELETE запросами скачать Insomnia.
- Скачать и установить последнюю версию LTS node.js.
- Для создания файла package.json прописать в консоли папки проекта:
npm init
- Установить библиотеки:
npm install bcrypt
- шифрование пароля,npm install express
- веб-сервер,npm install express-validator
- валидация запросов,npm install jsonwebtoken
- аутентификация/авторизация,npm install mongoose
- работа с базой данных,npm install multer
- загрузка файлов/изображений,npm install nodemon
- автоматически перезапускает проект при обновлении файлов.
- Для работы с модулями в package.json добавить:
"type": "module"
- Чтобы настроить nodemon в package.json надо написать:
"scripts": {
"startapp": "nodemon index.js"
}
После чего проект надо запускать командой npm run startapp
- Подключение к MongoDB:
mongoose.connect('mongodb+srv://admin:[email protected]/blog?retryWrites=true&w=majority')
.then(() => console.log('DB OK'))
.catch((err) => console.log('DB error', err));
- Для того, чтобы хранить изображения на сервере, надо использовать
Multer
. Так выглядит настройка в index.js:
const storage = multer.diskStorage({
destination: (_, __, cb) => {
cb(null, 'uploads');
},
filename: (_, file, cb) => {
cb(null, file.originalname);
}
});
const upload = multer({ storage });
app.use(express.json({ extended: true }));
app.use('/uploads', express.static('uploads'));
app.post('/upload', checkAdmin, upload.single('image'), (req, res) => {
res.json({
url: `/uploads/${req.file.originalname}`
});
});
Таким образом картинки будут храниться в папке uploads и открываться по ссылке /uploads/{img name}.
- Для того, чтобы хранить Id пользователя и другие полезные данные, можно использовать токен
JSON Web Token
const token = jwt.sign(
{
_id: user._id,
admin: user.admin,
},
'secret123',
{
expiresIn: '30d',
},
);
В данном случае сохраняется Id и является ли пользователь админом. Также указано, что токен действителен 30 дней. И указан ключ, по которому будет происходить расшифровка токена - 'secret123'. Расшифровка токена:
const token = (req.headers.authorization || '').replace(/Bearer\s?/, '');
const decoded = jwt.verify(token, 'secret123');
В данном случае decoded будет хранить в себе decoded.admin и decoded._id.
- Для валидации запросов, можно воспользоваться
express-validator
:
export const registerValidator = [
body('email', 'Error email').isEmail(),
body('password', 'Password should be more then 5 symbols').isLength({ min: 5 }),
body('firstName', 'FirstName should be more then 3 symbols').isLength({ min: 3 }),
body('lastName', 'lastName should be more then 3 symbols').isLength({ min: 3 }),
body('patronymic', 'Patronymic should be more then 3 symbols').isLength({ min: 3 }),
body('phoneNumber', 'Error phoneNumber').isMobilePhone(),
body('birthDate', 'Error birthDate').isDate(),
body('birthDate', 'BirthDate should be more then 18').custom((value) => {
const age = (new Date().getTime() - new Date(value).getTime()) / (365 * 24 * 60 * 60 * 1000);
return age >= 18;
}),
];
Данная библиотека имеет различные методы для проверки данных, такие как isEmail(), isMobilePhone() и тд. В body сначала передаётся название переменной, которое надо проверить, а после текст ошибки, если валидация не пройдёт. После body идут условия проверки. Также можно написать свою собственную проверку с помощью custom.
Пример использования валидации:
app.post('/auth/register', Validator.registerValidator, handleValidationErrors, UserController.register);
- Чтобы зашифровать пароль, можно воспользоваться
BCrypt
:
await bcrypt.hash(req.body.password, await bcrypt.genSalt(10))
Сравнение зашифрованного пароля и пароля, который пользователь отправил на сервер:
const isValidPass = await bcrypt.compare(req.body.password, user._doc.passwordHash);
if (!isValidPass) {
return req.status(404).json({
message: 'Error email/password',
});
}
- Также стоит отметить, что модели и контроллеры вынесены в отдельные папки, чтобы структурировать проект.
- Создать проект:
npx create-react-app my-app
- Чтобы установить необходимые библиотеки достаточно написать в консоли
npm i
- Установка router-dom -
npm install react-touter-dom
. С помощью этой библиотеки удобно указывать пути к страницам. - Запустить React приложение -
npm start
- В файле package.json необходимо дописать прокси, чтобы клиент мог обращаться к серверу:
"proxy": "http://localhost:8000"
- Пример установки пути к странице в App.js:
<BrowserRouter>
<Routes>
<Route path="rooms" element={<ListRoomsPage />}>
</Route>
</Routes>
</BrowserRouter>
- Для работы с состоянием и данными пользователя использовался провайдер:
<AuthContext.Provider value={{
token, login, logout, _id, isAdmin, isAuthenticated, ready
}}>
Провайдер в свою очередь использует хук auth.hook.js. Пример использования:
const auth = useContext(AuthContext);
auth.logout();
Стоит обратить внимание, что важные данные как токен и тд хранятся в localStorage.
- Для упрощения запросов к серверу, был написан хук http.hook.js. Пример использования:
const { request } = useHttp();
const fetchData = useCallback(async () => {
try {
const data2 = await request('/categories', 'GET', null);
setСategories(data2);
const data = await request('/rooms', 'GET', null);
setRooms(data);
setOriginalRooms(data);
} catch (e) { }
}, [request]);