我正在使用模式指令对字段进行授权。 Apollo 服务器在解析器返回后调用指令。因此,指令无权访问输出,因此当授权失败时,如果没有复杂的解决方法抛出错误,无论查询是否请求它们,最终总是返回错误数据,我无法为用户包含相关信息。
我希望有人比我更了解 Apollo 的内部结构,并且可以指出我可以从指令中插入正确信息的位置,这样我就不必破坏 GraphQL 的标准功能。
我尝试将我的输出包含在上下文中,但是尽管指令具有访问权限,但这不起作用,因为数据已经从解析器返回,之后不需要上下文版本。
截至目前,我在指令中使用代码 DIRECTIVE_ERROR 引发自定义错误,并包含我想要返回给用户的消息。在 formatResponse 函数中,我查找指令错误并通过将错误数组传输到数据的内部错误数组来过滤它们。我知道 formatResponse 不是为了修改数据的内容,但据我所知,这是我唯一可以访问所需内容的地方。同样令人沮丧的是响应中的错误对象不包括错误中的所有字段。
type User implements Node {
id: ID!
email: String @requireRole(requires: "error")
}
type UserError implements Error {
path: [String!]!
message: String!
}
type UserPayload implements Payload {
isSuccess: Boolean!
errors: [UserError]
data: User
}
type UserOutput implements Output {
isSuccess: Boolean!
payload: [UserPayload]
}
/**
* All output responses should be of format:
* {
* isSuccess: Boolean
* payload: {
* isSuccess: Boolean
* errors: {
* path: [String]
* message: String
* }
* data: [{Any}]
* }
* }
*/
const formatResponse = response => {
if (response.errors) {
response.errors = response.errors.filter(error => {
// if error is from a directive, extract into errors
if (error.extensions.code === "DIRECTIVE_ERROR") {
const path = error.path;
const resolverKey = path[0];
const payloadIndex = path[2];
// protect from null
if (response.data[resolverKey] == null) {
response.data[resolverKey] = {
isSuccess: false,
payload: [{ isSuccess: false, errors: [], data: null }]
};
} else if (
response.data[resolverKey].payload[payloadIndex].errors == null
) {
response.data[resolverKey].payload[payloadIndex].errors = [];
}
// push error into data errors array
response.data[resolverKey].payload[payloadIndex].errors.push({
path: [path[path.length - 1]],
message: error.message,
__typename: "DirectiveError"
});
} else {
return error;
}
});
if (response.errors.length === 0) {
return { data: response.data };
}
}
return response;
};
我对 Apollo 中操作顺序的理解是:
解析器返回数据
基于查询参数过滤的数据?
在应用的对象/字段上调用指令
基于查询参数过滤的数据?
formatResponse 有机会修改输出
formatError 有机会修改错误
返回给客户
我想要的是不必在指令中抛出错误,以便通过在 formatResponse 中提取信息来创建传递给用户的信息。预期的结果是客户端只接收它请求的字段,但当前方法打破了这一点,并返回数据错误和所有字段,无论客户端是否请求它们。
最佳答案
您可以使用 destruct 注入(inject)它:
const { SchemaDirectiveVisitor } = require("apollo-server-express");
const { defaultFieldResolver } = require("graphql");
const _ = require("lodash");
class AuthDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
const { resolve = defaultFieldResolver } = field;
field.resolve = async function (parent, args, context, info) {
// You could e.g get something from the header
//
// The verification below its necessary because
// my application runs locally and on Serverless
const authorization = _.has(context, "req")
? context.req.headers.authorization
: context.headers.Authorization;
return resolve.apply(this, [
parent,
args,
{
...context,
user: { authorization, name: "", id: "" }
},
info,
]);
};
}
}
然后在您的解析器上,您可以通过
context.user
访问它.
关于error-handling - 如何使用 Apollo Server 2.0 GraphQL 将架构指令中的信息作为返回的数据包含在内?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55410147/