微服务 REST API 设计原则

REST API 设计原则

REST API 的设计很有讲究,我司总结了一些规范和原则,详见 Cisco REST API 规范,编译如下:

REST 方法

    1. GET 方法的响应是由所请求URL代表的资源的表示
    1. GET 方法不会改变请求URL所代表的资源
    1. POST 请求在所请求的URL 路径下创建一个新的资源以作为叶子节点
    1. POST 响应体或者为空(响应状态码为204), 或者是所创建的资源的表示(响应状态码为201)
    1. PUT 请求一个URL, 如果没有相应的资源存在, 就会创建一个相应的新资源
    1. PUT 请求一个URL, 如果已经有相应的资源存在, 就会以请求体中的内容覆盖这个资源
    1. PUT 响应体是所请求的URL代表的资源的表示, 包含了这个请求所作出的修改
    1. DELETE 请求一个URL, 会删除相应的已存在的资源
    1. DELETE 的响应体或者为空(响应码为204) , 或者是资源的表示(响应码为200)
    1. PATCH 请求一个URL, 是部分地修改相应的资源的状态, 参见 RFC6902
    1. PATCH 响应返回所请求的URL代表的资源的表示, 包含了这个请求所作出的修改

URL 路径

    1. URL 路径表示一个资源, 或一组资源的集合
    1. URL 路径的开头形式一般为 /{service}/{apiclass}/v{version}
    1. 集合 URL 的最后一段是一个名词算数, 描述所包含资源的类型
    1. 资源 URL 路径的最后一段的父节点是复数名词,表示资源集合。
    1. 资源 URL 路径的最后一段是其容器内资源的唯一标识符。
    1. URL 路径各段是字母或者数字,遵循驼峰命名法的约定(第一个字符是小写)
    1. URL 路径各段的命名要直观,明确,简洁, 既不拖沓, 又一目了然

URL 查询参数

    1. 表示日期/时间的URL查询参数采用 RFC-3339 的 iso-date-time 格式
    1. 表示持续时间的URL查询参数采用 RFC-3339 的 duration 格式
    1. 表示时间间隔的URL查询参数采用 RFC-3339 的 period 格式
    1. URL查询参数在语义上以及在API中其他位置同名的参数要保持统一
    1. 如果选择所查询资源的特定字段, URL查询参数要符合字段命名和标准规范. 比如: ?fields=subject,body,createTime
    1. 与分页检索有关的URL查询参数符合分页查询形式: ?page=1&size=20&sort=username,asc
    1. URL查询参数名称是字母数字,并遵循驼峰命名法的约定(第一个字符是小写)
    1. URL查询参数名称应该直观,明确,简洁。

Resource Representations 资源表示

    1. 资源的表示通常编码为 application/json, 除非资源为其他标准的多媒体类型, 比如 png, vcard 等等
    1. 资源的集合通常编码为 application/json, 集合以 json 数组形式给出
    1. 如果一个集合支持分页, 那么这个集合的表示应该包括一些标准的分页属性, 比如集合放在 results 数组中, 加上 start(开始), size(页长), total(总数)等属性, 还可以包含一个 _links 对象, 包括 first, prev, next, last, self 这些链接作为属性
    1. 一个资源推荐在资源查询的响应中提供一个 url 属性, 表示这个资源自己的链接
    1. 一个资源不推荐包含另一个服务所拥有和负责的资源, 可以给出一个资源的链接, 使用绝对路径和规范的 URL 形式
    1. 在资源的响应体中一般不包括状态信息, 以免和本身http status code 发生语义上的不一致
    1. 在返回一个 4xx 或 5xx 的 HTTP 响应码时, 响应主体中就包括标准的错误信息, 比如: errorCode, errorReason, errorMessage等

JSON Attributes

    1. 属性名称直观,明确,简洁。
    1. 属性名称是字母数字,遵循camelCase约定(第一个字符是小写)。
    1. 表示日期/时间的属性采用RFC-3339 iso-date-time格式,并具有UTC偏移量。
    1. 表示持续时间的属性采用RFC-3339持续时间格式。
    1. 表示时间间隔的属性采用RFC-3339周期格式。
    1. 表示二进制值的属性使用JSON本机布尔类型进行编码。
    1. 表示数组的属性被命名为复数名词。
    1. 表示非数组的属性被命名为单数名词。
    1. 表示其他资源链接的属性以绝对和规范URL 的形式提供。
    1. 属性名称在各个地方应该在保持统一的语义
    1. 表示枚举类型的属性要具有明确定义的合法值和语义。
    1. 缺少JSON属性与显式赋值为null之间没有语义上的区别。

Security

    1. REST 请求必需使用 OAuth2 之类的协议进行身份验证,授权
    1. REST 请求具有关于访问所需资源的要有明确的授权策略。
    1. 必须验证包含个人身份信息(PII)的REST请求。
    1. REST请求不允许用户之间无意的内容或PII泄漏。
    1. 必须通过安全通道(HTTPS)进行身份验证的 REST 请求。
    1. REST请求不可以在URL中包含身份验证,授权或 PII 信息。

