GraphQL 是一种用于 API 的查询语言,它提供了一种更高效、强大和灵活的方式来获取和修改数据。然而,当我们在构建 GraphQL API 的时候,错误处理和日志记录也是非常重要的一部分。本文将介绍如何在 GraphQL 中进行错误处理和日志记录,并提供相关的示例代码和指导意义。
错误处理
在 GraphQL 中,错误处理可以通过定义自定义的错误类型和异常处理器来实现。我们可以使用 GraphQLScalarType 类型来定义自定义的标量类型,并在其中定义错误处理器。例如,下面的代码定义了一个自定义的标量类型 PositiveInt,它表示一个正整数,如果输入的值不是正整数,则会抛出一个自定义的错误类型 PositiveIntError:
// www.javascriptcn.com code example
const {
GraphQLScalarType,
GraphQLError,
Kind,
} = require('graphql');
const PositiveInt = new GraphQLScalarType({
name: 'PositiveInt',
serialize(value) {
if (value < 1) {
throw new GraphQLError('Value must be a positive integer');
}
return value;
},
parseValue(value) {
if (value < 1) {
throw new GraphQLError('Value must be a positive integer');
}
return value;
},
parseLiteral(ast) {
if (ast.kind !== Kind.INT) {
throw new GraphQLError(`Expected type "Int", but got "${ast.kind}"`);
}
const value = parseInt(ast.value, 10);
if (value < 1) {
throw new GraphQLError('Value must be a positive integer');
}
return value;
},
});在上面的代码中,我们重写了 serialize、parseValue 和 parseLiteral 方法,并在其中检查输入的值是否为正整数。当输入的值不是正整数时,我们抛出了一个自定义的 GraphQLError 错误类型,并在其中提供了错误信息。
除了自定义标量类型之外,我们还可以在定义 GraphQL 的 Schema 时使用 GraphQLNonNull 类型来表示必须存在的字段。例如,下面的代码定义了一个必须存在的字段 name:
// www.javascriptcn.com code example
const {
GraphQLNonNull,
GraphQLString,
} = require('graphql');
const UserType = new GraphQLObjectType({
name: 'User',
fields: {
name: { type: new GraphQLNonNull(GraphQLString) },
age: { type: GraphQLInt },
},
});在上面的代码中,我们使用了 GraphQLNonNull 类型来修饰 GraphQLString 类型,表示 name 字段必须存在,否则会抛出一个 GraphQLError 错误类型。
日志记录
在 GraphQL 中,日志记录可以通过定义中间件来实现。我们可以使用 graphql-middleware 模块来定义中间件,并在其中记录请求和响应的数据。例如,下面的代码定义了一个记录请求和响应的中间件:
// www.javascriptcn.com code example
const { applyMiddleware } = require('graphql-middleware');
const loggingMiddleware = async (resolve, root, args, context, info) => {
const start = Date.now();
console.log(`[${start}] Request: ${info.operation.operation} ${info.operation.name.value}`);
const result = await resolve(root, args, context, info);
const end = Date.now();
console.log(`[${end}] Response: ${JSON.stringify(result)}`);
console.log(`[${end}] Time: ${end - start}ms`);
return result;
};
const schemaWithMiddleware = applyMiddleware(schema, loggingMiddleware);在上面的代码中,我们定义了一个名为 loggingMiddleware 的中间件,它接收 resolve、root、args、context 和 info 这些参数,并在其中记录请求和响应的数据。我们使用 Date.now() 方法来记录请求和响应的时间,并使用 JSON.stringify() 方法来将响应的数据转换成字符串。最后,我们返回响应的数据,并在返回之前记录响应的时间。
示例代码
下面是一个完整的示例代码,它演示了如何在 GraphQL 中进行错误处理和日志记录:
// www.javascriptcn.com code example
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLScalarType,
GraphQLNonNull,
GraphQLInt,
GraphQLString,
GraphQLError,
Kind,
} = require('graphql');
const { applyMiddleware } = require('graphql-middleware');
const PositiveInt = new GraphQLScalarType({
name: 'PositiveInt',
serialize(value) {
if (value < 1) {
throw new GraphQLError('Value must be a positive integer');
}
return value;
},
parseValue(value) {
if (value < 1) {
throw new GraphQLError('Value must be a positive integer');
}
return value;
},
parseLiteral(ast) {
if (ast.kind !== Kind.INT) {
throw new GraphQLError(`Expected type "Int", but got "${ast.kind}"`);
}
const value = parseInt(ast.value, 10);
if (value < 1) {
throw new GraphQLError('Value must be a positive integer');
}
return value;
},
});
const UserType = new GraphQLObjectType({
name: 'User',
fields: {
name: { type: new GraphQLNonNull(GraphQLString) },
age: { type: GraphQLInt },
},
});
const QueryType = new GraphQLObjectType({
name: 'Query',
fields: {
user: {
type: UserType,
args: {
name: { type: GraphQLString },
age: { type: PositiveInt },
},
resolve: (root, { name, age }) => {
if (!name) {
throw new GraphQLError('Name is required');
}
const user = { name, age };
console.log(`User: ${JSON.stringify(user)}`);
return user;
},
},
},
});
const schema = new GraphQLSchema({
query: QueryType,
});
const loggingMiddleware = async (resolve, root, args, context, info) => {
const start = Date.now();
console.log(`[${start}] Request: ${info.operation.operation} ${info.operation.name.value}`);
const result = await resolve(root, args, context, info);
const end = Date.now();
console.log(`[${end}] Response: ${JSON.stringify(result)}`);
console.log(`[${end}] Time: ${end - start}ms`);
return result;
};
const schemaWithMiddleware = applyMiddleware(schema, loggingMiddleware);
module.exports = schemaWithMiddleware;在上面的示例代码中,我们定义了一个名为 QueryType 的查询类型,它包含了一个名为 user 的查询字段。我们在其中检查了 name 字段是否存在,并在 age 字段中使用了自定义的标量类型 PositiveInt。如果输入的值不符合要求,我们会抛出一个自定义的 GraphQLError 错误类型。我们还定义了一个名为 loggingMiddleware 的中间件,它用于记录请求和响应的数据。
指导意义
在 GraphQL 中进行错误处理和日志记录是非常重要的,它可以帮助我们及时发现和修复错误,并优化 API 的性能和可用性。在进行错误处理时,我们应该尽可能地使用自定义的错误类型,并在其中提供详细的错误信息,以便开发者能够快速地定位和解决问题。在进行日志记录时,我们应该尽可能地记录请求和响应的数据,并在其中包含有用的信息,例如请求的时间、响应的时间、请求的参数等等。这些信息可以帮助我们更好地了解和优化 API 的性能和可用性。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/67da5ea8a941bf713424f9f7