#javascript #node.js #express #dependency-injection #integration-testing
#javascript #node.js #выразить #внедрение зависимостей #интеграция-тестирование
Вопрос:
Я следую модульной или компонентной структуре. Я нашел образец репозитория.
https://github.com/sujeet-agrahari/node-express-clean-architecture
Итак, существует основной component.module.js файлы, которые отвечают за подключение всех других элементов, таких как контроллер, маршрут и службы.
Для контроллера службы внедряются с использованием функций более высокого порядка. Теперь контроллер очень прост в тестировании, я могу легко заглушать или имитировать сервисы.
auth.module.js
const router = require('express').Router();
const {
makeExpressCallback,
makeValidatorCallback,
} = require('../../middlewares');
// validator
const AuthValidator = require('./auth.validator');
// service
const { doRegister, doLogin, doCheckUserExist } = require('./auth.service');
const { BadRequestError } = require('../../utils/api-errors');
// controller
const controller = require('./auth.controller');
const register = controller.register({ BadRequestError, doCheckUserExist, doRegister });
const login = controller.login({ doCheckUserExist, doLogin });
const AuthController = { register, login };
// routes
const routes = require('./auth.routes')({
router,
AuthController,
AuthValidator,
makeValidatorCallback,
makeExpressCallback,
});
module.exports = {
AuthController,
AuthService: {
doCheckUserExist,
doLogin,
doRegister,
},
AuthRoutes: routes,
};
auth.controller.js
const login = (doCheckUserExist, doLogin) => async (httpRequest) => {
const { username, password } = httpRequest.body;
const userData = await doCheckUserExist({ username });
const loginData = {
username,
role: userData.role_id,
passedPassword: password,
actualPassword: userData.password,
};
const loginResult = await doLogin(loginData);
return {
statusCode: 200,
body: {
success: true,
message: 'Successfully logged in!',
data: loginResult,
},
};
};
const register = ({ BadRequestError, doCheckUserExist, doRegister }) => async (httpRequest) => {
const { username, password } = httpRequest.body;
try {
await doCheckUserExist({ username });
} catch (error) {
// user doesn't exist
const registerResult = await doRegister({ username, password });
return {
statusCode: 200,
body: {
success: true,
message: 'Registered successfully!',
data: registerResult,
},
};
}
throw new BadRequestError('User already exist!');
};
module.exports = { register, login };
С контроллером все в порядке, теперь проблема в сервисах. Я не могу найти какой-либо шаблон, чтобы сделать их тонкими и чистыми.
auth.services.js
const {
JWT_ACCESS_TOKEN_SECRET,
ACCESS_TOKEN_EXPIRES_IN,
SIGN_OPTION,
} = require('config');
const bcrypt = require('bcryptjs');
const { User } = require('../../db');
const { generateJWT } = require('./jwt.service');
const { NotFoundError, BadRequestError } = require('../../utils/api-errors');
const doRegister = async ({ username, password }) => {
const user = await User.create({
username,
password,
role_id: 1, // assign role id here
});
// generate access token
const payload = {
username,
role: user.role_id,
};
const token = await generateJWT({
secretKey: JWT_ACCESS_TOKEN_SECRET,
payload,
signOption: {
...SIGN_OPTION,
expiresIn: ACCESS_TOKEN_EXPIRES_IN,
},
});
return {
access_token: token,
...payload,
};
};
const doLogin = async ({
username, userRole, passedPassword, actualPassword,
}) => {
const isValidPass = bcrypt.compareSync(passedPassword, actualPassword);
if (!isValidPass) throw new BadRequestError('Username or Password is invalid!');
// generate access token
const payload = {
username,
role: userRole,
};
const token = await generateJWT({
secretKey: JWT_ACCESS_TOKEN_SECRET,
payload,
signOption: {
...SIGN_OPTION,
expiresIn: ACCESS_TOKEN_EXPIRES_IN,
},
});
return {
access_token: token,
...payload,
};
};
const doCheckUserExist = async ({ username }) => {
const user = await User.findOne({
where: {
username,
},
});
if (!user) throw new NotFoundError('User not found!');
return user;
};
module.exports = { doRegister, doLogin, doCheckUserExist };
Многое происходит в сервисах, импорте моделей, импорте констант и других утилит.
Теперь сервисы становятся действительно сложными для тестирования.
Есть ли какой-либо способ или шаблон, по которому я могу отделить некоторую логику от сервисов и сделать их легче?
Я могу реализовать шаблон повторного размещения для методов БД, но я не знаю, как я могу реализовать с помощью sequelize?
Должен ли я использовать также функцию более высокого порядка для ввода всех утилит и констант в сервис, как я сделал для контроллера?