выбрасывать ошибки в экспресс-функциональных маршрутах - PullRequest
0 голосов
/ 28 апреля 2019

Я пытаюсь работать с чисто функциональными функциями контроллера маршрутов, и у меня есть контроллер экспресс-маршрутизации:

router.get('/', serveJson((x, y) => (x > 5 ? {
  x: x + y
} : WHAT)))

serveBody - это промежуточное ПО, которое предоставляет параметры x и y дляфункция-обработчик и выполняет обычные res.json(...)Что должно быть вместо WHAT, чтобы контроллер выдавал ошибку?Или есть другой способ вызвать ошибки в функциональном коде?Я попытался throw "x should be smaller than 5", но это не работает и не работает правильно.

Ответы [ 3 ]

1 голос
/ 28 апреля 2019

Или есть другой способ вызвать ошибки в функциональном коде?

Ошибки выбрасывания скважин являются побочным эффектом и поэтому полностью не функционируют. Тем не менее, Express использует их, чтобы заставить сервер реагировать определенным образом, так что это немного вне вашего контроля. Вам придется throw в какой-то момент ...

Я согласен, что "хитрость" состоит в том, чтобы написать обработчик динамического маршрута, но я думаю, что я бы немного изменил его по сравнению с тем, как @eol написал их

  1. код x > 5 является частью вашей лямбды в вашем маршруте, но сообщение об ошибке x should be greater than 5 не настраивается. Если лямбда изменится на «1014», сообщение об ошибке не будет иметь смысла

  2. оператор с одной ветвью if является ошибочным и требует undefined для неиспользуемой ветви - это бородавка в коде. Может быть, переместить Error в эту позицию?

Вот как может выглядеть исправленный обработчик -

const serveJson = (cb) => (req, res, next) => {
  const x = Number(req.query.x)
  const y = Number(req.query.y)
  const data = cb(x, y)

  if (data instanceof Error)
    throw data 
  else
    res.json(data)
}

app.get('/test', serveJson((x, y) =>
  x > 5
    ? { x: x + y }
    : Error(`value for x (${x}) cannot exceed 5`)
))

Проблемы остаются. serveJson не является достаточно универсальным, поскольку он всегда запрашивает параметры x и y, что заставляет нас задаться вопросом, почему это вообще отдельная функция. Сколько маршрутов вам потребуется, чтобы определить, что именно для чтения только параметры запроса x и y?

Вы бы использовали это так? Я не знаю, это похоже на досягаемость -

app.get('/add', serveJson((x, y) =>
  x > 5
    ? { result: x + y }
    : Error(`value for x (${x}) cannot exceed 5`)
))

app.get('/mult', serveJson((x, y) =>
  x > 10
    ? { result: x * y }
    : Error(`value for x (${x}) cannot exceed 10`)
))

app.get('/divide', serveJson((x, y) =>
  x !== 0
    ? { result: x / y }
    : Error(`divisor cannot be zero`)
))

У вас действительно будет много мест, где вы можете использовать serveJson, как это? Это кажется маловероятным, но чтобы победить мертвую лошадь, давайте попробуем сделать serveJson более гибким, позволив нам указать параметры, с которыми мы хотим работать. Это все исправит, верно?

const serveJson = (params, cb) => (req, res, next) => {
  const data = cb(...params.map(p => Number(req.query[p])))
  if (data instanceof Error)
    throw data 
  else
    res.json(data)
}

app.get('/test', serveJson(['x', 'y'], (x, y) =>
  x > 5
    ? { result: x + y }
    : Error(`value for x (${x}) cannot exceed 5`)
))

Это будет считаться более функциональным, поскольку все взаимосвязанные части являются настраиваемыми аргументами на сайте вызова serveJson. Но у вас все еще есть огромная проблема - он предполагает, что все параметры являются числами, и пытается их соответствующим образом проанализировать / проверить.

Конечно, вы могли бы продолжать работать над этим и придумать что-нибудь -

app.get('/test/, serveJson({ x: Number, y: Number, z: String }, (x, y, z) =>
  // ...
))

Но обратите внимание, как все внешние спецификации становятся большими. Как будто было бы проще вообще пропустить serveJson. Нет скрытых намерений со 100% гибкостью -

app.get('/test', (req, res, next) => {
  const x = Number (req.params.x)
  const y = Number (req.params.y)
  if (x > 5)
    res.json({ result: x + y })
  else
    throw Error(`value for x (${x}) cannot exceed 5`)
})

В конце всего этого вы попросили волшебную пулю, которая просто не может существовать. По крайней мере, когда вы начинаете представлять нетривиальные случаи, в отличие от псевдокода, предоставленного в вашем OP.

Пожалуйста, расскажите больше о вашей программе. Я думаю, что каждый сможет помочь вам более эффективно.

0 голосов
/ 29 апреля 2019

Я закончил тем, что положился на контракт между обработчиком маршрута и оболочкой serveJson. Я возвращаю объект как это:

{
  body: "X should be greater than 5",
  status: 400
}

serveJson проверяет поле status, если оно равно 400, оно вызывает исключение для промежуточного программного обеспечения для экспресс-обработки.


Обработчик маршрута выглядит следующим образом:

app.get('/test', serveJson((x, y) => (x > 5 ? { body: "1234", status: 200 } : {
  body: "X should be greater than 5",
  status: 400
})));

И serveJson:

const serveJson = (cb) => {
    return function (req, res, next) {
        const result = cb({req.query);
        if (result.status === 400) {
            throw new Error(result.body);
        }
        res.json({ result });
    }
};

Таким образом, обработчик маршрута является чистой функцией, получающей параметры, и в случае ошибки ввода он отвечает контрактом с status: 400.

0 голосов
/ 28 апреля 2019

Что вы можете сделать, это вернуть, например, null или undefined и обработать этот результат в вашем промежуточном программном обеспечении serveJson.Примерно так:

const serveJson = (cb) => {
    return function (req, res, next) {
        // TODO: Validate input
        const x = Number.parseInt(req.query.x);
        const y = Number.parseInt(req.query.y);

        const result = cb(x, y);
        if (typeof res === 'undefined') {
            throw new Error("x should be greater than 5");
        }
        res.json({ result });
    }

};

app.get('/test', serveJson((x, y) => (x > 5 ? { x: x + y } : undefined)));

Если вы сейчас позвоните /test?x=6&y=3, вы получите

{"result":{"x":9}}

Если вы позвоните /test?x=3&y=3, вы получите ошибку:

Error: x should be greater than 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...