map式API开发方法
简介
为什么叫 map 式?
默认情况下API只返回极简的数据结构,最极端的情况,API默认只返回数据ID。
客户端通过传参,向API索取自身所需的其它数据,传参越多,返回数据越多。
随着业务需求的不断变化,API返回的数据越来越丰富,此时API只需要增加支持的传参,每一种参数都代表API能够提供的一类数据。例如
- 参数 name 对应 ID和名称的 map
- 参数 category 对应 ID 和类别的 map
- …
这里引出了命名的由来。
容我大胆地将此类参数命名为 getter。
好处
- 解决API版本兼容问题
- 客户端按需请求数据
- 数据颗粒度更加细化
对比
传统API开发方法
我们有一个API 名为 book-list,用于获取书籍列表,当前版本记为book-list-v1,返回数据格式如下
{
"list": [
{
"book_id": 1,
"book_name": "堂吉诃德",
"author": "塞万提斯"
},
{
"book_id": 2,
"book_name": "人生的智慧",
"author": "叔本华"
}
]
}
随着业务需求变化,我们需要给book-list返回数据增加字段,此时返回的数据格式如下。
可以看到每条记录都增加了字段category。
{
"list": [
{
"book_id": 1,
"book_name": "堂吉诃德",
"author": "塞万提斯",
"category": "novel"
},
{
"book_id": 2,
"book_name": "人生的智慧",
"author": "叔本华",
"category": "psycology"
}
]
}
返回数据相比v1增加了1个字段,所以是向后兼容v1版的。
此时我们不必对API进行版本化处理,继续沿用同一个API。
带来的问题
- 老版本客户端获取到了不需要的数据
需求继续变化,书籍的类别可以有多个,category字段需要是一个数组。此时期望的数据格式如下
{
"list": [
{
"book_id": 1,
"book_name": "堂吉诃德",
"author": "塞万提斯",
"category": ["novel", "classic"]
},
{
"book_id": 2,
"book_name": "人生的智慧",
"author": "叔本华",
"category": ["psycology", "classic"]
}
]
}
因为字段类型变了,API不再向后兼容。
此时为了做到向后兼容,有两种方式
- 版本化API,如新开一个API,名为book-list-v3
- 在v1基础上增加字段。
两种方式各有利弊,这里选用第二种方式:增加字段,此时接口返回
{
"list": [
{
"book_id": 1,
"book_name": "堂吉诃德",
"author": "塞万提斯",
"category": "novel",
"categories": ["novel", "classic"]
},
{
"book_id": 2,
"book_name": "人生的智慧",
"author": "叔本华",
"category": "psycology",
"categories": ["psycology", "classic"]
}
]
}
问题依然存在:老版本客户端获取到了不需要的数据。
map式API开发方法
book-list 默认返回书籍ID
{
"ids": [1,2]
}
如果客户端需要书籍名称,book-list?getters=name 返回
{
"ids": [1,2],
"name": {1: "堂吉诃德", 2: "人生的智慧"}
}
客户端需要更多数据,book-list?getters=name,author,category 返回
{
"ids": [1,2],
"name": {1: "堂吉诃德", 2: "人生的智慧"},
"author": {1: "塞万提斯", 2: "叔本华"},
"category": {1: "novel", 2: "novel"}
}
需求变化,书籍可以有多种类别了,API新增 getter, 名为 categories。
book-list?getters=name,author,categories 返回
{
"ids": [1,2],
"name": {1: "堂吉诃德", 2: "人生的智慧"},
"author": {1: "塞万提斯", 2: "叔本华"},
"categories": {1: ["novel","classic"], 2: ["novel","classic"]}
}
上面的数据格式,相比较book-list-v3,体积约减少40%。客户端按需获取数据,不存在数据冗余。
总结
本文引入了一种新的API开发方法,这种方法受到 graphql 的启发。
API默认只返回极简的数据结构(如数据ID),客户端通过传入getter获取其它数据。
getter对应的数据形式为ID与属性的映射关系(map)。