Rails GraphQL API:RSpec测试突变返回Null,GraphiQL却正常(Header问题?)
问题分析与解决方案
从错误信息Cannot return null for non-nullable field CreateSurveyPayload.user可以明确,问题根源是突变执行时无法获取到当前授权用户,导致CreateSurveyPayload的user字段(非空约束)返回null,进而触发整个createSurvey结果为null。结合你描述的"GraphiQL带授权头正常、不带则返回null"的现象,说明测试中的授权流程未正确生效。
排查与修复步骤
1. 修正RSpec测试的请求头格式
Rails在处理测试请求时,会将标准HTTP头转换为HTTP_前缀加下划线的键名。你当前使用的'Authorization'键可能未被正确识别,需改为'HTTP_AUTHORIZATION':
post '/graphql', headers: { 'HTTP_AUTHORIZATION': "Bearer #{token}" }, params: { query: mutation_query }
2. 验证GraphQL上下文的用户解析逻辑
确保你的GraphQLController正确从请求头解析token并将用户注入GraphQL上下文:
# app/controllers/graphql_controller.rb def execute variables = prepare_variables(params[:variables]) query = params[:query] operation_name = params[:operationName] context = { current_user: current_user } result = YourSchema.execute(query, variables: variables, context: context, operation_name: operation_name) render json: result end private def current_user auth_header = request.headers['HTTP_AUTHORIZATION'] || request.headers['Authorization'] return nil unless auth_header token = auth_header.split('Bearer ').last decoded_payload = JWT.decode(token, 'segredo', true, algorithm: 'HS256').first User.find(decoded_payload['user_id']) rescue JWT::DecodeError, ActiveRecord::RecordNotFound nil end
注意:要确保解码token使用的密钥'segredo'与测试中生成token的密钥完全一致,同时处理解码失败或用户不存在的异常,避免上下文注入nil。
3. 检查createSurvey突变的resolve逻辑
确认突变的resolve方法依赖上下文的current_user,并在用户未授权时抛出明确错误:
class Mutations::CreateSurvey < Mutations::BaseMutation field :user, Types::UserType, null: false field :survey, Types::SurveyType, null: true field :questions, [Types::QuestionType], null: true field :errors, [String], null: false argument :input, Types::CreateSurveyInput, required: true def resolve(input:) current_user = context[:current_user] raise GraphQL::ExecutionError, "Unauthorized access" unless current_user # 此处编写创建Survey及关联Question的逻辑 survey = current_user.surveys.create!(title: input[:title], amt_questions: input[:amt_questions]) # ... 创建questions的逻辑 { user: current_user, survey: survey, questions: survey.questions, errors: [] } end end
这里必须保证current_user存在时才执行创建逻辑,否则抛出授权错误,避免因user字段返回null触发非空约束错误。
4. 测试中验证token有效性
在测试中添加token解码验证,确保生成的token能正确解析出用户ID:
token = JWT.encode({ user_id: user.id }, 'segredo', 'HS256') decoded_token = JWT.decode(token, 'segredo', true, algorithm: 'HS256') expect(decoded_token.first['user_id']).to eq(user.id)
额外排查点
- 确认测试环境中JWT gem的版本与开发环境一致,避免解码逻辑差异。
- 检查用户模型是否有
role字段的验证逻辑,确保测试中创建的admin角色用户符合授权要求(如果突变有角色权限限制)。
内容的提问来源于stack exchange,提问作者José Sávio
相关产品推荐
相关产品推荐

