乐趣区

关于restful:什么是REST-API

前言

什么是 REST API?REST 是 Representational State Transfer(体现层状态转移) 的缩写 – 对最罕用的网络服务技术简直是毫无意义的形容。REST API 是两个计算机系统在 web 浏览器和服务器中应用 HTTP 技术进行通信的一种形式。

在两个或多个零碎之间共享数据始终是软件开发的一个根本要求。比如说,思考购买汽车保险。你的保险公司必须取得对于你和你的车辆的信息,所以他们要求从汽车注销机构、信贷机构、银行和其余零碎取得数据。所有这些都是实时通明地产生的,以确定保险公司是否能提供一个有竞争力的保单。

API(利用程序接口)通过为零碎之间的对话提供接口来帮忙这种类型的通信。REST 只是一种被宽泛驳回的 API 格调,咱们用它来与外部和内部以一种统一的和可预测的形式进行沟通。它能够比作咱们以前寄信时用邮票、地址和信封的形式,以确保函件被送达和浏览。

REST 是人们在 web 零碎中罕用的交互方式。例如,在一个社交媒体利用中检索和更新账户信息。

REST API 示例

在你的浏览器中关上以下链接,从 Open Trivia Database 中申请一个随机的计算机问题:

https://opentdb.com/api.php?amount=1&category=18

这是一个作为 RESTful 网络服务实现的公共 API(它遵循 REST 公约)。你的浏览器将展现一个独自的 JSON 格局的问答问题,并附有答案。比如说:

{
  "response_code": 0,
  "results": [
    {
      "category": "Science: Computers",
      "type": "multiple",
      "difficulty": "easy",
      "question": "What does GHz stand for?",
      "correct_answer": "Gigahertz",
      "incorrect_answers": [
        "Gigahotz",
        "Gigahetz",
        "Gigahatz"
      ]
    }
  ]
}

你能够应用任意 HTTP 客户端,来申请同样的 URL 并失去响应,比方应用 curl:

curl "https://opentdb.com/api.php?amount=1&category=18"

HTTP 客户端库能够在所有风行的语言和运行时中应用,包含 JavaScript、Node.js 和 Deno 中的 Fetch 以及 PHP 中的 file_get_contents()。JSON 响应是机器可读的,因而能够在输入 HTML 或其余格局之前被进行解析和应用。

REST APIs 和 Rest

多年来,各种数据通信规范曾经倒退起来。你可能遇到过的抉择包含 CORBA,SOAP,或者 XML-RPC。大多数都确定了严格的消息传递规定。

REST 是由 Roy Fielding 在 2000 年定义的,比其余的要简略得多。它不是一个规范,而是一套对于 RESTful 网络服务的倡议和束缚。其中包含:

  • 客户服务器拆散模式(Client-Server):零碎 A 向零碎 B 托管的 URL 收回 HTTP 申请,并返回一个响应。这与浏览器的工作形式雷同。浏览器对一个特定的 URL 发出请求,该申请被转发到一个 web 服务器,该服务器通常返回一个 HTML 页面。该页面可能蕴含对图片、样式表和 JavaScript 的援用,从而产生进一步的申请和响应。
  • 无状态(Stateless):REST 是无状态的:客户端申请应该蕴含响应所需的所有信息。换句话说,应该能够依照任何程序收回两个或更多的 HTTP 申请,并且会收到雷同的响应(除非 API 被设计为返回随机响应)。
  • 可缓存(Cacheable):响应应该被定义为可缓存或不可缓存。缓存能够进步性能,因为没有必要为同一个 URL 从新生成一个响应。在某个时间段特定于某个用户的私人数据通常不会被缓存。
  • 分层(Layered):申请的客户端不须要晓得它是否在与理论的服务器、代理或任何其余中间人进行通信。

创立 RESTful 网络服务

一个 RESTful 网络服务申请包含:

  1. 端点 URL。实现 RESTful API 的应用程序将定义一个或多个带有域名、端口、门路、和 / 或查问字符串的 URL 端点,例如,https://mydomain/user/123?format=json
  2. HTTP 办法。不同的 HTTP 办法能够在任何端点上应用,这些办法映射到应用程序的创立、读取、更新和删除(CRUD)操作:

| HTTP 办法 | CRUD | 行为 |
| --- | --- | --- |
| GET | 读取 | 返回申请数据 |
| POST | 创立 | 创立一个新记录 |
| PUT 或者 PATCH | 更新 | 更新已存在的记录 |
| DELETE | 删除 | 删除已存在的记录 |

