GraphQL 错误处理:如何检测错误和故障

GraphQL 是一个强大的查询语言,但是在大型应用中,错误处理成为一个非常重要的问题。在 GraphQL 中,错误处理不仅仅是对于错误的检查和提醒,还包括如何准确地识别错误和故障,并提供恰当的解决方案。

本文将向你展示如何全面地考虑 GraphQL 错误处理,以及如何在前端中有效地解决这些问题。

检测错误

如果你只关注你的应用程序或 API 是否能正确地解决 GraphQL 查询,则可能会错过一些重要问题。举例来说,以下查询本身是有效的:

{
  user(id: "123") {
    name
    age
  }
}

但是如果我们使用了不存在的 ID(例如“ user(id:“456”)”),这个查询就会失败。这意味着我们需要更多的错误检查过程,以支持更可靠的 Graphql 服务。

1. 使用静态检查器/检查 (Static checkers/linters)

静态检查器(也称为 linter 或代码风格检查器)可帮助我们快速找到代码中可能的错误和潜在的问题。在 GraphQL 中,我们可以使用像 eslint-plugin-graphql 这样的工具来检测和警告我们可能的错误和问题。例如,它可以通过NoUndefinedVariables规则来检查是否有缺少变量声明的响应。

// .eslintrc.js
module.exports = {
  plugins: ['graphql'],
  rules: {
    'graphql/template-strings': [
      'error',
      {
        // Import default settings for your GraphQL client. Supported values:
        // 'apollo', 'relay', 'lokka', 'literal'
        env: 'apollo',

        // Import your schema JSON here
        schemaJson: require('./schema.json'),

        // OR provide absolute path to your schema JSON (but not if using `eslint --cache`!)
        // schemaJsonFilepath: path.resolve(__dirname, './schema.json'),

        // Name of the imported namespace
        tagName: 'gql',

        // Regex for validating the tag name
        // Any tag matching this regex is processed as a GraphQL query
        // but only if a valid schema is available.
        // If this is not defined, any tag starting with "gql" is considered a query
        // if a valid schema is available.
        tagRegExp: '^relay|gql$',

        // Import your GraphQL operations from source files
        // NOTE: globbing does not work on Windows!
        // operations: {
        //   '*': ['./src/**/*.{ts,tsx,js,jsx}'],
        // },
      },
    ],
  },
};
2. 使用测试集 (Test sets)

另一种检测错误的方法是创建测试来检查 GraphQL 查询的正确响应。建立一个集合,以测试我们的查询是否正确,是否得到了所期望的响应,并且是否有问题。

// test.js
import { graphql } from 'graphql';
import { schema } from './schema';

test('user query', async () => {
  const result = await graphql(
    schema,
    `{
      user(id: "123") {
        name
        age
      } 
    }`,
  );

  expect(result).toMatchSnapshot();
});

在这个测试中,我们使用了 expect 来比较我们的查询结果和我们期望的结果以进行测试。

错误解决技巧

即使我们已经检测和预测了错误和故障,但是我们仍然不能避免它们发生。 GraphQL 已经提供了一些错误处理功能,例如 GraphQL 中间件,但是在前端中,我们还需要处理这些错误的导致和对策。

下面是一些对于错误处理应该采用的技术:

1. 报错 (Logging)

记录错误是一种在生产环境中快速发现和诊断故障的好方法。如果我们启用日志,那么就可以在错误发生时捕获关键数据,例如错误消息、堆栈跟踪、请求参数等等,这些都可以成为后来定位故障的线索。

// logging middleware
app.use((err, req, res, next) => {
  if (err) {
    console.error(err);
    res.status(500).send('Internal server error.');
  }
  next();
});
2. 纠错/发现/恢复/通知

在良好的错误处理中,我们要先尝试进行自动故障修复,以减少对于真正处理错误的人员的负担。如果自动纠错失败了,则应该通知用户已发送一份错误报告并且尽快修复故障。

3. 全面优化

在某些情况下,错误处理可以是我们应用程序的"性命攸关"。在这种情况下,我们应该考虑使用错误监控和优化技术来确保错误的及时检测和修复,以避免用户抱怨程序并且减少维修工作量。

总结

GraphQL 的错误处理解决方案是比较简单的,但是始终在应用程序中使用正确的工具和技术来处理 GraphQL 查询的结果和错误非常重要。本文阐述了关于 GraphQL 错误处理以及在前端中如何解决这些问题的实践方法。

虽然没有一种简单的解决方案可以覆盖所有的 GraphQL 查询错误和故障,但是如果我们正确地使用正确的工具和技术,我们可以减少错误和故障,并确保我们应用程序的可靠性。

示例代码

下面是实例代码,展示如何使用 GraphQL 错误处理:

// schema.js
import { gql } from 'apollo-server';

const typeDefs = gql`
  type Query {
    user(id: ID): User
  }
  type User {
    id: ID!
    name: String
    age: Int
  }
`;

const users = [
  {
    id: '1',
    name: 'Fred',
    age: 25,
  },
  {
    id: '2',
    name: 'Jane',
    age: 32,
  },
  {
    id: '3',
    name: 'Bob',
    age: null,
  },
];

const resolvers = {
  Query: {
    user: (parent, args, context, info) => {
      const { id } = args;
      const user = users.find(user => user.id === id);
      if (user === undefined) {
        return {
          error: 'User not found',
        };
      }
      if (user.age === null) {
        return {
          error: 'Age is not defined',
        };
      }
      return user;
    },
  },
};

export const schema = makeExecutableSchema({
  typeDefs,
  resolvers,
});
// index.js
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { schema } from './schema';
import { createServer } from 'http';
import * as sentry from '@sentry/node';

sentry.init({
  dsn: 'https://<your-dsn>.sentry.io/123',
});

const app = express();
const server = new ApolloServer({
  schema,
  tracing: true,
  introspection: true,
  playground: true,
  plugins: [
    {
      requestDidStart(requestContext) {
        return {
          didEncounterErrors(ctx) {
            sentry.captureException({ requestContext });
          },
        };
      },
    },
  ],
});

app.use(sentry.Handlers.requestHandler());
app.use(sentry.Handlers.errorHandler());

server.applyMiddleware({ app });
const httpServer = createServer(app);
httpServer.listen({ port: 4000 }, () => {
  console.log(`GraphQL API ready at http://localhost:4000${server.graphqlPath}`);
});

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a0ee54add4f0e0ff91bc80


纠错反馈