Rest API 最佳设计实践( 二 )

  • DELETE 删除数据 。
  • 动词映射到CRUD操作 。
    考虑到我们上面讨论的两个原则,我们应该创建像 GET 这样的路由/articles/来获取新闻文章 。同样,POST/articles/用于添加新文章,PUT/articles/:id用于使用给定的更新文章id 。DELETE/articles/:id用于删除具有给定 ID 的现有文章 。
    /articles表示 REST API 资源 。例如,我们可以使用 Express 添加以下端点来操作文章,如下所示:
    const express = require('express');const bodyParser = require('body-parser');const app = express();app.use(bodyParser.json());app.get('/articles', (req, res) => {  const articles = [];  // code to retrieve an article...  res.json(articles);});app.post('/articles', (req, res) => {  // code to add a new article...  res.json(req.body);});app.put('/articles/:id', (req, res) => {  const { id } = req.params;  // code to update an article...  res.json(req.body);});app.delete('/articles/:id', (req, res) => {  const { id } = req.params;  // code to delete an article...  res.json({ deleted: id });});app.listen(3000, () => console.log('server started'));在上面的代码中,我们定义了操作文章的端点 。正如我们所见,路径名中没有任何动词 。我们只有名词 。动词在 HTTP 动词中 。
    POST、PUT 和 DELETE 端点都将 JSON 作为请求体,它们都返回 JSON 作为响应,包括 GET 端点 。
    在端点上使用逻辑嵌套在设计端点时,将包含相关信息的端点分组是有意义的 。也就是说,如果一个对象可以包含另一个对象,您应该设计端点来反映这一点 。无论您的数据在数据库中的结构是否如此,这都是一种很好的做法 。事实上,避免在端点中镜像数据库结构以避免给攻击者提供不必要的信息可能是明智的 。
    例如,如果我们希望端点获取新闻文章的评论,我们应该将/comments路径附加到路径的末尾/articles 。我们可以在 Express 中使用以下代码来做到这一点:
    const express = require('express');const bodyParser = require('body-parser');const app = express();app.use(bodyParser.json());app.get('/articles/:articleId/comments', (req, res) => {  const { articleId } = req.params;  const comments = [];  // code to get comments by articleId  res.json(comments);});app.listen(3000, () => console.log('server started'));在上面的代码中,我们可以在 path 上使用 GET 方法'
    /articles/:articleId/comments' 。我们获取comments由标识的文章articleId,然后在响应中返回它 。我们'comments'在'/articles/:articleId'路径段之后添加以表明它是 的子资源/articles 。
    这是有道理的,因为comments是 的子对象articles,假设每篇文章都有自己的评论 。否则,用户会感到困惑,因为这种结构通常被认为是用于访问子对象 。同样的原则也适用于 POST、PUT 和 DELETE 端点 。它们都可以对路径名使用相同类型的嵌套结构 。
    但是,嵌套可能会走得太远 。在大约第二或第三级之后,嵌套端点可能会变得笨拙 。相反,请考虑将 URL 返回到这些资源,特别是如果该数据不一定包含在顶级对象中 。
    例如,假设您想返回特定评论的作者 。你可以使用
    /articles/:articleId/comments/:commentId/author. 但这已经失控了 。而是在 JSON 响应中返回该特定用户的 URI:
    "author": "/users/:userId"
    优雅地处理错误并返回标准错误代码为了在错误发生时消除 API 用户的困惑,我们应该优雅地处理错误并返回指示发生了哪种错误的 HTTP 响应代码 。这为 API 的维护者提供了足够的信息来了解发生的问题 。我们不希望错误导致我们的系统崩溃,所以我们可以不处理它们,这意味着 API 使用者必须处理它们 。
    常见的错误 HTTP 状态代码包括:
    • 400 Bad Request – 这意味着客户端输入验证失败 。
    • 401 Unauthorized – 这意味着用户无权访问资源 。它通常在用户未通过身份验证时返回 。
    • 403 Forbidden - 这意味着用户已通过身份验证,但不允许访问资源 。
    • 404 Not Found – 这表示未找到资源 。
    • 500 内部服务器错误 – 这是一般的服务器错误 。它可能不应该明确抛出 。
    • 502 Bad Gateway - 这表示来自上游服务器的无效响应 。
    • 503 Service Unavailable - 这表明服务器端发生了意外(可能是服务器过载,系统某些部分发生故障等) 。
    我们应该抛出与我们的应用程序遇到的问题相对应的错误 。例如,如果我们想拒绝来自请求负载的数据,那么我们应该在 Express API 中返回一个 400 响应,如下所示:


    推荐阅读