比方:- 对 `/user/` 的 GET 申请返回零碎中的注册用户列表。- 对 `/user/` 的 POST 申请应用 `body` 对象创立了一个 ID 为 `123` 的用户。该响应会返回 ID。- 对 `/user/123` 的 PUT 申请应用 `body` 对象更新用户 `123`。- 对 `/user/123` 的 GET 申请返回用户 `123` 的详情。- 对 `/user/123` 的 DELETE 申请删除用户 `123`。
  1. HTTP 头部 。认证令牌或cookies 等信息能够蕴含在 HTTP 申请头中。
  2. Body 对象 。数据通常在 HTTP 主体中传输,该形式与 HTML<form> 提交或者发送独自的 JSON 编码的数据字符串等形式雷同。

REST API 响应

响应的无效负载能够是任何实用的货色:数据、HTML、图像、音频文件等等。数据响应通常是 JSON 编码,但也能够应用 XML,CSV,简略字符串或任何其余格局。你能够容许在申请中指定返回格局。比如说,/user/123?format=json 或者 /user/123?format=xml

还应该在响应头中设置适当的 HTTP 状态码。200 OK用于胜利的申请,只管当记录被创立时也能够返回 201 Created。当产生谬误时应该返回适当的状态码,比如说400 Bad Request404 Not Found401 Unauthorized 等等。

其余 HTTP 头部能够被设置包含 Cache-ControlExpires,以指定响应在被视为过期之前能够缓存多长时间。

然而,并没有严格的规定。端点 URL、HTTP 办法、body 对象和响应类型能够得心应手地实现。例如,POST、PUT 和 PATCH 通常能够调换应用,如有必要任何一个都能够用来创立或更新记录。

Hello World 示例

上面的 Node.js 代码应用 Express 框架创立了一个 RESTful 网络服务。一个繁多的 /hello/ 端点对 HTTP GET 申请作出响应。

确保已装置 Node.js,创立名为restapi 的新文件夹。在该文件夹中创立一个新的 package.json 文件,内容如下:

{
  "name": "restapi",
  "version": "1.0.0",
  "description": "REST test",
  "scripts": {"start": "node ./index.js"},
  "dependencies": {"express": "4.18.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 从命令行启动该应用程序,并在浏览器中关上http://localhost:8888/hello/。响应 GET 申请时,会显示以下 JSON:

{"message": "Hello world!"}

API 也容许自定义名字,因而 http://localhost:8888/hello/everyone/ 会返回:

{"message": "Hello everyone!"}

客户端 REST 申请和 CORS

思考在浏览器中启动以下 HTML 页面,URL 是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 申请,浏览器控制台显示{message: "Hello world!"},正如你所冀望的那样。

然而,假如你的 RESTful 网络服务当初被放在网络上,域名是http://mydomain.com/hello/。页面的 JavaScript fetch()URL 也相应地扭转了,但在浏览器中关上http://localhost:8888/,当初会返回控制台谬误Cross-Origin Request Blocked

为了平安起见,浏览器只容许客户端的 XMLHttpRequestFetch API 调用页面所在的同域申请。

侥幸的是,跨源资源共享(CORS)使咱们可能躲避这一平安限度。设置Access-Control-Allow-OriginHTTP 响应头来通知浏览器容许该申请。它能够设置为一个特定的域,或者设置为所有的域*

能够更改网络服务器 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 API 收回两个申请:

  1. 对同一 URL 的 HTTP OPTIONS申请确定Access-Control-Allow-Origin HTTP 响应头是否无效。
  2. 理论的 REST 调用。

当你的服务器收到一个 OPTIONS 申请办法时,它能够设置Access-Control-Allow-Origin HTTP 响应头返回一个假的空响应,以确保工作不被反复。

REST API 挑战

REST 的胜利很大水平上归功于它的简略性。开发人员能够自在地实现 RESTful API,但这可能会导致进一步的挑战。要深刻理解实现策略,请看 13 个构建 RESTful API 的最佳实际。

端点共识

思考上面的端点:

  • /user/123
  • /user/id/123
  • /user/?id=123

所有这些都是为用户 123 获取数据的无效选项。当你有更简单的操作时,组合的数量会进一步减少。

归根结底,你如何格式化 URL 并不重要,但整个 API 的一致性很重要。这对有许多开发人员的大型代码库来说是个挑战。

REST API 版本控制

API 的变动是不可避免的,但端点的 URL 永远不应该生效,否则会毁坏应用它们的应用程序。

为了防止兼容性问题,API 通常是有版本的。例如,/2.0/user/123取代了/user/123。新的和旧的端点都能够放弃沉闷。可怜的是,这样就有必要保护多个历史 API。旧的版本最终能够被废除,但整个过程须要认真布局。

REST API 认证

下面显示的测试 API 是凋谢的:任何零碎都能够在未经受权的状况下获取数据。这对于拜访公有数据或容许更新和删除申请的 API 是不可行的。

与 RESTful API 处于同域的客户端应用程序将像其余 HTTP 申请一样发送和接管 cookies。(请留神,旧版浏览器中的Fetch() 须要设置 credentials 初始选项)。因而,一个 API 申请能够被验证,以确保一个用户曾经登录并领有适当的权限。

第三方应用程序必须应用代替的受权办法。常见的认证选项包含:

  • HTTP 根本身份验证。在申请头中传递一个蕴含 base64 编码的 username:password 字符串的 HTTPAuthorization头。因为 base64 很容易被解码,根本(Basic)认证应该只和其余平安机制一起应用,比方 HTTPS/SSL。
  • API 密钥。第三方应用程序通过公布一个密钥来取得应用 API 的许可,这个密钥可能有特定的权限或被限度在一个特定的域。密钥在每个申请中的 HTTP 头或查问字符串中被传递。
  • OAuth。在收回任何申请之前,通过向 OAuth 服务器发送一个客户 ID 和可能的客户机密,取得一个令牌。而后,OAuth 令牌会随每个 API 申请一起发送,直到过期。
  • JSON Web Tokens (JWT)。数字签名的认证令牌在申请和响应头中平安地传输。JWT 容许服务器对拜访权限进行编码,因而不须要调用数据库或其余受权零碎。

API 身份验证将依据应用上下文而有所不同:

  • 在某些状况下,第三方应用程序被视为像任何其余具备特定权力和权限的登录用户。例如,一个地图 API 能够将两点之间的方向返回给调用的应用程序。它必须确认该应用程序是一个无效的客户端,但不须要检查用户凭证。
  • 在其余状况下,第三方应用程序正在申请用户的公有数据,如电子邮件内容。REST API 必须辨认用户和他们的权力,但它可能不关怀哪个应用程序在调用 API。

REST API 安全性

RESTful API 提供了另一种拜访和操作你的应用程序的路径。即便它不是一个引人注目的黑客指标,一个行为不良的客户端也可能每秒发送数以千计的申请,并使你的服务器解体。

安全性超出了本文的范畴,但常见的最佳实际包含:

  • 应用 HTTPS。
  • 应用强壮的身份验证办法。
  • 应用 CORS 来限度客户端对特定域的调用。
  • 提供起码的性能,也就是不要创立不须要的 DELETE 选项。
  • 验证所有端点 URL 和 body 对象。
  • 防止在客户端 JavaScript 中裸露 API 令牌。
  • 阻止来自未知域名或 IP 地址的拜访。
  • 阻止意外的大型无效负载。
  • 思考速率限度,也就是应用同一 API 令牌或 IP 地址的申请被限度在每分钟 N 个以内。
  • 以适当的 HTTP 状态代码和缓存头进行响应。
  • 记录申请并考察失败状况。

多个申请和不必要的数据

RESTful APIs 受到其实现的限度。响应可能蕴含比你须要的更多的数据,或者须要进一步的申请来拜访所有数据。

思考一个 RESTful API,它提供对作者和书籍数据的拜访。为了显示前 10 名畅销书的数据,客户端能够:

  • 申请按销售量数量订购的前 10/book/的详细信息(最滞销的在前)。响应蕴含有每个作者 ID 的书籍列表。
  • 最多组成 10 个 /author/{id} 申请以获取每个作者的详细信息。

这被称为N+ 1 问题;必须为父申请中的每个后果提出 N 个 API 申请。

为了防止不必要的大的响应,能够调整 API 使作者的细节是可选的。例如,?author_details=full。API 作者须要满足的选项的数量可能会变得令人困惑。

GraphQL 是否更好?

REST 的难题导致 Facebook 创立了 GraphQL– 一种网络服务查询语言。把它看作是网络服务的 SQL:一个繁多的申请定义了你所须要的数据以及你心愿它如何返回。

GraphQL 解决了 RESTful APIs 带来的一些挑战,只管它引入了其余挑战。例如,很难对 GraphQL 响应进行缓存。

你的客户不太可能有与 Facebook 相似的问题,所以一旦 RESTful API 倒退到超出其理论限度时,GraphQL 可能值得思考。

REST API 链接和开发工具

有许多工具能够帮忙所有语言的 RESTful API 开发。值得注意的选项包含:

  • Swagger:帮忙设计、记录、模仿、测试和监控 REST APIs 的各种工具。
  • Postman:一个 RESTful API 测试应用程序。
  • Hoppscotch:一个开源的、基于 web 的 Postman 替代品。

还有大量的公共 REST API,汇合了笑话、货币转换、天文编码、政府数据以及你能想到的每一个主题。许多是收费的,只管有些须要你注册一个 API 密钥或应用其余认证办法。分类列表包含:

  • Any API
  • API list
  • Public APIs
  • Google APIs Explorer

在实现你本人的网络服务之前,在你本人的我的项目中尝试应用一些 RESTful API。或者思考追随 Facebook、GitHub、Google 和其余许多巨头的脚步,建设一个属于本人的 RESTful API。

下一篇文章中,会翻译分享 13 个构建 RESTful API 的最佳实际,欢送关注。

以上就是全部内容,如果对你有所帮忙,欢送点赞珍藏转发~

退出移动版