DevilKing's blog

冷灯看剑,剑上几分功名?炉香无需计苍生,纵一穿烟逝,万丈云埋,孤阳还照古陵

0%

GraphQL Api

原文链接

针对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:

  • graphQL,更体现domain部分