在快速功能路线中引发错误

时间:2019-04-28 10:29:36

标签: node.js express functional-programming

我正在尝试使用纯功能路由控制器功能,并且我有一个快速路由控制器:

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

serveBody是一个中间件,它为处理函数提供参数xy,并执行常规的res.json(...)。 要使控制器抛出错误,应该用什么代替WHAT?还是有其他方法在功能代码中引发错误? 我尝试了throw "x should be smaller than 5",但这行不通,而且没有正确执行。

3 个答案:

答案 0 :(得分:1)

  

还是有其他方法在功能代码中引发错误?

丢球错误是一个副作用,因此完全不起作用。但是,express会利用它们使服务器以某些方式做出响应,因此这有点超出您的控制范围。您将必须在某个时候throw ...

我同意“技巧”是编写动态路由处理程序,但我想我会从@eol编写他们的方式中对其进行一些更改

  1. x > 5代码是路径中lambda的一部分,但是错误消息x should be greater than 5是不可配置的。如果lambda更改为x > 6,则错误消息将毫无意义

  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不适合通用,因为它总是查询xy参数,这使我们质疑为什么它是一个单独的函数。您需要定义几条路由来专门读取xy请求参数?

您会这样使用吗?我不知道,感觉像是触手可及-

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`)
})

在所有这些操作的最后,您要求提供一个根本不存在的魔术子弹。至少在您开始想象不平凡的情况时,与您的操作手册中提供的伪代码不同,至少没有。

请在整个程序中共享更多上下文。我认为每个人都可以更有效地为您提供帮助。

答案 1 :(得分:0)

您可以做的是返回例如nullundefined,并在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

答案 2 :(得分:0)

我最终要做的是依靠路由处理程序和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的约定来响应。