23.4  API的设计原则和规范

API是服务提供方和使用方之间对接的通道,前面我们设计的一些简单API的例子,基本上比较随意,没有使用任何规范。设想一下,每个平台都可能存在大量的API,如果API设计没有原则,也没有统一的规范,按开发者的意愿随意编写,访问千差万别的API,不仅让API的使用非常麻烦,对API的改动也会导致项目或移动App无法工作。当然,一个好的规范对于解决这些事情能起到事半功倍的作用。如果想让服务端的价值更好地体现出来,就要好好设计API。通过使用规范的API,我们的服务或核心程序将有可能成为其他项目所依赖的平台。我们提供的API越易用,就会有越多人愿意使用它。

23.4.1  什么是RESTful风格的API

现在不管是开发移动应用,还是基于前后端分离,企业在设计API时都会遵循RESTful风格。REST(Representational State Transfer)定义了一套基于Web的数据交互方式的设计风格,符合REST风格的API就可以叫作RESTful API,REST只是风格没有标准,是目前最流行的一种互联网软件架构。它结构清晰、符合标准、扩展方便,基于这个风格设计的软件可以更简洁、更有层次、更易于实现缓存等机制,所以越来越多的网站和项目开始采用RESTful风格。Web应用程序的API设计,最重要的REST原则是,客户端和服务器之间的交互请求之间是无状态的。从客户端到服务器的每个请求,都必须包含理解请求所必要的信息。

23.4.2  RESTful API应遵循的原则

一次完整的API调用过程,所涉及的每个环节都需要设计为统一的风格,包括客户端使用的HTTP方法、URI的格式、返回数据的结构等,都应遵循RESTful API的原则。

1.    协议

API与用户的通信协议,尽量使用HTTPs协议。使用HTTPs协议和RESTful API本身没有多大关系,但是对于增加网站的安全性是非常重要的,特别是如果提供的是公开的API,那么HTTPs就更显得重要了。因为HTTPs协议的所有信息都是加密传播的,第三方无法窃听,具有校验机制,一旦被篡改,通信双方会立刻发现,配备身份证书,防止身份被冒充。如果做不到全部都使用HTTPs协议,也一定要在项目的登录和注册的接口上使用。因为在这两个接口用户还没有登录系统,没有获取用户身份,是最容易被窃听的。其他登录后才需要访问的API可以使用HTTP协议。

2.    域名

请求API的URL中除了协议外, 请求的根地址也很重要,一个好的软件架构,最好要让API的系统可以有单独的访问通道。应该尽量将API部署在专用的域名下面,例如:

https://api.ydma.com

如果确定API很简单,不会有进一步的扩展,可以考虑把API放在子域名下面,例如:

https://ydma.com/api/

3.    版本

在设计API时一定要有版本规划,以便以后API的升级和维护。应强制性规划API版本,不要发布无版本的API。在使用简单数字时,避免有小数点,如v3.5。应该将API的版本号放入URL中,如下所示:

https://api.ydma.com/v1/

当然,也可以将版本号放在HTTP的头信息中, 但不如放入URL方便和直观。

4.    路径

路径表示API的具体网址URL,在RESTful架构中,每个网址代表一种“资源”的存放地址,所以网址中不能有动词,只能有名词,而且名词一般都应该与数据库的表和字段对应且使用复数,例如:

https://api.ydma.com/v1/courses              // IT云课堂的所有课程,代表多个资源

https://api.ydma.com/v1/courses/1/php         // id为1的课程中的所有PHP课程,代表多个资源

https://api.ydma.com/v1/courses/1             // 代表单个资源,id为1的课程

https://api.ydma.com/v1/courses/1;2;3          // 代表单个资源,id为1、2、3的课程

URL中“/”表示层级,用于按“资源实体”的关联关系进行对象导航,一般跟进id导航。过深的导航层级容易导致URL膨胀,不易维护,如https://api.ydma.com/v1/ courses/1/web/3/php/4,尽量使用查询参数代替路径中的实体导航。

注意:根据RFC3986定义,URL是区分大小写的,所以应该尽量使用小写字母来命名!

5.    请求方法

有了“资源”的URL设计,所有针对资源的操作,都用指定的HTTP动词,HTTP常见的操作动词如表23-2所示。

表23-2  HTTP常见的操作动词

注意:GET方法和查询参数不应该涉及状态改变。应使用PUT、POST和DELETE方法而不是GET方法来改变状态。PUT更新单个资源(全量),由客户端提供完整的更新后的资源。与之对应的是 PATCH,PATCH 负责部分更新,由客户端提供要更新的字段。

6.    过滤信息