API Documentation

    1. API 文档应该由源代码或注释自动生成, 比如 swagger 之类的
    1. 自动生成的文档应该对于资源和所提供方法提供足够的描述信息
    1. 自动生成的文档应该对于认证,授权策略及调用方法提供足够的描述信息
    1. 自动生成的文档应该对于URL 路径, 调用参数等提供足够的描述信息
    1. 自动生成的文档应该对于表示资源的 JSON 属性提供足够的描述信息
    1. 自动生成的文档应该对于预计的错误触发条件和响应码提供足够的描述信息

API 文档工具

API 文档的生成有很多框架和工具, 现在比较流行的有三种:

1) RESTful API Modeling Language (RAML)

顾名思义, 它是一个RESTful API 的建模语言, 好象UML 类图那样, 通过这个建模语言描述的 raml 文件来定义你的 API 格式, 然后通过工具(raml2html)来生成易读的HTML 文档, 你需要手动编写 raml 文件, 然后生成所需文档.
它已经形成了一套规范和工具, 例如
• API Workbench: 一个功能完善的IDE, 可用来设计, 构建,测试 RESTful API, 和相应文档生成和分享
• RAML Java Client Generator: 一个可以基于 RAML 文档自动生成Java 客户端代码的工具
• RAML2HTML: 一个Node.js 工具, 将 RAML 文件转化成易于阅读的 HTML文档.

例如以如下 raml 来定义API

#%RAML 1.0
title: Hello world # required title
version: 1
baseUri: http://example.com/{version}
documentation:
  - title: Welcome
    content: |
      Welcome to the Example Documentation. The Example API allows you
      to do stuff. See also [example.com](https://www.example.com).
  - title: Chapter two
    content: |
      More content here. Including **bold** text!
/helloworld: # optional resource
  description: This is the top level description for /helloworld.

  get: # HTTP method declaration
    responses: # declare a response
      200: # HTTP status code
        body: # declare content of response
          application/json: # media type
            type: | # structural definition of a response (schema or type)
              {
                "title": "Hello world Response",
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string"
                  }
                }
              }
            example: # example how a response looks like
              {
                "message": "Hello world"
              }
  /test:
    displayName: TEST
    get:
      description: a sub resource

  /{id}:
    uriParameters:
      id:
        type: string
        description: account identifier
        minLength: 1
        maxLength: 10

    get:
      headers:
        Authorization:
          type: string
          description: Basic authentication header
          example: |
            Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    put:
      body:
        application/x-www-form-urlencoded:
          properties:
            name:
              description: name on account
              type: string
              examples:
                example1: Naruto Uzumaki
                example2: Kevin Renskers
            gender:
              enum: ["male", "female"]

然后安装 raml2html

npm i -g raml2html
npm i -g raml2html-markdown-theme

  • 执行
raml2html api.raml > api.html

生成的 API html 文件如下

详情参见 https://github.com/raml2html/raml2html

2) Swagger UI

它是一个更加流行的文档生成框架, 强调从代码中全自动生成 API 文档
这个框架有三个主要的组件:
• Swagger 是它的规范部分, 一套描述 RESTful 服务的规则, 类似于 RAML
• Swagger UI 是它的渲染部分, 它就象 RAML2HTML 那样生成易读的HTML文档, 用户无需用任何客户端就可基于Swagger 规范用它自动生成的客户端进行API测试
• Springfox 是它的生成部分, 通过Java代码, SpringMVC 和 Swagger 的注解来自动生成API 文档.

3) Spring REST Docs

这是 Spring 生态圈, 它基于API 测试来生成 AsciiDoc 文档, 你也可以自己编写一些描述性的 AsciiDoc 文档, 这些 AsciiDoc 文档可以通过它提供的 maven 插件自动生成易读的 HTML 文档, 相比前两者, 它介于手动和全自动之间, 相当于半自动的工具.
如果你是一个新项目, 在设计阶段就可以采用 RAML 来定义你的 API, 如果是老项目, 采用 Swagger 会更省力, 当然 Spring REST Docs 更加符合测试驱动开发的理念, 既可以通过测试来自动生成文档, 也可以手动添加说明, 推荐使用

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式。”但是在要求详细讲述它所提出的各个约束,以及如...
    时待吾阅读 3,339评论 0 19
  • 去年有段时间得空,就把谷歌GAE的API权威指南看了一遍,收获颇丰,特别是在自己几乎独立开发了公司的云数据中心之后...
    骑单车的勋爵阅读 20,127评论 0 41
  • 感恩我有一个安静的学习环境,一切都是那么祥和美好,感恩小巧的紫砂壶,还有壶里那轻柔的玫瑰花水。感恩窗外蓝蓝的天,绿...
    Daisy明阅读 251评论 0 0
  • 你或许是最能直面狗生的小黑了!无论如何都坐的笔直
    李安闻阅读 105评论 0 0
  • 因为改变是痛苦的,所以很多人总想着让别人改变,而自己不想改变。 不想改变的人是自私的,改变确实是痛苦的,但是经历这...
    恬淡罗罗阅读 142评论 0 1