Restful API 设计

1. 简介

目前 "互联网软件"从用客户端/服务端模式,建立在分布式体系上,通过互联网通讯,具有高延时、高开发等特点。但是软件开发和网络是两个不同的领域,交集很少。要使得两个融合,就要考虑如何在互联网环境使用软件。

REST 描述了一个架构样式的网络系统,2000 年 Roy Fielding 在他的博士论文中首次提出了 REST,同时他也是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。

目前主流的三种 Web 服务交互方案:

  • REST:表现层状态转化
  • SOAP(Simple Object Access protocol):简单对象访问协议
  • XML-RPC

要想理解什么是 REST(Representational State Transfe) 就要理解这里几个词是什么意思。

资源(Resources)

REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。

网络中所谓资源即实体表现的一种,如:文本、图片、音频,视频等。通过调用特定的 URI 来获取相应资源,因此 URI 就成了每一个资源的地址或独一无二的识别符。


表现层(Representation)

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

如:文本可以以 txt、json、xml 等格式表现,甚至是二进制格式,图片也有 jpg、png 等格式。

URI 只代表资源的实体,不代表它的形式。严格地说,有些网址最后的.html 后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用 Accept 和 Content-Type字段指定,这两个字段才是对"表现层"的描述。


状态转化(State Transfer)

众所周知互联网通讯协议 HTTP 协议是无状态的,所有状态都保存在服务器上。因此如果客户端要想操作(获取、删除、更新操作数据),就必须让服务器状态发生改变(State Transfer)而这种状态转化建立在表现层上,所有称为 表现层状态转化

客户端通过 HTTP 协议可以与服务端进行通信,HTTP 协议中表示操作的四个动作是:

  • GET:获取资源
  • POST:新建资源
  • PUT:更新资源
  • DELETE:删除资源

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。


RESTful架构典型的设计误区

1、URI 中包含动词:资源是一种实体,应该用名词,动词应放在 HTTP 协议中。

# 错误,show 为动词
/posts/show/1# 如果要获取可用 get
/posts/1
/get/         # 表示 show      

若某些动作用 HTTP 动词表示不了,可用将动作看做一种资源,如:网上付款 URI 设计:

# 错误
POST /accounts/1/transfer/500/to/2# 正确
POST /transaction HTTP/1.1
Host: 127.0.0.1from=1&to=2&amount=500.00

2、在 URI 中加入版本号

# 错误
http://www.example.com/app/1.0/foo
http://www.example.com/app/1.1/foo

不同的版本,可以理解成同一种资源的不同表现形式,所以应该采用同一个U RI。版本号可以在HTTP请求头信息的Accept字段中进行区分(参见 Versioning REST Services):

# 正确
Accept: vnd.example-com.foo+json; version=1.0
Accept: vnd.example-com.foo+json; version=1.1

然而实际开发中,大多开发人员会将版本号放在 URI 中,因为方便。


总结

什么是 RESTful 架构:

  • RESTful 是一种在网络上能够开发软件的体系架构
  • 互联网之间通讯是资源的一种交互
  • 每个 URI 代表一种资源,通过特定 URI 可以访问相应资源
  • 资源有不同的表现形式
  • HTTP 协议无状态
  • 客户端获取服务器资源,需要改变其状态
  • 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"

2. RESTful API 设计指南

2.1 协议

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

2.2 域名

1、应该尽量将 API 部署在专用域名之下,(这中情况会存在跨域问题)

https://api.example.com

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

https://example.org/api/

2.3 版本(Versioning)

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

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

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

