REST是代表状态转移的缩写,它是最常用的Web服务技术的几乎毫无意义的描述!REST是两个计算机系统通过HTTP进行通信的一种方式,类似于Web浏览器和服务器。
在两个或多个系统之间共享数据一直是软件开发的基本要求。例如,考虑购买汽车保险。您的保险公司必须获取有关您和您的车辆的信息,以便他们向汽车登记机构,信贷机构,银行和其他系统索取数据。所有这些实时透明地发生,以确定是否可以提供策略。
这篇颇受欢迎的文章在2020年进行了更新,以准确地解释现代REST API。
REST示例
在浏览器中打开以下链接,以请求一个随机编程笑话:
https://official-joke-api.appspot.com/jokes/programming/random
这是实现为RESTful Web服务的公共API(遵循REST约定)。您的浏览器将显示可怕的 JSON格式的编程笑话,例如:
[
{
"id": 29,
"type": "programming",
"setup": "There are 10 types of people in this world...",
"punchline": "Those who understand binary and those who don't"
}
]
您可以使用任何HTTP客户端(例如curl)来请求相同的URL并获得响应:
curl "https://official-joke-api.appspot.com/jokes/programming/random"
HTTP客户端库在所有流行的语言和运行时中都可用,包括JavaScript中的Fetch和PHP中的file_get_contents()。JSON响应是机器可读的,因此可以解析并以HTML或任何其他格式输出。
休息与休息
这些年来,各种数据通信标准都在发展。您可能会遇到包括CORBA,SOAP或XML-RPC在内的标准,这些标准通常会建立严格的消息传递规则。
REST由Roy Fielding于2000年定义,并且相当简单。它不是标准,而是针对RESTful Web服务的一系列建议和约束。这些包括:
- 客户端服务器。SystemA向SystemB托管的URL发出HTTP请求,该URL返回响应。
这与浏览器的工作方式相同。该应用程序请求一个特定的URL。该请求被路由到返回HTML页面的Web服务器。该页面可能包含对图像,样式表和JavaScript的引用,这些引用会导致进一步的请求和响应。
- 无状态的。REST是无状态的:客户端请求应包含响应请求所需的所有信息。换句话说,应该可以以任何顺序发出两个或多个HTTP请求,并且将接收到相同的响应。
- 可缓存。应将响应定义为可缓存或不可缓存。
- 分层。发出请求的客户端不需要知道它是否与实际的服务器,代理或任何其他中介进行通信。
创建一个RESTful Web服务
RESTful Web服务请求包含:
- 端点URL。实施RESTful API的应用程序将使用域,端口,路径和/或查询字符串(例如)定义一个或多个URL端点。
https://mydomain/user/123?format=json
- HTTP方法。可以在映射到应用程序创建,读取,更新和删除(CRUD)操作的任何端点上使用不同的HTTP方法:
HTTP方法 欺诈 行动 得到 读 返回请求的数据 开机自检 创建 创建新记录 放置或修补 更新 更新现有记录 删除 删除 删除现有记录 例子:
- GET请求以
/user/
返回系统上已注册用户的列表 - POST请求以使用主体数据创建具有ID的用户
/user/123
123
- 一个PUT请求,以用主体数据更新用户
/user/123
123
- GET请求以返回用户的详细信息
/user/123
123
- 删除用户的DELETE请求
/user/123
123
- GET请求以
- HTTP标头。如信息的认证令牌或Cookie可以包含在HTTP请求报头。
-
身体数据。数据通常以与HTML 提交相同的方式在HTTP正文中传输,或通过发送单个JSON编码的数据字符串传输。
<form>
响应
该响应有效载荷可以是任何实用:数据,HTML,图像,音频文件,依此类推。数据响应通常是JSON编码的,但是可以使用XML,CSV,简单字符串或任何其他格式。您可以允许在请求中指定返回格式,例如或。/user/123?format=json
/user/123?format=xml
还应该在响应头中设置适当的HTTP状态代码。尽管成功也可以在创建记录时返回,但它通常用于成功的请求。错误应该返回相应的代码,比如,,,等等。200 OK
201 Created
400 Bad Request
404 Not Found
401 Unauthorized
可以设置其他HTTP标头,包括Cache-Control或Expires指令,以指定在响应被认为过时之前可以将响应缓存多长时间。
但是,没有严格的规则。可以根据需要实现端点URL,HTTP方法,主体数据和响应类型。例如,POST,PUT和PATCH通常可以互换使用,因此任何人都可以创建或更新记录。
REST“ Hello World”示例
以下代码使用Node.js Express框架创建RESTful Web服务。单个/hello/
端点响应GET请求。
确保已安装Node.js,然后创建一个名为的新文件夹restapi
。在该文件夹中创建一个包含以下内容的新文件:package.json
{
"name": "restapi",
"version": "1.0.0",
"description": "REST test",
"scripts": {
"start": "node ./index.js"
},
"dependencies": {
"express": "4.17.1"
}
}
运行npm install
在命令行来获取相关性,则创建一个用下面的代码文件:index.js
// simple Express.js RESTful API
'use strict';
// initialize
const
port = 8888,
express = require('express'),
app = express();
// /hello/ GET request
app.get('/hello/:name?', (req, res) =>
res.json(
{ message: `Hello ${req.params.name || 'world'}!` }
)
);
// start server
app.listen(port, () =>
console.log(`Server started on port ${port}`);
);
使用从命令行启动应用程序,npm start
然后在浏览器中打开。显示以下JSON以响应GET请求:http://localhost:8888/hello/
{
"message": "Hello world!"
}
该API还允许使用自定义名称,因此返回:http://localhost:8888/hello/everyone/
{
"message": "Hello everyone!"
}
客户端REST请求和CORS
考虑以下在浏览器中URL启动的HTML页面:http://localhost:8888/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>REST test</title>
</head>
<body>
<script>
fetch('http://localhost:8888/hello/')
.then((response) => {
return response.json();
})
.then((json) => {
console.log(json);
});
</script>
</body>
</html>
该fetch
调用发出与您期望的相同的API请求和浏览器控制台。Object { message: "Hello world!" }
但是,假设您的RESTful Web服务现在已在域中的Web上发布。页面JavaScript URL会相应更改,但是现在在浏览器中打开会返回控制台错误Cross-Origin Request Blocked。http://mydomain.com/hello/
fetch()
http://localhost:8888/
为了安全起见,浏览器仅允许客户端XMLHttpRequest和Fetch API调用访问托管页面的同一域。
幸运的是,跨域资源共享(CORS)使我们能够规避该安全限制。设置HTTP响应标头可告知浏览器允许该请求。可以将其设置为特定域或所有域(由上述Joke API完成)。Access-Control-Allow-Origin
*
因此,可以更改Web服务API代码以允许从任何域上运行的任何客户端脚本进行访问:
// /hello/ GET request
app.get('/hello/:name?', (req, res) =>
res
.append('Access-Control-Allow-Origin', '*')
.json(
{ message: `Hello ${req.params.name || 'world'}!` }
)
);
另外,Express.js中间件函数可以将标头附加到每个端点请求:
// enable CORS
app.use((req, res, next) => {
res.append('Access-Control-Allow-Origin', '*');
next();
});
// /hello/ GET request
// ...
REST挑战
REST的成功很大程度上归功于其简单性。开发人员可以随意实现自己喜欢的RESTful API,但这可能会带来更多挑战。
端点共识
考虑以下端点:
/user/123
/user/id/123
/user/?id=123
所有这些都是为user提取数据的有效选项123
。当您进行更复杂的操作时,组合的数量会进一步增加。例如,返回十个姓氏以’A’开头的用户,并按生日按相反的生日顺序为第51条记录的companyX工作。
最终,格式化URL的形式无关紧要,但API的一致性很重要。对于许多开发人员而言,在大型代码库上很难做到这一点。
API版本控制
API的更改是不可避免的,但是当端点URL在内部和/或由第三方应用程序使用时,绝不应使它们无效。
通常对API进行版本控制以避免兼容性问题(例如,被取代),但是旧的端点仍处于活动状态。但是,由于维护了多个API,因此增加了工作量。较旧的API最终可能会被废弃,但是该过程需要仔细计划。/2.0/user/123
/user/123
认证方式
上面显示的笑话API是开放的:任何系统都可以未经授权获取笑话。这对于访问私有数据或允许更新和删除请求的API不可行。
与RESTful API在同一域中的客户端应用程序将像其他任何HTTP请求一样发送和接收cookie。(请注意,在较旧的浏览器中,需要设置init选项。)因此,可以验证API请求,以确保用户已登录并具有适当的权限。Fetch()
credentials
第三方应用程序必须使用其他授权方法。常见的身份验证选项包括:
- HTTP基本认证。
Authorization
包含base64编码的username:password字符串的HTTP标头在请求标头中传递。 - API密钥。通过发布可能具有特定权限或限于特定域的密钥,可以授予第三方应用程序使用API的权限。密钥在HTTP标头或查询字符串中的每个请求中传递。
- OAuth。通过向OAuth服务器发送客户端ID和可能的客户端密码,可以在获得任何请求之前获取令牌。然后,随每个API请求一起发送OAuth令牌,直到其过期为止。
- JSON Web令牌(JWT)。数字签名的身份验证令牌在请求和响应标头中安全地传输。
API身份验证将根据使用上下文而有所不同。在某些情况下,例如,从地图API生成路线时,第三方应用程序被认为是具有特定权限的另一个登录用户。在其他情况下,第三方应用程序由注册用户使用,并且只能访问其数据-例如,在获取电子邮件内容或文档时。
安全
RESTful API提供了另一种访问和操作应用程序的途径。即使这不是一个有趣的黑客攻击目标,行为不端的客户端也可能每秒发送数千个请求,并使服务器崩溃。
安全性不在本文讨论范围之内,但是常见的最佳做法包括:
- 使用HTTPS
- 使用可靠的身份验证方法
- 使用CORS将客户端调用限制为特定域
- 提供最小的功能-也就是说,不要创建不需要的DELETE选项
- 验证所有端点URL和主体数据
- 避免在客户端JavaScript中公开API令牌
- 阻止来自未知域或IP地址的访问
- 阻止意外的大负载
- 考虑速率限制-也就是说,使用相同API令牌或IP地址的请求限制为每分钟N个
- 使用适当的HTTP状态代码和缓存头进行响应
- 记录请求并调查失败。
多个请求和不必要的数据
RESTful API受其实现限制。响应中包含的数据可能超出您的需要,或者需要其他请求才能访问所有数据。
考虑一个RESTful API,它提供对作者和书籍数据的访问。为了显示最畅销的10本图书的数据,客户将:
- 请求
/book/
按销售数量排序的前10个详细信息(最畅销的产品)。该响应包含具有每个作者ID的书籍列表。 - 最多提出10个请求以获取每个作者的姓名。
/author/{id}
这被称为N + 1问题;必须为父请求中的每个结果发出N个API请求。
如果这是一个常见的用例,则可以更改RESTful API,以便每本返回的书都包含完整的作者详细信息,例如姓名,年龄,国家/地区,传记等。它还可以提供其他书籍的详细信息,尽管这会大大增加响应的负载!
为了避免大量响应,可以调整API,以便可以控制作者的详细信息(例如),但是选项的数量很快就会变得令人困惑。?author_details=basic
GraphQL可以修复REST吗?
这些REST难题使Facebook创建了GraphQL(一种Web服务查询语言)。可以将其视为Web服务的SQL。单个请求定义了您需要什么数据以及如何返回它们。
GraphQL解决了RESTful API带来的许多挑战。话虽如此,很少有公司遇到可与Facebook媲美的问题。一旦您的RESTful API的发展超出其简单的起点,就值得考虑GraphQL。
REST链接和开发工具
有许多工具可以帮助所有语言的RESTful API开发。值得注意的选项包括:
- Swagger:各种工具,可帮助设计,记录,模拟,测试和监视REST API
- 邮递员:RESTful API测试应用程序
- Postwoman:Postman的开源,基于Web的替代方案。
还有许多公共REST API,可满足笑话,货币换算,地理编码,政府数据以及您能想到的每个主题。许多都是免费的,尽管有些要求您注册API密钥或使用其他身份验证方法。分类列表包括: