Node.JS дизайн сервисного слоя - PullRequest
0 голосов
/ 11 октября 2019

У меня очень простой экспресс-сервер JS, который принимает запрос от клиента, выполняет некоторую бизнес-логику и отвечает клиенту. Конвейер запроса-ответа обрабатывается контроллером, а бизнес-логика выполняется на уровне сервиса. Код функционален, но я не уверен, что способ, которым я возвращаю ошибки в контроллер из уровня обслуживания, является правильным.

Контроллер выглядит примерно так:

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

Я пытаюсь разделить заботу между бизнес-уровнем и всем остальным. Мне также нужен умный контракт между методами уровня сервиса и контроллерами.

Я думаю, что я пытался сделать следующее:

  1. Проверка входных данных происходит на уровне контроллера (инфраструктуры)проверки, связанные с бизнесом, происходят только на уровне обслуживания
  2. Методы уровня обслуживания возвращают значение true, если операция прошла успешно, и false, если имеются ошибки проверки бизнеса.
  3. Любые ошибки, возникающие с помощью методов уровня обслуживания, относятся к среде выполнения. ошибки, которые обнаруживаются контроллерами и возвращаются клиенту как внутренняя ошибка.

Другой способ - придерживаться принципа CQS. Метод сервисного уровня не должен возвращать значение, а вместо этого выдает исключение, указывающее на ошибку. Проблема с этим подходом состоит в том, что у контроллеров нет контекста того, может ли сообщение об ошибке быть возвращено клиенту. Возможно, я смогу выбросить исключение ClientFacingError из сервисного уровня, который может использоваться контроллером, чтобы решить, можно ли вернуть сообщение об ошибке клиенту, но мне кажется, что я связываю сервисный уровень с уровнем инфраструктуры.

1 Ответ

0 голосов
/ 13 октября 2019

У вас есть хорошие проблемы и хороший подход, позвольте мне добавить несколько мыслей:

  • validation может быть частью службы, отделенной от основной логики. Таким образом, наряду с createOrder у вас также будет validateOrder (к вашим услугам). На вашем контроллере вы можете использовать его так:

Контроллер:

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

Для этого можно либо сгенерировать исключение (как в моем примере), вернуть микслогического + код ошибки, сообщение ... или просто вставить его в createOrder. Это зависит от потребностей вашего проекта и вашего вкуса.

  • Я бы выбросил исключения с кратким сообщением и набрал бы из orderService, если что-то пошло не так. Код будет более элегантным. Также было бы здорово вернуть реальный вновь созданный объект заказа, если все прошло хорошо, но сначала будет достаточно логического значения. (или даже недействительным, учитывая, что вы генерируете исключения).

  • Поймайте исключения в вашем контроллере, зарегистрируйте их, отправьте соответствующий ответ клиенту.

...