GraphQL 是一个用于 API 请求的数据查询语言,它的特点是可以在单个 API 请求中精确地描述需要返回的数据,减少了 API 请求的数量和响应的大小,大大提高了前端工程师的开发效率。GraphQL 不仅是一种查询语言,还是一个规范和一种思想,它的核心理念是面向客户端的 API 设计。同时,GraphQL 还提供了一套完整的错误处理机制,让开发者可以更好地定位和处理错误,提高应用程序的可靠性。
GraphQL Error
GraphQL Error 是一种特殊的错误类型,它可以包含多个错误信息,每个错误信息都包含了发生错误的位置、错误类型和错误描述。GraphQL Error 通常由 GraphQL 服务端返回,当客户端向 GraphQL API 发送请求时,GraphQL 服务端会根据请求参数进行查询、验证和解析,如果出现错误,则会返回 GraphQL Error。
下面是一个查询用户信息的 GraphQL 请求:
query getUser($id: ID!) { user(id: $id) { id name email } }
如果要查询 id 为 100 的用户信息,则可以这样发送请求:
{ "id": "100" }
假设这个请求由 GraphQL 服务端进行查询时出现了错误,则返回的错误信息可能如下所示:
// javascriptcn.com 代码示例 { "errors": [ { "message": "Cannot read property 'name' of undefined", "locations": [ { "line": 3, "column": 5 } ], "path": [ "user", "name" ] } ] }
其中,errors 数组包含了一个 GraphQL Error 对象,该对象包含了 message、locations 和 path 三个属性,它们分别表示错误消息、错误位置和错误路径。clientExtensions、extensions 和 errorType 这三个属性是可选的,它们分别表示客户端扩展、服务端扩展和错误类型。
自定义错误处理
GraphQL 提供了一种灵活的错误处理机制,开发者可以根据自己的需求定义错误处理规则,将错误信息转换为需要的形式。GraphQL 的错误处理机制有两种方式:全局错误处理和局部错误处理。下面分别来介绍这两种方式。
全局错误处理
全局错误处理是指对所有 GraphQL 请求都采用相同的错误处理规则,如将所有错误信息统一封装,返回指定格式的错误消息。全局错误处理可以通过定义中间件来实现,下面是一个 Express 应用程序中的全局错误处理中间件:
// javascriptcn.com 代码示例 app.use((err, req, res, next) => { if (err instanceof GraphQLError) { res.status(500).json({ errors: err.errors.map(error => { return { message: error.message, locations: error.locations, path: error.path, code: undefined }; }) }); } else { next(err); } });
该中间件会将所有发生的 GraphQL Error 转换为类似下面这样的格式:
// javascriptcn.com 代码示例 { "errors": [ { "message": "Cannot read property 'name' of undefined", "locations": [ { "line": 3, "column": 5 } ], "path": [ "user", "name" ], "code": undefined } ] }
其中,code 属性用来自定义错误码,开发者可以根据业务需求定义相应的错误码。
局部错误处理
局部错误处理是指对某个 GraphQL 查询或者字段采用特定的错误处理规则,如对指定的错误信息进行忽略或者替换。局部错误处理可以通过定义错误解析器来实现,下面是一个简单的错误解析器的例子:
// javascriptcn.com 代码示例 const userResolver = { Query: { user: async (root, {id}, context) => { try { const user = await getUserById(id); return user; } catch (err) { throw new UserNotFoundError(err.message, id); } } } }; class UserNotFoundError extends Error { constructor(message, id) { super(message); this.name = 'UserNotFoundError'; this.id = id; } } const errorResolver = { UserNotFoundError: err => { return { message: `User with ID ${err.id} not found.`, locations: err.locations, path: err.path }; } }; const schema = makeExecutableSchema({ typeDefs, resolvers: [userResolver, errorResolver] });
该错误解析器会将 UserNotFoundError 类型的错误转换为类似下面这样的格式:
// javascriptcn.com 代码示例 { "message": "User with ID 100 not found.", "locations": [ { "line": 3, "column": 5 } ], "path": [ "user", "name" ] }
开发者可以根据自己的需求定义任意数量的错误类型和错误解析器,实现精细化的错误处理。
总结
GraphQL 中自定义错误处理可以对错误进行精细化的定位和处理,提高应用程序的可靠性。全局错误处理可以统一封装错误信息,局部错误处理可以对指定错误进行忽略或者替换。开发者可以根据自己的需求定义任意数量的错误类型和错误解析器,实现精细化的错误处理。
示例代码
// javascriptcn.com 代码示例 const { ApolloServer, gql } = require('apollo-server'); const { makeExecutableSchema } = require('graphql-tools'); const typeDefs = gql` type User { id: ID! name: String! email: String! } type Query { user(id: ID!): User! } `; const users = [ { id: '1', name: 'Alice', email: 'alice@example.com' }, { id: '2', name: 'Bob', email: 'bob@example.com' }, { id: '3', name: 'Charlie', email: 'charlie@example.com' } ]; const getUserById = async id => { return users.find(user => user.id === id); }; const userResolver = { Query: { user: async (root, {id}, context) => { try { const user = await getUserById(id); if (user) { return user; } else { throw new UserNotFoundError(`User with ID ${id} not found.`, id); } } catch (err) { throw new UserNotFoundError(err.message, id); } } } }; class UserNotFoundError extends Error { constructor(message, id) { super(message); this.name = 'UserNotFoundError'; this.id = id; } } const errorResolver = { UserNotFoundError: err => { return { message: err.message, locations: err.locations, path: err.path }; } }; const schema = makeExecutableSchema({ typeDefs, resolvers: [userResolver, errorResolver] }); const server = new ApolloServer({ schema, introspection: true, playground: true, formatError: error => { return { message: error.message, locations: error.locations, path: error.path, code: undefined }; } }); server.listen().then(({ url }) => { console.log(`GraphQL server ready at ${url}`); });
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653f389a7d4982a6eb8c02a7