Rest API 设计最佳实践(2)

原创 2016年05月31日 01:10:06

Base URL

  1. 那么应该选择哪URL呢?
    http(s)://api.foo.com VS http(s)://www.foo.com/dev/service/api/rest
    选择的原则是:简单,方便。所以可以得话还是选第一种

  2. Rest Client 和 Browser 访问 http(s)://api.foo.com, 各应该返回什么结果?
    原则是保持返回结果一致:这样会方便开发者debug 和了解 API,因为这样可以让开发者无论使用什么工具都可以方便的得到相同的反馈。

  3. 版本号 两种方法可选:
    URL方式
    http(s)://api.example.com/v1
    或者
    Media-Type
    application/json+foo;application&v=1
    该选择哪种方式呢?
    URL方式看起来简洁易懂,问题是如果版本号变更很频繁,对于调用API的开发者而言将会很痛苦。所以但采用这种方式时,没有大的变更不要频繁的变更版本号,尽量保持版本号为整型(int), 不要使用像 2.3、1.2.2 之类的小版本号。
    Media-Type 可以让开发者在http请求头Acccept中指定的想要访问API的版本号:
    Accept: application/json+foo;application&v=1
    Server 可以通过检查这个请求头再确定版本号。这种方式的缺点是,要花很多时间去设计,实现和支持 Media-Type。(这中也是最符合http标准的方式)
    总结:这两种方式都可以,但是开发者倾向于URL方式,因为 。。。 简单

camelCase?

JSON 是JavaScript object notation 的简称,也就是说 JSON 是JavaScript 原生的格式。 JavaScript的规范中要求使用驼峰式(camelCase), 那我们最好也要遵守这个规范, 保持命名的一致性。
JavaScript 中的方法是遵守规范的:

myArray.forEach
而不是 myArray.for_each

所以我们最好写成 account.givenName ,而不是这样account.given_name

怎么表示 Date/Time/Timestamp

这个已经有标准,那就是 ISO 8601
例子:
{
…,
“createdTimeStamp”:”2012-07-10T18:02:24.343z”
}

在JSON中使用HREF

  • 实现分布式超媒体十分重要(我理解超媒体的意思跟超文本差不多,可以链接到其他Media Type)
  • 每一个可访问的资源都应该有一个独有URL.
  • 用HREF取代ID表示唯一资源方式
    {
    “href”:https://api.example.com/v1/accounts/1234
    }
    在返回的JSON中加入href属性来表示说访问资源的位置,当然可以添加相关资源的href,这样就实现的资源之间的链接,也就是上面提到的超媒体(HyperMeida)。

响应体(Response Body)应该返回什么?

对Get来说这很明显,返回请求内容即可。
对于POST来说,是返回最新更新或者创建的资源的内容吗?
如果用POST更新的某个资源,而客户端也需要使用这个资源来更新到最新数据或更新缓存,那这种合理的情况下应该返回更新的资源。
但是也会有返回资源不合理的情况,如:上传文件,客户端就没有必要再获得从服务器返回的上传文件。另一种情况是有访问数据量的限制,每次都返回肯定会消耗数据量配额。
解决方式:可以在请求的链接后跟上类似(?_body=false),需要返回响应体时指定__body=true, 不需要时指定_body=false

