You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GraphQL Express中间件无法传递自定义ValidationError问题

解决graphql-http无法识别自定义ValidationError的问题

1. 修复自定义错误类的原型链

ES6继承Error时,默认原型链存在缺陷,会导致instanceof判断失效,必须手动修正:

class ValidationError extends Error {
  constructor(message, data, code) {
    super(message);
    this.name = 'ValidationError'; // 显式设置错误名称,用于类型识别
    this.data = data;
    this.code = code;
    // 修正原型链,确保instanceof能正确识别当前类实例
    Object.setPrototypeOf(this, ValidationError.prototype);
  }
}

2. 配置graphql-http的错误格式化与响应状态码

在createHandler中,通过formatError识别自定义错误并格式化返回内容,再通过onResponse设置对应的HTTP状态码:

import { createHandler } from 'graphql-http/lib/use/express';
import { schema } from './your-schema';
import { ValidationError } from './your-error-class';

const graphqlHandler = createHandler({
  schema,
  context: async ({ req, res }) => ({ req, res }),
  formatError: (err) => {
    // 检查原始错误是否为自定义ValidationError
    if (err.originalError instanceof ValidationError) {
      return {
        message: err.originalError.message,
        extensions: {
          code: err.originalError.code,
          data: err.originalError.data,
        },
      };
    }
    // 非自定义错误返回默认格式
    return {
      message: '服务器内部错误',
      extensions: {
        code: 'INTERNAL_SERVER_ERROR',
      },
    };
  },
  // 根据错误类型设置HTTP状态码
  onResponse: async ({ res, errors }) => {
    const hasValidationError = errors?.some(
      err => err.extensions?.code === 'VALIDATION_ERROR'
    );
    res.statusCode = hasValidationError ? 400 : errors ? 500 : 200;
  },
});

// 挂载到Express路由
app.use('/graphql', graphqlHandler);

3. 在Resolver中正确抛出自定义错误

验证失败时直接抛出ValidationError实例:

const resolvers = {
  Mutation: {
    createUser: (_, { input }) => {
      if (!input.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.email)) {
        throw new ValidationError(
          '请输入有效的邮箱地址',
          { field: 'email' },
          'VALIDATION_ERROR'
        );
      }
      // 正常创建用户逻辑
      return { id: Date.now(), email: input.email };
    },
  },
};

4. (可选)将错误传递到Express错误中间件

如果需要把自定义错误交给Express的错误中间件处理,可在createHandler的onError回调中手动传递:

const graphqlHandler = createHandler({
  // ...其他配置
  onError: async ({ req, res, error, next }) => {
    if (error instanceof ValidationError) {
      // 调用Express错误中间件
      next(error);
    } else {
      // 其他错误默认返回500
      res.statusCode = 500;
      res.end(JSON.stringify({ error: '服务器内部错误' }));
    }
  },
});

对应的Express错误中间件:

app.use((err, req, res, next) => {
  if (err instanceof ValidationError) {
    return res.status(400).json({
      message: err.message,
      code: err.code,
      data: err.data,
    });
  }
  res.status(500).json({ message: '服务器内部错误' });
});

内容的提问来源于stack exchange,提问作者Mr.Unforgettable

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 01:50:03