Appearance
API URI 规范
不要用 RESTful API
RESTful API 只适用于资源型网站,比如 GitHub.com,世上 90% 的网站都不是资源型网站。RESTful API 规范非常理想化,不普适,更不适合中国开发者的快速开发需求,下文有详细解释。
本文讲一个更适合中国国情的、适合快速开发的 API 规范。
Method
4 种 Method
模仿 RESTFul API 规范,严格使用 4 种 Method:
获取:
GET
新增:
POST
修改:
PUT
删除:
DELETE
为何使用 4 种而不是简化为 GET 和 POST
使用 4 种 Method 并不是心智负担,确实有区分的必要,因为:
PUT
和DELETE
要追求幂等性,POST
不追求。这对后端程序员是一个提醒,开发维护时一目了然。新增和修改资源需要传递的内容是不一样的,区分
POST
和PUT
对后端程序员是一个提醒,开发维护时一目了然。DELETE
传参应使用 URL 查询,POST
不是,即使都用POST
,开发的时候照样要区分传参方式,所以干脆区分使用POST
和DELETE
,开发维护时更一目了然。从浏览器
Network
可以直接看到Method
(没有的话需要右击开启),当请求很多时,请求列表会很乱,此时PUT
和DELETE
会被视线第一时间扫到,可以减少心智负担。
复杂业务 API 如何确定使用哪个 Method
有时候查询、新增、修改在一个接口中同时发生,则根据业务性质和幂等性确定使用哪个 Method。
比如 Login 接口会返回 token,虽然它有返回数据,但是因为这个接口主作用是新增登记,所以应使用POST
。
同理,新增一条记录显然使用POST
,然后接口返回新增的记录的id
,你不能说因为它返回了有意义的数据,就说它是GET
,况且,从幂等性来说,一次和多次调用接口的结果是不一样的。
URL
Chrome 的“Network”应显示“Name”、“Path”还是“URL”?
Chrome 浏览器的Network
可以显示Name
、Path
、URL
中的一个或多个,而且,当点击一个请求查看详情时,只会显示其中的一个,所以现在我们需要抉择显示哪一个:
URL
的缺陷在于它太长了,信息冗余,增加心智负担。Path
虽然不长,长度挺恰当,但是缺陷是不带 URL 参数。Name
没有以上问题,它长度恰当,也带 URL 参数,所以应只显示Name
。
接下来的问题就是:如何规范接口 URL,让Name
最清晰、一目了然、减少心智负担。
RESTful API 规范的缺陷
RESTful 规范在Network
的Name
的表现如下,你可以看到 2 个/123
,2 个/user
。
Method | 路径的 RESTful 写法举例 | Name |
---|---|---|
GET | /manage/system/user/123?... | /123?... |
POST | /manage/system/user | /user |
PUT | /manage/system/user | /user |
DELETE | /manage/system/user/123 | /123 |
只显示Name
的话,你会发现一些心智负担:
看不出
123
是什么资源的123
。看不出
/user
是什么操作,只能结合 Method 才能发现是POST
还是PUT
操作。PUT
/user
可能代表多种操作,比如修改基本信息、用户禁言,如果前者只修改一个数据表,后者修改多个数据表,按照中国开发者的习惯,应分成 2 个接口,这时候只用PUT
/user
无法明确表达,需要再结合请求体综合判断。
其他某些劣质规范的缺陷
一些程序员习惯使用GET
/user/list
来获取资源列表,这样的话Name
显示为/list
,因为网站打开时会加载多个list
资源,导致Name
列出现多个/list
,更看不出是什么资源,增加心智负担。
本文规范详情
- 关于接口的路径
👎 REST:路径一律是/api/manage/system/user
,禁止使用动词。
👍 本文:应使用动词
加名词
加修饰词
写法,比如:
获取用户使用
GET
/api/manage/system/user/getUserList
新增用户使用
POST
/api/manage/system/user/addUser
修改用户使用
PUT
/api/manage/system/user/editUser
删除用户使用
DELETE
/api/manage/system/user/delUser?id=123
如果有多种
PUT
操作,可以使用更加明确的动词单词,比如禁言叫/api/manage/system/user/banUser
修饰词举例:获取被封禁的用户使用
GET
/api/manage/system/user/getUserBanned
- 关于接口的参数
👎 REST:参数使用/:id
结构,比如:/api/manage/system/user/123
。
👍 本文:参数应使用 URL 查询的写法:/api/manage/system/user?id=123
。
本文规范优势
现在我们再来对比一下,看看 RESTful 规范和本文规范在浏览器Network
呈现的Name
的区别:
Method | RESTful 写法 | 本文规范写法 |
---|---|---|
GET 查列表 | /system/user/orgId/123 | /system/user/getUserList?orgId=123 |
Name | 👎/123 | 👍/getUserList?orgId=123 |
GET 查 Tree | /system/user/orgId/123 | /system/user/getUserTree?orgId=123 |
Name | 👎/123 | 👍/getUserTree?orgId=123 |
GET 带修饰词 | /system/user/banned | /system/user/getUserBanned |
Name | 👎/banned | 👍/getUserBanned |
GET 查单条 | /system/user/123 | /system/user/getUser?id=123 |
Name | 👎/123 | 👍/getUser?id=123 |
POST | /system/user | /system/user/addUser |
Name | 👎/user | 👍/addUser |
PUT | /system/user | /system/user/editUser |
Name | 👎/user | 👍/editUser |
DELETE | /system/user/123 | /system/user/delUser?id=123 |
Name | 👎/123 | 👍/delUser?id=123 |
接口尽量避免跨域
以当前 API 请求的行业通用惯例来说,一旦跨域,一定是非简单请求,因为简单请求必须符合以下特征:
请求方式只能是:
GET
、POST
、HEAD
(如果打算迁就此特征,可以将PUT
和DELETE
改为POST
)HTTP 请求头限制这几种字段:
Accept
、Accept-Language
、Content-Language
、Content-Type
、Last-Event-ID
(无法迁就,因为一定要有一个其他字段比如Authorization
用于传递 Token)Content-type
只能取:application/x-www-form-urlencoded
、multipart/form-data
、text/plain
(如果打算迁就此特征,行业惯例是使用Content-Type: application/json;charset=UTF-8
,虽然可以改为application/x-www-form-urlencoded
、multipart/form-data
,但更麻烦)
总之,受制于第 2 条,注定无法使用简单请求,而非简单请求会发送预请求,很山寨的感觉。
所以,要么接口尽量避免跨域,要么忍受浏览器发送OPTIONS
请求。