我正在为新的全栈项目采用GraphQL,我已经研究了许多概念并开始了我的第一个项目。
我的问题与使用声明式和编程式GraphQL模式定义有关。基本上我在GraphQL official site中看到的所有内容都使用声明式方法:您可以在一个或多个文件中定义模式,如(感谢this example here):
type Brand {
name: String
logoUrl: String
}
enum Gender {
MALE
FEMALE
}
type Image {
thumbnailUrl: String
smallUrl: String
mediumUrl: String
largeUrl: String
}
type Article {
id: ID! # non-nullable, is guaranteed to exist on every article
name: String
thumbnailUrl: String
brand: Brand
genders: [Gender]
images: [Image]
recommendations: [Article]
}
type Query {
Article(id: ID!): Article
Articles: [Articles]
}
即使对于某种复杂的数据结构,代码也非常干净简洁。
但是我在网上看到的大多数例子,甚至在我学习过的书上,都使用编程方法来构建模式,比如:
import { GraphQLObjectType, GraphQLInputObjectType } from 'graphql';
import {GraphQLNonNull, GraphQLID, GraphQLList } from 'graphql';
import { GraphQLString, GraphQLInt, GraphQLBoolean } from 'graphql';
import { UserType } from '../User/types';
import UserModel from '../../../models/User';
const fields = {
_id: {
type: new GraphQLNonNull(GraphQLID)
},
name: {
type: GraphQLString
},
phone: {
type: GraphQLString
}
};
const CompanyType = new GraphQLObjectType({
name: 'Company',
description: 'Company',
fields: fields
})
const Company = {
type: CompanyType,
description: 'Get single company',
args: {
id: {
name: 'id',
type: new GraphQLNonNull(GraphQLID)
}
},
resolve(root, params) {
params.deleted = false;
return CompanyModel.find(params).exec();
}
}
const Companies = {
type: new GraphQLList(CompanyType),
description: 'Get all companies',
resolve(root) {
const companies = CompanyModel.find({ deleted: false }).exec();
if (!companies) {
throw new Error('Error getting companies.')
}
return companies;
}
}
export default {
Company,
Companies
}
我的目标是构建一个大型SaaS应用程序,因此模式将变得非常复杂,我担心代码很快就会变得复杂。
那么,我应该选择声明式方法、编程式方法还是两者的混合?
这里的最佳实践是什么?
4条答案
按热度按时间at0kjp5o1#
关于here和here,有很多讨论。
恕我直言,用GraphQL schema语言定义schema的最大优点是可读性。它使schema易于阅读和理解,特别是对于可能查询端点但实际上不参与其设计的内部用户。我认为它也使定义和更改schema更不容易出错。
另一方面,以编程方式定义模式提供了更多的灵活性。例如,如果使用
buildSchema
,则只能为查询和变化传递解析器。如果您对每个类型都可以使用默认解析器,那么这很好-但是当您需要为单个字段定义解析器时会发生什么?以编程方式定义模式允许您为指定的任何类型中的各个字段定义解析程序。(将该
thumbanail_url
转换为thumbnailUrl
字段),但如果这些字段需要额外的数据库查询,则它会阻止它们触发,除非实际请求了该字段,正如文档所指出的,如果您想自动生成模式,这种方法也很有用。就个人而言,这就是我喜欢
graphql-tools
makeExecutableSchema的原因。它是一种中间路线,允许您以非常干净的方式定义类型(使用GraphQL模式语言),同时允许在实现解析器时具有很大的灵活性。bprjcwpo2#
你可以使用
merge-graphql-schemas
库来进行更好的模式设计。这个post演示了如何模块化你的graphql模式,使用这个库并提供一个你可以克隆的种子项目。希望它能有所帮助!:)8i9zcol23#
下面的帖子。
“完全依赖于full-schema文本来创建GraphQL schema有一些缺点。您需要付出一些努力来使代码模块化和清晰,并且您必须依赖编码模式和工具来保持schema-language文本与resolver树(aka resolvers map)一致。这些都是可以解决的问题。
我看到的full-schema方法的最大问题是,代码中失去了一些灵活性。所有类型都必须以依赖于模式语言文本的特定方式编写。需要时不能使用构造函数创建某些类型。您被锁定在这种基于字符串的方法中。尽管模式语言文本使类型更具可读性,但在许多情况下,你需要的是灵活性而不是可读性。
基于对象的方法非常灵活,易于扩展和管理。它不会遇到我刚才提到的任何问题。使用它,您的代码将是模块化的,因为您的schema将是一堆对象。您也不需要合并模块,因为这些对象被设计为像树一样工作。
我在基于对象的方法中看到的唯一问题是,你必须处理更多的代码来管理模块中的重要内容(类型和解析器)。许多开发人员认为这是噪音,我并不责怪他们。
如果你正在创建一个小的,定义良好的GraphQL服务,使用全模式字符串方法可能是可以的。但是,在更大,更敏捷的项目中,我认为更灵活,更强大的基于对象的方法是要走的路。
Source
vc9ivgsu4#
首先,在2023年,随着所有可用于nodejs的工具,我会提倡schema-first而不是code-first。关于code-first的好文档似乎越来越难找到。
第二,Declarative并不意味着schema-first。Graphql本身是一种声明性语言。然而,您的实现不是。您只是使用特定于域的语言来定义类型,并且仍然强制实现解析器。
从理论上讲,您可以创建一个允许声明式模式生成的库,但要实现这一点,它需要非常有主见,不需要编程“如何做”。
最后,模式优先或代码优先都不重要,如果你的代码库太大,以至于你希望你选择一个,这意味着你需要将关注点分成单独的可管理模块或服务。