网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备......)。

因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致API构架的流行,甚至出现"API First"的设计思想。RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。我以前写过一篇《理解RESTful架构》,探讨如何理解这个概念。

今天,我将介绍RESTful API的设计细节,探讨如何设计一套合理、好用的API。我的主要参考资料是这篇《Principles of good RESTful API Design》

一、协议

API与用户的通信协议,总是使用HTTPs协议

二、域名

应该尽量将API部署在专用域名之下。


https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。


https://example.org/api/

三、版本(Versioning)

应该将API的版本号放入URL。


https://api.example.com/v1/

另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。

四、路径(Endpoint)

路径又称"终点"(endpoint),表示API的具体网址。

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。

举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

  • https://api.example.com/v1/zoos
  • https://api.example.com/v1/animals
  • https://api.example.com/v1/employees

五、HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个(括号里是对应的SQL命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

还有两个不常用的HTTP动词。

  • HEAD:获取资源的元数据。
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

下面是一些例子。

  • GET /zoos:列出所有动物园
  • POST /zoos:新建一个动物园
  • GET /zoos/ID:获取某个指定动物园的信息
  • PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
  • PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
  • DELETE /zoos/ID:删除某个动物园
  • GET /zoos/ID/animals:列出某个指定动物园的所有动物
  • DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

六、过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数。

  • ?limit=10:指定返回记录的数量
  • ?offset=10:指定返回记录的开始位置。
  • ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
  • ?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

七、状态码(Status Codes)

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。

  • 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
  • 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
  • 204 NO CONTENT - [DELETE]:用户删除数据成功。
  • 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。。
  • 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
  • 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

状态码的完全列表参见这里

八、错误处理(Error handling)

如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。


{
error: "Invalid API key"
}

九、返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

  • GET /collection:返回资源对象的列表(数组)
  • GET /collection/resource:返回单个资源对象
  • POST /collection:返回新生成的资源对象
  • PUT /collection/resource:返回完整的资源对象
  • PATCH /collection/resource:返回完整的资源对象
  • DELETE /collection/resource:返回一个空文档

十、Hypermedia API

RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。


{"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}}

上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系 (collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。

Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。


{
"current_user_url": "https://api.github.com/user",
"authorizations_url": "https://api.github.com/authorizations",
// ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。


{
"message": "Requires authentication",
"documentation_url": "https://developer.github.com/v3"
}

上面代码表示,服务器给出了提示信息,以及文档的网址。

十一、其他

(1)API的身份认证应该使用OAuth 2.0框架。

(2)服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

REST API初识及设计的更多相关文章

  1. Atitit.提升 升级类库框架后的api代码兼容性设计指南

    Atitit.提升 升级类库框架后的api代码兼容性设计指南 1. 增加api直接增加,版本号在注释上面增加1 2. 废弃api,使用主见@dep1 3. 修改api,1 4. 修改依赖import, ...

  2. 高性能PHP框架thinkphp5.0.0 Beta发布-为API开发而设计

    ThinkPHP V5.——为API开发而设计的高性能框架 ThinkPHP5..0版本是一个颠覆和重构版本,采用全新的架构思想,引入了很多的PHP新特性,优化了核心,减少了依赖,实现了真正的惰性加载 ...

  3. 访问API安全性认证设计

    1.用户POST登录(账号+密码) | |成功 |2.返回(Private key+时间戳)加密字符串+用户信息+缓存到内存中 | |发起其它请求 |3.发起请求时携带Request参数和(Reque ...

  4. 设计一个较好的框架的难点之一--API兼容性的设计

    设计一个好的框架和设计一个好的软件一样,需要考虑的方面很多,比如扩展性.性能.用户体验.稳健性等等,视不同的场景,每个点都可能导致成败,但他们通常并不是老板们关心的,因为在大部分情况下,他们通常都没有 ...

  5. Atitit.api参数传递的设计

    Atitit.api参数传递的设计 · 引言 · 形参和实参 · 命名实参 · 可选参数 · params,数目可变参数 · 方法解析与重载决策 · 参数传递      [重难点] · ref引用参数 ...

  6. 后台API服务的设计考虑

    我在<写在最前>里说过,后台API的文档至关重要.不过,文档只是外在表现形式,设计才是真正的灵魂.我在这篇博文主要介绍的就是我在后台开发过程中,设计API时的考虑.我只说他是考虑,因为很多 ...

  7. API网关的设计思路及落地 IT大咖说 - 大咖干货,不再错过

    API网关的设计思路及落地 IT大咖说 - 大咖干货,不再错过   http://www.itdks.com/dakashuo/new/dakalive/detail/1407

  8. 开放接口/RESTful/Api服务的设计和安全方案

    总体思路 这个涉及到两个方面问题:一个是接口访问认证问题,主要解决谁可以使用接口(用户登录验证.来路验证)一个是数据数据传输安全,主要解决接口数据被监听(HTTPS安全传输.敏感内容加密.数字签名) ...

  9. REST API权限集成设计

    REST API权限集成设计 应用分为两大部分,前端html+后端Rest服务,前端html和后端Rest服务部署完全分离. 目标:可访问资源都处于权限控制之下(意味着通过浏览器地址栏的任意url都会 ...

随机推荐

  1. JAVA判断上传表单中file是否为空

    <form action="update.do"method="post" enctype="multipart/form-data" ...

  2. 升级 pip版本

    安装第三方库:pip install Pillow 出现 You are using pip version 7.1.2, however version 9.0.1 is available. Yo ...

  3. jdbc调用mysql存储过程实现代码带有输入和输出

    转载自 http://www.jb51.net/article/34747.htm 1. 创建存储过程 建立一个MySQL的存储过程 add_pro 复制代码代码如下: delimiter // dr ...

  4. ubuntu14.04 + cocos2d-x-2.2.6 + eclipse发布android + Qt Creator4

    先把需要的东西准备好,打开控制台,执行以下语句: sudo apt--jdk lib32z1 lib32ncurses5 lib32bz2- 接下来,准备好cocos2d-x-2.2.6和 andro ...

  5. python核心编程第二版笔记

    python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d   提供调试输出1.2 –O   生成优化的字节码(生成 ...

  6. 小米路由器mini如何设置外网访问wan网站的方法

    很多的玩友都在小米路由器mini上面搭建了自己的网站,有些朋友还需要设置对外网进行开放,我自己也在路由器上面实践了使用,下面与大家分享一下如何设置外网访问路由器网站的办法. 工具/原料 小米路由器mi ...

  7. Javascript: 截取字符串多出来并用省略号[...]显示

    /背景知识/ substring 方法用于提取字符串中介于两个指定下标之间的字符 substring(start,end) 开始和结束的位置,从零开始的索引 参数描述 start 必需.一个非负的整数 ...

  8. ffmpeg + sdl -03 简单音频播放器实现

    没办法,工作中遇到了问题. 目前NEC EMMA的架构如下: 从USB读入文件 -> 文件分析并提取Packet中的Payload Data   -> NEC HANDLE AVTrans ...

  9. 多路复用I/O select()

    select(),poll(),epoll()的总结:http://www.cnblogs.com/Anker/p/3265058.html 在socket编程中,仅仅使用connect,accept ...

  10. fread(),fwrite() 读/写流

    C 库函数 - fread() 描述 C 库函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 strea ...