GraphQL 是一种新型的数据查询语言,它能够使得前端开发人员更加便捷与灵活的进行数据查询。在 GraphQL 中,Schema 设计是非常重要的一项工作,好的 Schema 设计能够让我们更加方便的进行数据查询,而不好的 Schema 设计则会使得查询出现很多冗余,并且会对服务器性能造成很大压力。本文将围绕 GraphQL 的 Schema 设计为主题,介绍一些 Schema 设计的最佳实践。
1. 单一责任原则
在设计 GraphQL Schema 的时候,我们应该遵循单一责任原则,即一个 Query 类型只查询一类数据,一个 Mutation 类型只操作一类数据。这样做的好处是能够将资源隔离,使得 Schema 更加清晰明了。
举个例子,下面是一个查询文章和查询标签的 Schema 设计:
type Query { article(id: ID!): Article articlesByTag(tag: String!): [Article] tag(id: ID!): Tag } type Mutation { createArticle(input: ArticleInput!): Article createTag(input: TagInput!): Tag } type Article { id: ID! title: String! content: String! tags: [Tag]! } type Tag { id: ID! name: String! articles: [Article]! } input ArticleInput { title: String! content: String! tagIds: [ID!]! } input TagInput { name: String! articleIds: [ID!]! }
上面的 Schema 设计中,我们将查询文章和查询标签分别放在了两个 Query 类型中,并为它们指定了不同的名称,这样能够清晰地区分开数据的来源。同时,我们定义了相应的 Mutation 类型用于新增文章和新增标签,而这两个 Mutation 类型的名称和 Query 类型的名称都不一样,这样也是符合单一责任原则的。
2. 嵌套结构
在 GraphQL Schema 设计中,我们经常会遇到嵌套结构的数据,如文章的评论、标签的子标签等等。在这种情况下,我们应该将数据的嵌套结构在 Schema 中展开,这样可以使得查询更加清晰明了。
举个例子,下面是一个包含嵌套结构的 Schema 设计:
type Query { book(id: ID!): Book } type Book { id: ID! name: String! author: Author! chapters: [Chapter]! comments: [Comment]! } type Chapter { id: ID! name: String! content: String! } type Comment { id: ID! content: String! book: Book! } type Author { id: ID! name: String! books: [Book]! }
上面的 Schema 设计中,我们将图书的章节和评论分别放在了 Chapters 和 Comments 类型中,同时也分别定义了相应的类型用于表示章节和评论的详细信息。而在这些数据类型中,我们都通过字段来描述了各个数据之间的关系,比如在 Comment 类型中,我们通过字段 "book" 来描述一条评论所属的图书,这样使得查询数据时更加明确。
3. 输入类型
在开发 GraphQL API 时,我们经常需要从客户端获取数据,然后使用这些数据进行查询或者操作。为了方便从客户端获取数据,我们可以利用输入类型来让客户端更加方便的提交数据。
举个例子,下面我们来看一下 Comment 类型的新增接口:
type Mutation { createComment(input: CommentInput!): Comment } input CommentInput { content: String! bookId: ID! }
在上面的代码中,我们定义了一个新的输入类型 CommentInput,该类型包含了客户端需要提交的数据,这样客户端就可以通过输入这些数据,然后使用 createComment 接口来新增评论了。
4. 抽象类型
在 GraphQL 中,我们可以使用接口(interface)和 Union 类型来定义抽象类型。抽象类型表示一个对象只包含某些共用的字段,而不关心对象的实际类型。
举个例子,下面是一个包含了接口的 Schema 设计:
interface IBlock { id: ID! content: String! } type TextBlock implements IBlock { id: ID! content: String! fontSize: Int! } type ImageBlock implements IBlock { id: ID! content: String! imageUrl: String! } type Query { block(id: ID!): IBlock }
在上面的 Schema 设计中,我们定义了一个接口 IBlock,它包含了共用的字段 "id" 和 "content"。同时,我们还定义了两个类型 TextBlock 和 ImageBlock,这两个类型实现了 IBlock 接口,但又拥有各自特有的字段。在 Query 类型中,我们使用了 IBlock 接口来查询块数据,GraphQL 会根据实际类型的不同,自动选择 TextBlock 或者 ImageBlock 中包含的字段来返回查询结果。
5. 描述枚举
在 GraphQL 中,我们可以使用枚举类型来表示某个字段可能的取值。为了方便对枚举类型进行描述,我们可以使用描述符来为枚举类型添加便于理解的描述信息。
举个例子,下面是一个包含了枚举类型和描述符的 Schema 设计:
enum OrderDirection { ASC DESC } type Query { articles(limit: Int!, offset: Int!, order: OrderDirection!): [Article] }
在上面的 Schema 设计中,我们定义了一个名为 "OrderDirection" 的枚举类型,它包含了两个取值 "ASC" 和 "DESC"。同时,我们在 Query 类型的 "order" 字段上使用了 "OrderDirection" 枚举类型,并为该枚举类型添加了描述信息 "文章排序的方向"。这样,客户端在使用 "order" 查询时,就能够直接使用 "ASC" 或者 "DESC" 来进行查询,而不需要了解后台定义的具体取值范围。
总结
本文主要介绍了 GraphQL Schema 设计的最佳实践,包括单一责任原则、嵌套结构、输入类型、抽象类型、描述枚举等方面。通过学习和使用这些最佳实践,我们可以更加清晰明了地设计和实现 GraphQL API,提高前端开发人员的开发效率和体验。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a3e35dadd4f0e0ffc134e8