node.js - Node.JS服务层设计

标签 node.js error-handling architecture domain-driven-design design-by-contract

我有一个非常简单的express js服务器,该服务器接受来自客户端的请求,执行一些业务逻辑并响应该客户端。请求-响应管道由 Controller 处理,业务逻辑在服务层内部执行。该代码可以正常工作,但是我不确定从服务层向 Controller 返回错误的方式是否正确。

Controller 看起来像这样:

async createAnOrder(req, res, next) {
    try {

        // Input validations
        if (!req.body.name){
            throw new ClientFacingError(ERROR_CODES.BAD_REQUEST, "Name is missing")
        }

        let newOrder = new Order();
        let validationDictionary = new ValidationDictionary();

        if (!await orderService.createOrder(newOrder, validationDictionary)){
            return next(new ClientFacingError(ERROR_CODES.BAD_REQUEST, validationDictionary.getErrorMessage()));
        }

        res.json({
            orderId: newOrder.id
        })

    } catch (err) {
        if (err instanceof ClientFacingError) {
            res.status(err.code).json({ message: err.message })
        } else {
            res.status(500).json({ message: "Internal Error" })
        }
    }
}

orderService看起来像这样:
async createOrder(newOrder, validationDictionary) {

    // Business logic validation
    if (await orderDb.hasOrder(newOrder)) {
        validationDictionary.addError("Invalid Order", "Order already exists");
        return false;
    }

    await orderDb.createOrder(newOrder);
    return true;
}

我试图将业务层与其他所有层之间的关注点分离。我还希望在服务层方法和 Controller 之间建立一个智能合约。

我想我想做的是:
  • 输入验证发生在 Controller (基础结构)层,而与业务相关的验证仅发生在服务层
  • 服务层方法如果操作成功,则返回true;如果存在业务验证错误,则返回false。
  • 服务层方法引发的任何错误都是运行时错误,由 Controller 捕获并作为内部错误返回给客户端。

  • 另一种方法是遵守CQS原则。服务层方法不应返回值,而应引发异常以指示失败。这种方法的问题在于, Controller 不具有是否可以将错误消息返回给客户端的上下文。我可能能够从服务层引发ClientFacingError异常, Controller 可以使用该异常来确定是否可以将错误消息返回给客户端,但是感觉就像我正在将服务层耦合到基础结构层。

    最佳答案

    您有很好的担忧和好的方法,让我补充一些想法:

  • validation可以是服务的一部分,与主逻辑分开。因此,沿着createOrder,您还将拥有一个validateOrder(在您的服务中)。在您的 Controller 中,您可以像这样使用它:

  • Controller :
    try {
        ...
        orderService.validateOrder(order);
        orderService.createOrder(order);
        ...
    } catch (e) { 
        //handle e
    }
    

    解决此问题的方法是引发异常(例如在我的示例中),返回 bool(boolean) 值+错误代码,消息...的混合,或者只是将其嵌入createOrder中。这取决于您的项目需求和口味。
  • 如果出现问题,我会用简洁的消息引发异常,并从orderService中键入。代码会更优雅。如果一切顺利的话,返回实际新创建的订单对象也很不错,但是一开始 bool(boolean) 就足够了。 (考虑到您抛出异常,甚至无效)。
  • 在 Controller 中捕获异常,将其记录下来,并向客户端发送适当的响应。
  • 关于node.js - Node.JS服务层设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58339810/

    相关文章:

    node.js - 将AWS S3文件直接下载到目录

    python - 如果没有足够的输入,如何遍历文件并引发自定义异常?

    node.js - 从 Angular6 向 NodeJS Express 发送 POST 请求时出现未知错误

    php - 如何处理基于 MVC 的网站中的状态消息?

    javascript - javascript 错误 "Cannot read property ' foo' of null"和 "null is not an object"之间有什么区别

    android - Android 上的嵌套 MVP : how to

    c++ - 我的 C++ 游戏架构

    .net - 安全的数据库连接。 DAL .net 架构最佳实践

    node.js - 在服务器和客户端上的共享代码中呈现 Canvas 界面

    node.js - 在 AWS Lambda for Node 模板中返回没有 API 网关的 HTML 响应