Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

REST API 设计之 —— 不要考虑 UI!

  经常有人在设计 API 的时候根据页面 UI 展示的数据形式来设计响应的数据结构。这种做法是非常不好的!也许当时这套 API 用着挺爽,但只要哪天设计师换了个风格,原来的那套 API 就会变得非常难用。而且这时可能 API 已经被别的东西依赖,想改都太迟了。
  以前就遇到过一套历史遗留的 API 完全按照当时的 UI 来设计,当我接过那个项目并开始使用那套 API 时感觉那套 API 的设计简直匪夷所思。虽然没有见过程序早期的 UI,但从那套神奇的 API 中我已经可以在脑子里还原出当时 UI 的大致样子了。当我要使用一个列表时它是一棵树的结构,当我要使用一个树是它是另一种排列方式的树,几乎所有数据都没法直接用。于是前端代码大部分工作都在做数据转换,完全变成一坨。
  之前的文章中已经介绍过了 API 响应数据的类型。一套正常的 API 只应该响应两种类型的数据,要么是列表,要么是非列表。不应该在后端将列表转换成一个树的形式再传到前端,即使这个数据大部分时候都被作为树形渲染。
  当然,非列表类型可能是树型的,但这种情况非常少见的。只有当在数据库中直接存入一个树形的序列化数据时,非列表类型才会出现树形。比如数据库的某个字段存的是 JSON 数据,这个 JSON 数据解析出来就是树形的,那么后端可以解析后作为非列表类型原样传回来。
  无论何时我们都不应该将数据库中本来是表的东西转换成一棵树后再传会给前端。或者最多可以是一个嵌套的表,这是多表关联查询时经常会有的数据结构,但我们还是应该尽可能地将对象扁平化来传输。对于只读 API,对它们的结构设计应该更像是数据库视图的设计,最终结果尽可能地扁平。因为扁平的数据是最容易维护的,而且从扁平的数据转换到其他任何类型的数据都是最容易的。
  下面举个例子 吧,假如有这么两张表
goods
id name category_id
1  xx   1
2  yy   1
3  zz   2

categories
id name
1  AAAA
2  BBBB
  现在的需求是商品需要知道自己的分类名,那么我们可以创建出一个这样的视图 categorized_goods
id name category_id category_name
1  xx   1           AAAA
2  yy   1           AAAA
3  zz   2           BBBB
  于是 API 响应就完全按照这个 [
  { "id": 1, name: "xx", category_id: 1, category_name: "AAAA" },
  { "id": 2, name: "yy", category_id: 1, category_name: "AAAA" },
  { "id": 3, name: "zz", category_id: 2, category_name: "BBBB" }
]
  我觉得这个结果是非常好的(更好的做法是不提供这么个接口,前端分别调分类和商品的接口,这里只是为了说明这个问题而随便找的一个例子)。然而可能此时 UI 的设计是一个分类名作为标题,下面显示一组商品列表。而且开发者可能觉得上面这种形式会造成分类名的重复传输,而改用下面这样的设计。
[
  {
    name: "AAAA",
    id: 1,
    goods: [
      { "id": 1, name: "xx" },
      { "id": 2, name: "yy" }
    ]
  },
  {
    name: "BBBB",
    id: 2,
    goods: [
      { "id": 3, name: "zz" }
    ]
  }
]
  它似乎解决了传输冗余的问题,对于当前的 UI 而言还更容易使用。但我认为这是一个糟糕的设计。首先,传输冗余的问题在 HTTP 开启 GZIP 的情况下根本可以忽略不计。然后它只考虑了当前的 UI 设计易用,只要 UI 一变化就完蛋。
  API 的设计和开发者根本就不用知道 UI 到底长什么样。「设计狮」是一种完全取决于心情来工作的生物,UI 这种东西的变化速度远比底层数据结构的变化速度快得多。所以 API 设计永远不要根据 UI 走,否则将来可能甚至可能有机会看到 DBA 和设计师撕逼的神奇场景。
网名:
34.203.245.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^