如果数据量太大,服务器不可能将所有数据返给用户。API应该提供参数来过滤返回结果,为集合提供过滤、排序、选择和分页等功能。如表23-3所示,是URL中常见的过滤信息。

表23-3  URL中常见的过滤信息

另外,在移动端开始时,由于移动设备的显示空间小,只能显示其中一些必要的字段,其实不需要接口返回一个资源的所有字段,给API一个选择字段的功能,这会降低网络流量,提高API的可用性,例如:

GET https://api.ydma.com/v1/users?fields=id,username,sex&state=open&sort=age     // 获取三个字段

7.    固定返回码

在HTTP头部报文构成中,字段“status code”很重要。它说明了请求的大致情况,是否正常处理、出现了什么错误等。状态码都是3位数,大概分为以下几个区间,如表23-4所示。

表23-4  HTTP 状态码区间说明

我们在使用RESTful API时需要使用返回码的原因大致如下,客户端在调用一个API之后,接收到的反馈必须能够标识这次调用是否成功,如果不成功,客户端需要得到执行失败的原因。我们可以在API设计时做一个小小的约定,就能完美的满足自己的需求了。REST的大部分实现都是基于HTTP的,那么自然而然就少不了与返回码打交道。遗憾的是,HTTP的返回码的定义很多,也很烦琐,信息表达还不够详细,和实际开发中用到的状态含义还有些差距。虽然很多公司的开发组都直接使用HTTP的状态码,但笔者建议,根据项目自身去自定义一些状态码和对应的错误返回信息会更适用一些,如表23-5所示。

表23-5  自定义状态码参考

尽可能提供准确的错误信息,如数据格式不正确、缺少某个字段等,而不是直接返回“请求错误”之类的信息。

8.    固定返回结构

现在,越来越多的API设计会使用JSON来传递数据,本章也以JSON为例。只要调用成功,服务器端必须响应数据,而响应数据的格式在任何情况下都应当是一致的,这样有利于客户端处理返回结果。自定义服务器端所有的响应格式如下:

成功返回的消息结构

失败返回的消息结构

{

"code": 0,

"message": "",

"time":1527158707,

"data":{"id":"1","username":"高洛峰","sex":"男","age":"30"}

}

{

"code": E002,

"message": "无效的请求",

"time":1527158402,

"data":{ }

}

它们的含义如下:

Ø code为0代表调用成功,其他是自定义的错误码。

Ø message表示在API调用失败的情况下详细的错误信息,这个信息可以由客户端直接呈现给用户,否则为空。

Ø time 返回的是服务器动态时间,通过这个时间的变化,让用户知道重新请求过服务器。

Ø data表示服务器端返回的数据,具体格式由服务器端自定义,API调用错误则为空。

REST风格的API会针对不同操作,服务器向用户返回的不同结构的结果,需要符合以下规范,但笔者认为这样比较烦琐,如下所示:

GET https://api.ydma.com/v1/collection

GET https://api.ydma.com/v1/collection/resource

POST https://api.ydma.com/v1/collection

PUT https://api.ydma.com/v1/collection/resource

PATCH https://api.ydma.com/v1/collection/resource

DELETE https://api.ydma.com/v1/collection/resource

#返回一个资源对象的列表

#返回一个资源对象

#返回新创建的资源对象

#返回一个完整的资源对象

#返回一个完整的资源

#返回一个空文档

9.    编写文档

API最终是让人使用的,无论是对内还是对外,即使遵循上面提到的所有规则,API设计得很优雅,有时候用户还是不知道该如何使用它们。因此,编写清晰可读的文档是很有必要的。另外,编写文档也可以作为产出的一部分,以及用来记录,以方便查询参考。项目组中常用的API文档结构如图23-10所示。

图23-10  项目组中常用的API文档结构

当然,如果单独管理API文档是比较麻烦的,我们可以借助工具来管理,如国内比较不错的平台www.showdoc.cc,可以在该平台上注册一个账号管理接口文档,也可以独立搭建网站来管理,下载地址 https://www.getpostman.com/。该工具不仅可以管理文档,还可以模拟HTTP请求,当作应用接口的客户端来使用,操作比较简单,还可以模拟GET、POST等请求接口,也能查看响应结果,针对 JSON 格式的数据还提供解析功能。