2.4 路径(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

2.5 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:删除某个指定动物园的指定动物

2.6 过滤信息(Filtering)

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

下面是一些常见的参数:

# 指定返回记录的数量
https://api.example.com/v1/zoos?limit=10# 指定返回记录的开始位置
https://api.example.com/v1/zoos?offset=10# 指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?page=2&per_page=100# 指定返回结果按照哪个属性排序,以及排序顺序
https://api.example.com/v1/zoos?sortby=name&order=asc# 指定筛选条件
https://api.example.com/v1/zoos?animal_type_id=1

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

2.7 状态码(Status Codes)

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

  • 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
  • 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
  • 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
  • 204 NO CONTENT - [DELETE]:用户删除数据成功。
  • 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
  • 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
  • 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
  • 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
  • 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
  • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
  • 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
  • 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

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

2.8 错误处理(Error handling)

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

{error: "Invalid API key"
}

2.9 返回结果

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

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

2.10 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。

转载于:https://www.cnblogs.com/midworld/p/11075965.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393078.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sql行数少于10_如何用少于100行的代码创建生成艺术

sql行数少于10by Eric Davidson埃里克戴维森(Eric Davidson) 如何用少于100行的代码创建生成艺术 (How to Create Generative Art In Less Than 100 Lines Of Code) Generative art, like any programming topic, can be intimidating if you’ve never tried it before. I’v…

安装输入发

直接在系统 ——系统管理 ——语言支持 选——中文从新启动 sudo apt-get install scim-pinyin安装JAVA环境支持 sudo apt-get install sun-java-jre()要是 apt -get 命令不能用 可能是你 的 源有问题 可以 更新一下 在系统 -系统管理 源设置 选这台湾的 就可以 …

(第2篇)一篇文章教你轻松安装hadoop

摘要: 这篇文章将会手把手教你安装hadoop,只要你细心按照文章中的步骤操作,hadoop肯定能正确安装,绝对不会让你崩溃 博主福利 给大家赠送一套hadoop视频课程 授课老师是百度 hadoop 核心架构师 内容包括hadoop入门、hadoop生态架构以及大型ha…

linux cpio到指定目录,linux cpio命令存取归档包中的文件

功能描述使用cpio命令可以通过重定向的方式将文件进行打包备份及还原恢复,它可以解压缩以“.cpio”或者“.tar”结尾的文件。命令语 法cpio [选项] [目标目录]选项含义选项含义-o执行 copy-out 模式,建立备份档。-i执行 copy-in 模式,还原备份…

leetcode剑指 Offer 20. 表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"100"、“5e2”、"-123"、“3.1416”、"-1E-16"、“0123"都表示数值,但"12e”、“1a3.14”、“1.2.3”、"…

python接口自动化2-发送post请求

前言 发送post的请求参考例子很简单,实际遇到的情况却是很复杂的,首先第一个post请求肯定是登录了,但登录是最难处理的。登录问题解决了,后面都简单了。 一、查看官方文档 1.学习一个新的模块,其实不用去百度什么的&am…

简介浏览器内核与JavaScript引擎

本文介绍了常用浏览器内核与JavaScript引擎 一、浏览器内核 Rending Engine, 顾名思义,称之为渲染网页内容的,将网页的代码转换为你看得见的页面,因为是排版,所以排版,所以肯定会有排版错误等问题。为什么会有排版错误…

Linux查看tar实用程序,linux tar指令常用选项

linux的tar指令经常被用到,因为压缩文件的时候通常需要打包文档,而tar指令就是打包指令,同时gzip压缩程序和bzip2压缩程序都是支持tar指令的,所以tar指令在打包的同时还可以用gzip和bzip进行压缩,这样多文件可以打包的…

代码字体mono_如何构建代码存储库:Multi,Mono或Organic?

代码字体monoby Chetan Sharma由Chetan Sharma 如何构建代码存储库:Multi,Mono或Organic? (How to Structure Code Repositories: Multi, Mono, or Organic?) The newest debate in town is whether you should keep your services in a si…

leetcode1424. 对角线遍历 II(排序)

给你一个列表 nums ,里面每一个元素都是一个整数列表。请你依照下面各图的规则,按顺序返回 nums 中对角线上的整数。 示例 1: 输入:nums [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,4,2,7,5,3,8,6,9] 代码 class Solution …

DaVinci各版本安装指南

链接: https://pan.baidu.com/s/1g1kaXZxcw-etsJENiW2IUQ?pwd0531 ​ #2024版 1.鼠标右击【DaVinci_Resolve_Studio_18.5(64bit)】压缩包(win11及以上系统需先点击“显示更多选项”)【解压到 DaVinci_Resolve_Studio_18.5(64bit)】。 2.打开解压后的文…

使用 Servlet 读取表单数据

Technorati 标签: servlet;java 一、概述 Servlet 有一个比较好的功能就是可以自动处理表单提交的数据。我们只需要调用HttpServletRequest#getParameter(String name),就可以获得指定参数的值(String),注意此方法是大小写敏感的。…

linux文档权限

1、登录 root 用户:su - mac一开始进入创建的用户是具有管理员权限的用户,但是密码却不是进入 root 用户的密码,可以使用 sudo su - 免密进入 root 用户。 2、退出 root 用户:exit 3、列出档案(包括隐藏的档案&#xf…

小程序 仿麦当劳_手机上的麦当劳和星巴克:为什么现在首先使用移动应用程序...

小程序 仿麦当劳by James Hsu由徐H 手机上的麦当劳和星巴克:为什么现在首先使用移动应用程序 (McDonald’s and Starbucks on Your Phone: Why Mobile Apps Are Now First on the Menu) One Friday this July, I got excited about McDonalds. So excited that I s…

MyLinkedList

/*** 节点类* author JP* */ class Node {Object value;//节点元素值Node pre;//上一个节点Node next;//下一个节点public Node(Object value) {this.value value;} }/*** 链表类* author JP**/ public class MyLinkedList {Node cur;//目前指向的节点Node head;//头结点Node …

linux开启ping服务,Linux 云服务器禁止和开启Ping

原标题:Linux 云服务器禁止和开启Ping在使用Linux服务器的时候,一般系统默认是开启ping的,比如我们可以ping测试网络的延迟质量。当然也有部分服务商是可以通过安全组设置禁止ping的,我们可以设置安全组对应项目开启或禁止ping&am…

leetcode1432. 改变一个整数能得到的最大差值(贪心)

给你一个整数 num 。你可以对它进行如下步骤恰好 两次 &#xff1a; 选择一个数字 x (0 < x < 9). 选择另一个数字 y (0 < y < 9) 。数字 y 可以等于 x 。 将 num 中所有出现 x 的数位都用 y 替换。 得到的新的整数 不能 有前导 0 &#xff0c;得到的新整数也 不能…

oracle之 Oracle归档日志管理

在Oracle中&#xff0c;数据一般是存放在数据文件中&#xff0c;不过数据库与Oracle最大的区别之一就是数据库可以在数据出错的时候进行恢复。这个也就是我们常见的Oracle中的重做日志(REDO FILE)的功能了。在重做日志分成2部分&#xff0c;一个是在线重做日志文件&#xff0c;…

linux 安装rmp服务,Linux LAMP服务的rpm包安装与配置

1.apache(httpd) 所在光盘装包apr-xxx.rpm (二)postgresql-libs-xxx.rpm (二)apr-util-xxx.rpm (二)http-xxx.rpm (二)2.mysql (二)装包perl-DBI-xxx.rpm (二)mysql-xxx.rpm (二)3.mysqlserver装包perl-DBD-mysql-xxx.rpm (二)mysql-server-xxx.rpm (二)4.PHP装包gmp-xxx.rpm (…

红外感应模块+蜂鸣器实现简易报警(转)

拿到了一个红外感应模块HC-SR501&#xff0c;于是就用它和蜂鸣器简单试验了下。主要是试验一下这个红外感应模块的功能&#xff0c;所以代码也写的很随便啦&#xff0c;逻辑上也欠考虑。实现基本功能&#xff1a;运行脚本后&#xff0c;感应模块每隔一定时间检测&#xff0c;如…