响应体内容格式

  1. Accept Header :
    通过请求头可以指定返回的数据类型,格式为:

    GET /applications/a1b2c3
    Accept: application/json, text/plain //从左到右,优先级依次降低

    这是传统的方式,还有另外一种方式,对用户很友好
  2. 资源后缀:

    /applications/a1b2c3.json
    /applications/a1b2c3.csv

    可以用这种方来覆盖上边传统的方式,也就是同时支持上面提到的两种方式,如果用户在url通过 .json 或 .csv 指定了格式,那就采用url指定的方式

  3. 资源引用
    这个对Rest API 的拓展性很重要

    • 单个实体

      GET /accounts/x7y8z9
      200 ok
      {
      "href": "https://api.example.com/v1/accounts/x7y8z9",
      "givenName": "Tony",
      "surname": "Stark",
      ...,
      "directory": {
      "href":"https://api.stormpath/v1/directories/g4b5i6'
      }
      }

      这样当请求某个account是,会得到与这个account相关的 directory的url, 通过这个url,就可以访问这个directory
      那么怎么,一次请求返回 account 和directory的信息,而不是只返回directory的url,可以在url后边加上?expand=true,如下:

      GET /accounts/x7y8z9?expand=true
      200 ok
      {
      "href": "https://api.example.com/v1/accounts/x7y8z9",
      "givenName": "Tony",
      "surname": "Stark",
      ...,
      "directory": {
      "href":"https://api.stormpath/v1/directories/g4b5i6' ,
      "name":"Avengera",
      "creationDate":...
      }
      }

      如果只想要一部分的结果呢?可以通过添加fields 字段来指定想要返回的字段,如下
      `
      GET /accounts/x7y8z97? fields=givenName,surname,directory(name)
      ·
    • 集合
      怎么做分页呢?可以添加offset和limit作为参数,如下:
      /applications?offset=50&limit=25
      这种方式的缺点在于还需要用户来指定查询相关的关键字想offset和limit,下面这种方式 是通过资源应用的思想,如下
      GET /accounts/x7y8z9/groups
      ·
      200 OK
      {
      "meta":{}
      "offset":0,
      "limit": 25,
      "first": {"meta":".../accounts/x7y8z9/groups?offset=0"},
      "previouse":null,
      "last": {"meta":".../accounts/x7y8z9/groups?offset=25"},
      "items": {
      {
      "meta":{"href":"..."}
      },
      {
      "meta":{"href":"..."}
      }
      }
      }

      这种方式通过资源链接的方式,可以很方便的获取想过相关的资源的访问url,想第一个资源,最后一个资源等等。

      怎么处理many to many的情况?

      • 一个group可以有多个account
      • 每个account可能在多个group里
      • account和group的mapping(GroupMembership)也看作是资源

      通过访问 GroupMembership 来获得account和group的信息

      GET /groupMemberships/2143214
      200 OK
      {
      "href": "/groupMemberships/2143214",
      "account": {"href":""},
      "group": {"href":""}
      }

      通过account获得其他信息,如下

      GET /accounts/x7y8z9
      200 OK
      {
      "href": ".../accounts/x7y8z9",
      "givenName":"Tony",
      "gorups": {"href":".../accounts/x7y8z9/groups"},
      "groupMemberships": {"href":".../groupMemberships/accountId=x7y8z9"}
      }

      这里既返回了groups的信息,又返回了groupMemberships的信息,这样可以给用户更多的选择。

相关文章推荐

Rest API 设计最佳实践(3)

错误处理通过http 中的状态码来表示不同的错误,如下POST /directories 409 Conflict { "status": 409, "code": 40924, ...

编写 Node.js Rest API 的 10 个最佳实践

全文共 6953 字,读完需 8 分钟,速读需 2 分钟。翻译自:RingStack 的文章 10 Best Practices for Writing Node.js REST APIs | @...

REST与RESTFul API最佳实践

我经常会面试一些做PHP的开发者,让我很奇怪的是,10个人总有8个多不知道什么是REST服务,甚至是没有听说过。但RESTFul API已经是现在互联网里对外开放接口的主流模式,可参考: 豆瓣A...

移动App的REST API设计实践

通讯协议 一些只是对服务器数据进行CRUD操作的App,通常采用HTTP协议,为了安全也可以采用HTTPS协议。IM软件可以选择使用XMPP协议。 其他一些特有场景的App可能基于Sock...

API设计的十大最差和五大最佳实践

作者张红月 目前ProgrammableWeb上收录的API数已过8000,这也说明API的火热趋势锐不可当。在2012年,CSDN就做过许多关于API已越来越热的报道,如API趋势...

RESTful API 设计最佳实践(7)

RESTful API 设计最佳实践(7)本篇博客将侧重介绍在RESTful API设计中,消息头HEADER和消息体body相关的东西。URL只是RESTful API设计的主要一部分,要实现RES...

RESTful API 设计最佳实践

背景 目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API格式如何?你的AP...

[转]RESTful API 设计最佳实践

 作者 BRUCE-ACCUMULATE 摘要:目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个”万能...

【转载】RESTful API 设计最佳实践

英文原文:http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api 转载原文:http://www.oschina...

RESTful API 设计最佳实践

背景 目前互联网上充斥着大量的关于RESTful API(为方便,下文中“RESTful API ”简写为“API”)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API 格式如何...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Rest API 设计最佳实践(2)
举报原因:
原因补充:

(最多只允许输入30个字)