可能没有完美的技术。 Graphql也不例外。 如果您没有使用该技术的经验,那么您需要对可能遇到的问题有个很好的了解,并提前进行准备。
首先,我要说的是,我是支持者,而不是在可能的地方使用graphql的对手。 而且,我绝不会说服任何人使用这项技术。 这就是为什么我在graphql技术框架中提出与未解决问题相关的问题的原因。
例如,对于某人来说,graphql中的每个对象至少必须被描述两次可能是意外的:一次作为对象的返回类型,再一次作为对象的输入类型(请参见
graphql.org/graphql-js/mutations-和输入类型 )。 但是,我从一开始就告诉它,甚至不认为这是一个重大缺陷。 今天,我们将重点关注通常在使用graphql技术开发应用程序时必须解决的问题:
- 用户和用户组的访问权限分离。
- 错误处理。
- SELECT N + 1问题
用户和用户组的访问权限分离
graphql对用户和组之间的共享访问一无所知。 因此,共享访问权的所有工作都是应用程序开发人员的责任。 第三个参数将应用程序上下文对象传递给解析器功能。 因此,例如,如果您使用graphql JavaScript + express的实现,则可以在context参数中从请求express.js对象获取当前用户。 但是,应该直接在每个解析器中进行有关访问控制的进一步工作:
function(root, {id}, ctx) { return DB.Lists.get(id) .then( list => { if(list.owner_id && list.owner_id != ctx.userId){ throw new Error("Not authorized to see this list"); } else { return list; } }); }
自然,此方法使访问控制复杂化,因为 无法以声明的方式设置访问权限,并且对权限的控制分散在数十个(对于某些大型系统而言,是数千个)解析器功能中。 因此,有许多库可以解决此问题。 其中一些非常受欢迎(根据github.com上的星数判断),例如
github.com/maticzav/graphql-shield 。
错误处理
如果您的前端需要输入验证,并且需要为尚未通过验证的每个字段生成详细消息,则对您而言,graphql中的错误处理很可能不够灵活。 例如,如果将输入参数描述为字符串,并且接收到数值,则错误消息对此几乎没有用:
{ "errors": [ { "message": "Expected type String, found 1.", "locations": [ { "line": 2, "column": 15 } ] } ] }
如果输入参数的类型存在严重错误,则将自动生成错误消息,并且无法控制此过程。 如果通过输入参数类型的验证成功,则可以通过抛出
new Error ('custom message ...')
对象
new Error ('custom message ...')
将自定义错误消息发送给客户端。 将自定义字段添加到错误对象将不起作用(一起使用时,在apollo-server-express和apollo-errors库中实现了错误自定义)。 当然,总是有机会在服务器上将对象序列化为
message
字符串,然后在客户端上反序列化它。 但是有必要这样做吗?
SELECT N + 1问题
消息中详细讨论了此问题 。
graphql建立在解析器功能上。 这意味着从数据库中获取数据可能会导致称为SELECT N + 1的问题。 假设在解析器功能中获得了一个对象列表,其中与该对象关联的数据由标识符(外键)表示。 对于每个这样的标识符,将调用其自己的函数解析器,在该解析器中(每个)将向数据库发出附加请求。 因此,将执行许多查询,而不是单个数据库查询(使用SQL JOIN),这会使查询超载。
为了解决这个问题,facebook开发了
github.com/graphql/dataloader库,该库使用了挂起的请求策略。 建议不要在函数解析器中直接执行请求,而建议在数组中累积标识符(辅助键),然后立即通过一个请求接收它们。
apapacy@gmail.com
五月13,2019