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部分