WebAPI规范设计——违RESTful

2020-02-04  本文已影响0人  五维思考

本文首先简单介绍了几种API设计风格(RPC、REST、GraphQL),然后根据实现项目经验提出WebAPI规范设计思路,一些地方明显违反了RESTful风格,供大家参考!

一、几种设计风格介绍

1.1 RPC

这是最常见的方式,RPC说的是本地调用远程的方法,面向的是过程,估计超过50%的API是这种分格的。

1.2 REST

REST架构风格有四个级别的成熟度:

  • 级别 0:定义一个 URI,所有操作是对此 URI 发出的 POST 请求。
  • 级别 1:为各个资源单独创建 URI。
  • 级别 2:使用 HTTP 方法来定义对资源执行的操作。
  • 级别 3:使用超媒体(HATEOAS)。

级别0其实就是类RPC的风格,级别3是真正的REST,大多数号称REST的API在级别2。REST实现一些要点包括:

对于一套设计精良的REST API,其实客户端只要知道可用资源清单,往往就可以轻易根据约定俗成的规范以及导航探索出大部分API。比较讽刺的是,有很多网站给前端和客户端的接口是REST的,爬虫开发者可以轻易探索到所有接口,甚至一些内部接口,毕竟猜一下REST的接口比RPC的接口容易的多。

1.3 GraphQL

如果说RPC面向过程,REST面向资源,那么GraphQL就是面向数据查询了。“GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。”

二、风格选择

三、违RESTful规范设计

3.1 文档系统

无论是独立的wiki还是整合在网关系统中,文档系统都应该支持全局模糊搜索。文档有3种,全局设计规范、API参考手册、文档系统本身的使用指南。其中,参考手册的每个API说明应包括这些信息:

  • URL
  • method
  • 传参方式(URL query、HTTP header、body)
  • 请求与响应的参数表
    • 参数名
    • 类型(string、array、object、int、float、bool)
    • 是否必填,必填时的默认值
    • 说明:中文名称、功能意义、取值范围。至少要能看出对应需求文档或UI稿的哪个东西
  • 可能的错误码与错误信息
  • 示例

3.2 全局规范

URL格式

大小写和连接符的规范应该全局统一:snake_case或者camelCase。一般snake_case会更像普通的web URL。如果使用RESTful,URL格式可以是https://api.example.com/{service_name}/{version}/{api_name}?{filters}https://www.example.com/api/{service_name}/{version}/{api_name}?{filters}
注:Web URL和API URL的规范是不同的。

header

如果不用RESTful,最好也不要把参数放到header里,尽量在HTTP协议框架内实现业务。在此前提下,如果存在(所有接口都需要的)公共参数,可以放在URL query里;或者最方便地使所有接口的method都是POST然后放body里。
JSON格式的Content-Typeapplication/json,如果进行了加密和BASE64转码,则应该是text/plain。如有必要,可进一步指定编码:application/json;charset=utf-8

业务参数 以下讨论的是放在body里的JSON

响应体

较常见的JSON结构是这样的:

{
  "status": 0,
  "message": "",
  "data": {}
}

其中,错误码和错误信息也可以设计一份全局统一的对照表。需要注意的是,这里的status都表示业务情况,跟HTTP的status不要混用。 各级网关都可能以HTTP status表示错误,故它无法明确表示是业务API的问题。简单的例子是,业务API鉴权失败,HTTP也应该返回200 OK而不是返回401。因为接口是正常的,是数据逻辑不正确。

如果不用考虑多语言,message错误信息可以是面向用户的中文语句,由前端/客户端直接toast告知用户。

分页设计

组合请求

为了减少请求数,后端可提供组合请求接口,并且可组合任意接口。假如有3个接口(示例的响应体经简化仅保留data):

/a:请求{"a": "a"}会响应{"data": {"d": "d"}}
/b:请求{"b": "b"}会响应{"data": {"e": "e"}}
/c:请求{"c": "c"}会响应{"data": {"f": "f"}}

增加一个接口/combo可以一次性获取这3个接口的数据:

// 请求
{
  "api": {
    "/a": {"a": "a"},
    "/b": {"b": "b"},
    "/c": {"c": "c"}
  }
}
// 响应
{
  "data": {
    "/a": {"data": {"d": "d"}},
    "/b": {"data": {"e": "e"}},
    "/c": {"data": {"f": "f"}}
  }
}

防攻击

可参考资料

上一篇 下一篇

猜你喜欢

热点阅读