原文链接 
针对collection->product的多对多关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 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 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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. 
1 2 3 4 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: