什么是 GraphQL
GraphQL 是一种已经广泛使用的查询语言,用于构建 API。GraphQL 十分灵活,能够让客户端来决定请求数据的结构和内容,减少了不必要的数据传输和服务器端的开销。
Resolver 的作用
在 GraphQL 中,Resolver 负责查询请求数据,并在服务器上执行逻辑,将结果返回给客户端。它们是组成 GraphQL 查询和类型系统的核心组件。
Resolver 可以从各种来源获取数据,如数据库、REST API、其它 GraphQL 系统等。Resolver 可以定义在类型定义文件中,也可以使用代码中的函数来定义。
通常,Resolver 是将处理请求的 API 逻辑分解为可维护的单元的关键所在。
Resolver 分离的方案
Resolver 的设计非常重要,因为它可以决定构建响应式 API 的质量和可靠性。下面是分离 Resolver 的一些最佳实践:
1. Resolver 的分离
我们建议将 Resolver 抽象为独立的模块。这有助于将前端/客户端和后端/服务器端之间的责任划分清晰,并防止过于紧密的耦合。
下面是一个例子:
// javascriptcn.com 代码示例 // resolvers.js const productResolvers = require('./productResolver'); const orderResolvers = require('./orderResolver'); const resolvers = { Query: { ...productResolvers.Query, ...orderResolvers.Query, }, Mutation: { ...productResolvers.Mutation, ...orderResolvers.Mutation, }, }; module.exports = resolvers;
该代码创建了一个 resolvers
对象,该对象包含从 productResolver
和 orderResolver
模块导入的 Query 和 Mutation Resolver。
你也可以在 Resolver 中使用类似的方法来分离逻辑:
// javascriptcn.com 代码示例 // productResolver.js const productQueries = { products: (_, args) => ProductService.getProducts(args), product: (_, args) => ProductService.getProduct(args), }; const productMutations = { createProduct: (_, args) => ProductService.createProduct(args), updateProduct: (_, args) => ProductService.updateProduct(args), deleteProduct: (_, args) => ProductService.deleteProduct(args), }; module.exports = { Query: productQueries, Mutation: productMutations, };
2. Resolver 的模块化
模块化的 Resolver 使得代码更利于管理,容易维护和测试。每个 Resolver 都应该被定义在一个单独的文件中,并且文件命名应该能够体现 Resolver 的作用。
下面是一个 Resolver 模块的例子:
// javascriptcn.com 代码示例 const { AuthenticationError, UserInputError } = require('apollo-server-express'); const Product = require('../models/Product'); const checkAuth = require('../utils/checkAuth'); module.exports = { Query: { async getProduct(_, { productId }) { try { const product = await Product.findById(productId); if (product) { return product; } else { throw new Error('Product not found'); } } catch (err) { throw new Error(err); } } }, Mutation: { async createProduct(_, { name, description, price }, context) { const user = checkAuth(context); if (user.isAdmin) { const newProduct = new Product({ name, description, price, }); const product = await newProduct.save(); return product; } else { throw new AuthenticationError('Unauthorized for this action'); } }, }, };
3. Resolver 的测试
单独测试 Resolver 是非常重要的,这不仅帮助我们保证 Resolver 的正确性,也提供了一个在代码修改时不会破坏功能的方式。
测试可以与 Resolver 一起创建并在单独的文件中执行。只需要编写测试用例,引入 Resolver 和需要进行的断言即可。
下面是一个例子:
// javascriptcn.com 代码示例 const { ApolloServer } = require('apollo-server-express'); const resolvers = require('./resolvers'); const typeDefs = require('./typeDefs'); const mongoose = require('mongoose'); const { MongoMemoryServer } = require('mongodb-memory-server'); const mongod = new MongoMemoryServer(); beforeAll(async () => { const uri = await mongod.getConnectionString(); await mongoose.connect(uri, { useNewUrlParser: true }); }); afterAll(async () => { await mongoose.disconnect(); await mongod.stop(); }); describe('Resolvers', () => { let server: any; beforeAll(() => { server = new ApolloServer({ typeDefs, resolvers }); }); it('returns a product by ID', async () => { const result = await server.executeOperation({ query: ` query GetProduct($productId: ID!) { getProduct(productId: $productId) { id name description price } } `, variables: { productId: 1 }, }); expect(result.errors).toBeUndefined(); expect(result.data.getProduct.id).toBe(1); }); afterAll(async () => { await server.stop(); }); });
总结
Resolver 是构建 GraphQL API 中不可或缺的组成部分。按照最佳实践来进行 Resolver 设计和分离可以帮助我们更好地管理代码、减少混乱、使得代码更利于维护和测试。
通过实践、探索和实现,在我们的项目中使用本文所介绍的 Resolver 设计和分离方案,以提供更高质量和可靠性的 API。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653da7c77d4982a6eb7658c6