На прошлой неделе я много играл с Mongoose. Я создал шаблон NodeJS API, чтобы помочь мне запустить какой-то проект REST API. Я устанавливаю обычную аутентификацию с помощью PassportJS со стратегиями local и JWT. Делая это, я нашел несколько полезных трюков с Mongoose. Некоторые советы я никогда не видел где-то может быть, я не искал много 😃, и я хочу поделиться с вами тем, что я нашел.
toJSON()
Например, вы хотите выполнить аутентификацию в своем приложении и не хотите отправлять пароль во внешний интерфейс. Это нормально, потому что это большая проблема безопасности, если вы это сделали. Итак, вы можете сделать это, создав функцию, которая берет вашего пользователя и возвращает новый объект.
function getUser(user) { return { _id: user._id, username: user.username, }; }
Эта стратегия работает, но я думаю, что та, которую я покажу, будет лучше.
UserSchema.methods = { /** * Authenticate the user * * @public * @param {String} password - provided by the user * @returns {Boolean} isMatch - password match */ authenticateUser(password) { return compareSync(password, this.password); }, /** * Hash the user password * * @private * @param {String} password - user password choose * @returns {String} password - hash password */ _hashPassword(password) { return hashSync(password); }, /** * Generate a jwt token for authentication * * @public * @returns {String} token - JWT token */ createToken() { return jwt.sign( { _id: this._id, }, constants.JWT_SECRET, ); }, /** * Parse the user object in data we wanted to send when is auth * * @public * @returns {Object} User - ready for auth */ toAuthJSON() { return { _id: this._id, token: `JWT ${this.createToken()}`, }; }, /** * Parse the user object in data we wanted to send * * @public * @returns {Object} User - ready for populate */ toJSON() { return { _id: this._id, username: this.username, }; }, };
Так что здесь нам есть что проверить 😃. Методы в мангусте, наконец, то, что они сказали. Это методы, доступные для вашего пользовательского объекта. Например, здесь у нас есть authenticateUser(password), который используется для аутентификации пользователя, находящегося по электронной почте, если пароль правильный. То же самое касается _hashPassword(password), которые просто хэшируют пароль перед сохранением пользователя в БД. createToken() как говорится в названии, создайте токен JWT и может быть пользователем прямо внутри ответа res.status(200).json({ user, token: user.createToken() }).
Но тот, который я хочу, чтобы вы увидели, это toJSON(). Это используется, когда, наконец, вы на своем пользователе. Итак, если вы вернетесь назад res.status(200).json({ user, token: user.createToken() }), вы увидите, что я отправил пользователя. Поскольку у нас есть toJSON(), заставьте его работать именно так. Мы не отправляем метки времени, адрес электронной почты, пароль и т. д. Мы просто отправляем _id и username и больше ничего. Но хорошо, почему toAuthJSON()? Потому что теперь я могу переформатировать ответ, чтобы он был res.status(200).send(user.toAuthJSON()), поэтому я просто отправляю объект с _id и token. Надеюсь, эта часть имеет смысл 😃.
Причина, по которой нужны методы для JSON ниже 😃.
Статика
После этого в Mongoose у вас есть доступ к чему-то, что называется Statics в вашей схеме. Это то же самое, что и в классе. Статика — это метод, который можно использовать без инициации. Таким образом, вы можете использовать его прямо с самой моделью.
Пример
PostSchema.statics = { /** * Create a post * * @public * @param {Object} args - Object contains title and text * @param {String} authorId - the author id * @returns {Post} Post Object - new post create */ createPost(args, authorId) { return this.create({ ...args, author: authorId, }); }, list({ skip = 0, limit = 10 }) { return this.find() .sort({ createdAt: -1 }) .skip(skip) .limit(limit) .populate('author'); }, };
Здесь у меня есть 2 метода статики для моего поста. Наконец, этот метод предназначен только для абстрагирования части вашего кода. Для меня это немного упрощает жизнь и делает контроллер чище. createPost(args, authorId) это для того, чтобы немного почистить код. Я могу использовать его, выполнив Post.createPost({ title: 'Hello' }, '123'). Я просто удаляю некоторый код и делаю его немного проще, когда дело доходит до изменения БД. Я могу оставить тот же контроллер, но просто изменю свои Post сервисы.
После этого у нас есть list({ skip = 0, limit = 10 }). Это просто для облегчения разбиения на страницы. Вы можете видеть, что я использую функцию ES6 Параметры по умолчанию, которая позволяет мне добавлять параметры по умолчанию, если эти значения равны undefined. Опять же, я могу использовать его вот так Post.list({ skip: 5, limit: 20 });. Это снова для меня просто сахар и упрощает мой код.
Снова в JSON() 😃
В последнем примере в списке у нас есть .populate('author');. Из-за toJSON() по умолчанию у пользователя будут только _id и username, нет необходимости добавлять значение выбора и т. д. :). Вот почему у меня есть toAuthJSON(), который вызывается при входе в систему, и toJSON() для подобных вещей.
Пакеты
Некоторые пакеты, которые я не знал в экосистеме NodeJS, и которые нужно использовать 😄.
Мне очень нравится этот, потому что он помогает мне сделать проверку в моем контроллере. Так же легко использовать.
export const validation = { create: { body: { title: Joi.string().min(3).required(), text: Joi.string().required(), }, }, update: { body: { title: Joi.string().min(3), text: Joi.string(), }, }, };
После этого в своем файле маршрутов делаете с помощью экспресс-проверки
routes.post( '/', authJwt, validate(PostController.validation.create), PostController.create, ); routes.patch( '/:id', authJwt, validate(PostController.validation.update), PostController.updatePost, );
Helmet — это библиотека, которая поможет вам защитить ваше приложение Express. Легко установить, просто нужно добавить его в качестве промежуточного программного обеспечения app.use(helmet()). Это для получения стандарта. Вы можете проверить их GitHub, чтобы увидеть другой способ.
Cors — это промежуточное программное обеспечение, которое позволяет вам выполнять запрос Cross-Origin. Можно добавить, чтобы все заработало, просто выполнив app.use(cors()), но неплохо добавить в белый список только интерфейсную часть и т. д. Еще раз просмотрите документацию, прежде чем использовать ее.
Http-Status просто упростит вашу жизнь, добавляя статус к вашей конечной точке.
export async function getList(req, res, next) { try { return res .status(HTTPStatus.OK) .json(await Post.list({ skip: req.query.skip, limit: req.query.limit })); } catch (err) { err.status = HTTPStatus.BAD_REQUEST; return next(err); } }
Другие полезные пакеты
Prettier поможет вам переформатировать ваш код и сделать его лучше в кратчайшие сроки. Я начал использовать его около 1 месяца назад и теперь использую его в каждом проекте, который делаю. Эти простые в установке пакеты сэкономят ваше время и сделают ваш код намного лучше. PS, если вы используете его с eslint и у вас много красных ошибок, возможно, добавьте eslint-config-prettier в свой проект и добавьте его в свои расширения в .eslintrc. Это устранит проблему eslint с синтаксисом и улучшит управление.
Пример
{ "extends": [ "equimper", "prettier" ] }
Lint-Staged запустит ваш линтер на вашем коммите. Зачем это? Потому что, возможно, вы используете eslint и красивее и забыли все время запускать скрипты. Таким образом, ваш код выглядит плохо и т. д. Добавив эти инструменты, ваша фиксация будет линтинговать, прежде чем это позволит сделать вашу фиксацию. Может быть очень полезным для проекта с большим количеством людей.
Для добавления я просто добавляю это в свой packages.json
{ "pre-commit": "lint-staged", "lint-staged": { "*.js": [ "eslint", "yarn prettier", "git add" ] }, "scripts": { "lint": "eslint src --color", "prettier": "node ./scripts/prettier.js write", "lint-staged": "lint-staged", } }
Конечное слово
Надеюсь, что эта небольшая статья была для вас золотой жилой пакетов и советов. Это был действительно хороший опыт работы над этим простым шаблоном. Пожалуйста, взгляните на это и дайте мне знать, что вы думаете об этом.