首页 > 解决方案 > 在基于组件的结构中注入服务依赖

问题描述

我遵循模块化或基于组件的结构。我找到了一个示例回购。

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 };

在服务、模型导入、常量导入和其他实用程序中发生了很多事情。

现在服务变得很难测试。

有什么方法或模式可以将一些逻辑与服务分开并使它们更轻吗?

我可以为 db 方法实现存储模式,但我不知道如何使用 sequelize 实现?

我是否也应该使用高阶函数来注入服务中的所有实用程序和常量,就像我为控制器所做的那样?

标签: javascriptnode.jsexpressdependency-injectionintegration-testing

解决方案


推荐阅读