title: GraphQL Api date: 2018-12-15 11:51:05 categories: graphQL
tags: [graphQL]
针对collection->product的多对多关系
interface Collection {
id: ID!
memberships: [CollectionMembership!]!
title: String!
imageId: ID
bodyHtml: String
}
type AutomaticCollection implements Collection {
id: ID!
rules: [AutomaticCollectionRule!]!
rulesApplyDisjunctively: Bool!
memberships: [CollectionMembership!]!
title: String!
imageId: ID
bodyHtml: String
}
type ManualCollection implements Collection {
id: ID!
memberships: [CollectionMembership!]!
title: String!
imageId: ID
bodyHtml: String
}
type AutomaticCollectionRule {
column: String!
relation: String!
condition: String!
}
type CollectionMembership {
collectionId: ID!
productId: ID!
}
针对er模型
interface Collection {
Image
[CollectionMembership]
}
type AutomaticCollection implements Collection {
[AutomaticCollectionRule]
Image
[CollectionMembership]
}
type ManualCollection implements Collection {
Image
[CollectionMembership]
}
type AutomaticCollectionRule { }
type CollectionMembership {
Collection
Product
}
Rule #1: Always start with a high-level view of the objects and their relationships before you deal with specific fields.
对于状态进行clean
去掉了collectionMembership部分,替换成为product
Rule #2: Never expose implementation details in your API design.
Rule #3: Design your API around the business domain, not the implementation, user-interface, or legacy APIs.
Most of your major identifiable business objects (e.g. products, collections, etc) should implement Node.
Rule #7: Always check whether list fields should be paginated or not.
针对每一个field去判断其合适的一个展现形式,以及继承方式等,这样在后面的扩展的时候,能够随时添加,游刃有余
Rule #8: Always use object references instead of ID fields.
Rule #9: Choose field names based on what makes sense, not based on the implementation or what the field is called in legacy APIs.
最终版的schema如下:
type Collection implements Node {
id: ID!
ruleSet: CollectionRuleSet
products: ProductConnection!
title: String!
image: Image
description: HTML!
}
type CollectionRuleSet {
rules: [CollectionRule!]!
appliesDisjunctively: Bool!
}
type CollectionRule {
field: CollectionRuleField!
relation: CollectionRuleRelation!
value: String!
}
enum CollectionRuleField {
TAG
TITLE
TYPE
INVENTORY
PRICE
VENDOR
}
enum CollectionRuleRelation {
CONTAINS
ENDS_WITH
EQUALS
GREATER_THAN
LESS_THAN
NOT_CONTAINS
NOT_EQUALS
STARTS_WITH
}
考虑接口部分的问题:
在考虑关系membership部分的时候,考虑的几个点:
- 整个关系是否适合crud
- 对于关联field部分,有一些delta的修改,关系是否需要改变
- 关系是否large或者需要分页
- Is the relationship ordered
- Is the relationship mandatory
- Do both sides have IDs
type Mutation {
collectionDelete(id: ID!)
collectionPublish(collectionId: ID!)
collectionUnpublish(collectionId: ID!)
collectionAddProducts(collectionId: ID!, productIds: [ID!]!)
collectionRemoveProducts(collectionId: ID!, productIds: [ID!])
collectionCreate(title: String!, ruleSet: CollectionRuleSetInput, image: ImageInput, description: HTML!)
}
input CollectionRuleSetInput {
rules: [CollectionRuleInput!]!
appliesDisjunctively: Bool!
}
input CollectionRuleInput {
field: CollectionRuleField!
relation: CollectionRuleRelation!
value: String!
}
Rule #16: When writing separate mutations for relationships, consider whether it would be useful for the mutations to operate on multiple elements at once.
type CollectionUpdatePayload {
userErrors: [UserError!]!
collection: Collection
}
Rule #23: Most payload fields for a mutation should be nullable, unless there is really a value to return in every possible error case. 关于这条的理解,大部分的payload都是nullable
tips:
- graphQL,更体现domain部分