《细说PHP》第四版 样章 第23章 自定义PHP接口规范 6的更多相关文章

  1. 《细说PHP》第四版 样章 第二章 PHP的应用与发展 1

    <细说PHP>第四版 样章 第二章 PHP的应用与发展 1 学习任何编程语言之前,先了解一下它的应用与发展是很有必要的.从Web开发的历史看来,PHP.Python和Ruby几乎是同时出现 ...

  2. 《java编程思想(第四版)》第一二章学习笔记

    目录 一.Introduction 1.抽象过程 2.面向对象语言(包括Java)的五个基本特性 3.每个对象都提供服务 4.public.private.protected三者的区别 5.Java的 ...

  3. 《细说PHP》 第四版 样章 第二章 PHP的应用与发展 5

    2.5  如何学习PHP PHP以其简单易学的特点,以及敏捷开发的优势,从一个几乎不被人知的开源项目,慢慢成长为技术人员首选的动态Web设计工具,与其他语言相比,PHP表现得更好.更快.更简单易学.尽 ...

  4. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 11

    23.6  使用第三方接口服务实例 接供服务的第三方接口平台有很多,现在的项目中也经常用到一些第三方接口,如支付宝.微信.短信.邮件接口等,我们需要借助第三方的能力来实现产品的某些功能.如果自己已经掌 ...

  5. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 9

    23.5.3  WebAPI框架应用 程序框架其实就是一个半成品项目,在应用框架时,核心的服务程序只应用,不需要改动.当然如果有必要,也可以根据项目的需要对框架进行二次开发.本节内容主要基于我们的框架 ...

  6. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 8

    23.5.2  架构详解 本例的实现最重要的就是服务层的设计,有两个配置文件config.php和api.php,其中文件config.php是全局的配置文件,用于整个程序全局需要的参数设置.可以根据 ...

  7. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 3

    23.2  接口实现的基础 大家都很了解函数在本地应用,通过名称调用函数执行,并通过传递不同参数,函数有不同执行,执行后给调用者返回结果.如果把一个函数做成一个接口远程访问,也需要这几个步骤.使用HT ...

  8. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 1

    如今的项目开发中,接口是很普遍的应用技术.现在好多项目组都单独设有接口开发人员.像腾讯.微博.淘宝等开放平台,其所谓的开放,就是提供一些可调用的接口,用于获取相关的信息.例如,微信用户基本信息.淘宝店 ...

  9. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 12

    18.9  管理表books实例 在Web项目中,几乎所有模块都要和数据表打交道,而对表的管理无非就是增.删.改.查等操作,所以熟练掌握对表进行管理的这些常见操作是十分有必的.本例为了能更好地展示PD ...

随机推荐

  1. 如何通过QT designer设置不让窗口最大化

    最近使用QT写一个小窗口的程序,窗口通过QT designer制作之后,运行时可以最大化操作,且最大化之后界面上控件也不会随窗口变化而变化,但由于人都比较懒,直接在QT designer设置窗口属性时 ...

  2. 28.分类算法---KNN

    1.工作原理: 存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系.输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特 ...

  3. [洛谷P1279][题解]字串距离

    题目戳我 很明显的这题是一道dp,主要讲一下几个细节 1.初始化 我们需要初始化边界情况也就是一个字符串为空的情况 #----------# #----------# A:aaaaaa A:□□□□□ ...

  4. 菜鸟刷面试题(一、Java基础篇)

    目录: JDK 和 JRE 有什么区别? == 和 equals 的区别是什么? 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? final 在 java 中有什 ...

  5. spring data JPA entityManager查询 并将查询到的值转为实体对象

    spring data JPA entityManager查询 并将查询到的值转为实体对象 . https://blog.csdn.net/qq_34791233/article/details/81 ...

  6. ccf-csp201809题解

    目录 ccf-csp201809题解 1. 201809-1 卖菜 题目描述 解析 通过代码 2. 201809-2 买菜 题目描述 解析 通过代码 3.201809-3 元素选择器 题目描述 解析 ...

  7. Pipe——高性能IO(三)

    Pipelines可以替换掉那些丑陋的封装(kludge).变通(workaround)或妥协(compromise)——用一个在框架中设计优雅的专门的解决方案. 敢肯定,下面所覆盖的那些痛点,对于那 ...

  8. 你必须知道的Docker数据卷(Volume)

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.将Docker数据挂载到容器 在Docker中,要想实现数据的持久化(所谓 ...

  9. ArrayList 与数组的“纠缠不清”的暧昧

    目录 前言 正话(个人的见解,有误请多指教) 惯例先明白它是什么? 那么它有什么用呢? 怎么用 前言 能不能有一种数组可以在删除掉某些元素自动缩小就好了.可是话说哪里学的Java?数组能删除元素吗?今 ...

  10. 从web到游戏,走出舒适区

    最近很久没有更新博客了,实在太忙.因为在这段时间里我做了一个改变了我现在职业生涯的一个决定,而我现在正在为这个决定而加倍的努力付出. 我认为我还是有必要把这个比较重要的节点记录下来,我也是第一次在自己 ...