GraphQL:field.resolve() 结果在指令内未定义
Posted
技术标签:
【中文标题】GraphQL:field.resolve() 结果在指令内未定义【英文标题】:GraphQL: field.resolve() result is undefined inside directive 【发布时间】:2020-06-02 17:46:39 【问题描述】:我一直在关注我在 Google 上找到的关于如何制作 AuthDirective 的所有结果,但我无法让它发挥作用。
我会留下所有文件,看看我是否在实现时出错,但我猜不是因为即使在 field.resolve 中没有任何条件的情况下我也进行了测试。
我发现的一个特别的东西是 field.resolve,带有 4 个参数,其中第一个总是未定义的,不确定是否可以,但只是作为一个额外的提示。
代码如下:
这是我的 typedef 的一部分
directive @isAuthenticated on FIELD_DEFINITION
scalar Date
type User
id: ID,
name: String
email: String
password: String
createdAt: Date
type Token
token: String
# IF I REMOVE @isAuthenticated this works!
type Query
user(name: String): User! @isAuthenticated
users: [User!]! @isAuthenticated
type Mutation
createUser(name: String, email: String, password: String): Boolean!
login(email: String!, password: String!): Token!
这是我的架构:
import path from 'path';
import makeExecutableSchema from 'graphql-tools';
import fileLoader, mergeResolvers, mergeTypes from 'merge-graphql-schemas';
import schemaDirectives from './Directives';
const typedefsArray = fileLoader(path.join(__dirname, './**/*.graphql'));
const resolversArray = fileLoader(path.join(__dirname, './**/*.resolvers.ts'));
const typeDefs = mergeTypes(typedefsArray);
const resolvers = mergeResolvers(resolversArray);
const schema = makeExecutableSchema( typeDefs, resolvers, schemaDirectives );
export default schema;
这是我的 AuthDirective
import defaultFieldResolver from 'graphql';
import AuthenticationError, SchemaDirectiveVisitor from 'apollo-server-express';
class AuthDirective extends SchemaDirectiveVisitor
visitFieldDefinition(field: any)
const resolver = defaultFieldResolver = field;
field.resolve = async function (...args: any)
const [_, __, context] = args;
const req = context;
const accessToken = req.headers.authorization
? req.headers.authorization.replace('Bearer ', '')
: null;
if (accessToken)
// here I was doing jwt.verify(accessToken) but I removed it for now to simplify
const result = await resolver.apply(this, args);
return result; // <--- THIS IS ALWAYS UNDEFINED
else
throw new AuthenticationError('Unauthorized field');
;
export default AuthDirective;
位于 ./Directives 下,并从索引中导出为:
import AuthDirective from './auth';
export default
isAuthenticated: AuthDirective
最后是我的用户解析器。就像我之前说的,如果我从用户 graphql 查询中删除指令,它应该会正常工作:
import jwt from 'jsonwebtoken';
import AuthenticationError, UserInputError from 'apollo-server-express';
import IUser from './IUser';
import UserModel from './user.schema';
import Config from '../../config';
const APP_SECRET = Config;
const createToken = async (user: IUser, secret: string, expiresIn: string) =>
const id, email, name = user;
return jwt.sign( id, email, name , secret, expiresIn );
;
const userResolvers =
Query:
user: (_: any, name : name: string ) => UserModel.findOne( name ).exec(),
users: () => UserModel.find().exec()
,
Mutation:
createUser: async (_: any, args: IUser) =>
await new UserModel(args).save();
return true;
,
login: async (_: any, email, password : IUser) =>
const user = await UserModel.findOne( email ).exec();
if (!user)
throw new UserInputError('No user found with this login credentials.');
const isValid = await user.validatePassword(password);
if (!isValid)
throw new AuthenticationError('Invalid password.');
return token: createToken(user, APP_SECRET, '30m') ;
;
export default userResolvers;
和我的服务器:
import morgan from 'morgan';
import express from 'express';
import bodyParser from 'body-parser';
import compression from 'compression';
import depthLimit from 'graphql-depth-limit';
import ApolloServer from 'apollo-server-express';
import Config, DBConfig from './config';
import schema from './domain';
const PORT = Config;
const app = express();
const apolloServer = new ApolloServer(
schema,
validationRules: [depthLimit(7)],
context: ( req, res : any) => ( req, res )
);
app.use(express.json());
app.use(compression());
app.use(morgan('combined'));
app.use(bodyParser.urlencoded( extended: true ));
apolloServer.applyMiddleware( app );
DBConfig.init();
app.listen(PORT, () => console.log(`Server running on port $PORT`));
【问题讨论】:
【参考方案1】:field
上没有 resolver
属性,所以这个
const resolver = defaultFieldResolver = field;
将始终导致resolver
具有defaultFieldResolver
的值。如果您在具有自定义解析器的某个字段上使用该指令,则永远不会调用该自定义解析器 - 仅使用默认行为,它确实可以返回 undefined
。
您需要确保使用正确的属性:
const resolve = defaultFieldResolver = field;
或者你可以在解构field
时重命名结果变量:
const resolve: resolver = defaultFieldResolver = field;
【讨论】:
我的天啊,我觉得自己很愚蠢,测试了除此之外的所有内容!感谢您的快速回复以上是关于GraphQL:field.resolve() 结果在指令内未定义的主要内容,如果未能解决你的问题,请参考以下文章
当我的 GraphQL 架构在运行时由 postgraphile(在其自己的容器中)自动生成时,如何将中继编译器作为离线构建步骤运行?
GraphQl 和 insomnia 桌面客户端无法使用 graphql.org/swapi-graphql