Richardson成熟度模型 – RESTful API

Richardson成熟度模型 – RESTful API

Leonard Richardson开发了Richardson成熟度模型,根据API对REST约束的遵守程度来评分。具有高REST合规性评分的API被认为性能更优。

在确定服务的成熟度时,Richardson强调了三个主要因素。它们包括:

  • URI
  • HTTP方法
  • HATEOAS(超媒体)

URI: 统一资源标识符(URI)是Web技术用于标识Web上的资源的唯一字符序列。

HTTP METHODS: 超文本传输协议(HTTP)是一种用于传输超媒体文档的协议。HTTP客户端通过请求消息向服务器发送请求。HTTP定义了一组请求方法来指定对给定资源采取的操作。

  • GET: GET方法检索指定资源的表示。
  • POST: POST请求向服务器传输数据。
  • PUT: PUT方法替换资源的所有现有表示。
  • PATCH: PATCH请求对资源进行部分更改。
  • DELETE: DELETE方法删除指定的资源。

HATEOAS(超媒体作为应用状态引擎)指的是可发现性。客户端可以仅通过服务器的响应与REST API进行交互。它是自说明的超媒体。客户端无需引用任何文档即可与新API进行交互。

REST服务根据Richardson成熟度模型分为不同的成熟度级别。

  • Level 0
  • Level 1
  • Level 2
  • Level 3

LEVEL 0: POX沼泽

Level 0也经常被称为POX(Plain Old XML)。在0级成熟度上,HTTP只用作传输协议。对于0级成熟度服务,我们使用单个URL和单个HTTP方法。我们发送请求到相同的URI来获取和发布数据。只能使用POST方法。例如,一个公司可能有很多客户或用户。我们只有一个端点用于所有的客户。所有的操作都通过POST方法进行。

  • 获得数据的请求:POST http://localhost:8080/users
  • 发布数据的请求:POST http://localhost:8080/users

LEVEL 1: 基于多个URI的资源和单个动词

在Level 1中,每个资源映射到一个特定的URI。但是,只有一种HTTP方法(POST)用于检索和创建数据。例如,我们需要访问在公司工作的员工。

  • 将员工添加到特定部门: POST/department/<department-id>/employee
  • 访问特定员工: POST/department/<department-id>/employee/<employee-id>

LEVEL 2: 基于多个URI的资源和HTTP动词

在Level 2中,使用正确的HTTP动词发送请求。每个请求都返回一个正确的HTTP响应码。

例如:要获取公司的用户,我们发送一个包含URI的请求
http://localhost:8080/users 服务器会发送正确的响应200 OK。

LEVEL 3: HATEOS

Level 3是最高级别的。它结合了Level 2和HATEOS。它有助于自我文档化。HATEOS指引可以找到新的资源。想象一家中国餐馆作为类比。你点了面条,服务员给你带来了你点的菜,并解释你刚刚点的是什么以及你可以找到其他可供选择的菜品。因此,我们可以将所需的菜品视为JSON数据,而其他菜品则是超媒体。

当API达到级别4时,我们认为它是RESTful的。其他级别只是成为RESTful的阶梯。让我们按照Richardson的成熟模型创建一个RESTFUL API

方法: 我们将创建一个名为gfg-wiki的RESTFUL API。我们将插入文章并发送HTTP请求。在这个过程中,我们将获取、修改和删除文章。将使用Robo3T来进行数据库操作。将使用Postman发送请求。

为了在 node.js 中创建一个RESTFUL API,需要安装:

node: 一个JavaScript运行环境

  • 下载链接:https://nodejs.org/en/download/

Robo3t: MongoDB的GUI。我们将使用Robo3T来创建数据库。

  • 下载链接:https://robomongo.org/

Postman: 一个API开发和测试平台。

  • 下载链接:https://www.postman.com/

Visual Studio Code 或者(其他任何代码编辑器)

  • 下载链接:https://code.visualstudio.com/download

JSON 查看器的Chrome扩展

  • 下载链接:https://chrome.google.com/webstore/detail/json-viewer-pro/eifflpmocdbdmepbjaopkkhbfmdg

步骤1: 创建一个新的目录,进入终端,并通过以下命令初始化NPM。

npm init -y

Richardson成熟度模型 - RESTful API

步骤2: 安装 body-parser, mongoose, express

  • body-parser: 一个在处理请求之前负责解析传入请求体的中间件。
  • express: node.js 框架。
  • mongoose : Mongoose 将 MongoDB 连接到 Express Web 应用程序。
npm i body-parser mongoose express

Richardson成熟度模型 - RESTful API

步骤3: 在当前目录中创建一个 app.js文件 并设置服务器。我们将导入包到我们的项目中并配置服务器。

app.js

// app.js file 
// Setting up the server  
  
// jshint esversion:6 
  
const express = require("express"); 
const bodyParser = require("body-parser"); 
const mongoose = require('mongoose'); 
  
const app = express(); 
  
app.use(bodyParser.urlencoded({ 
    extended: true
})); 
app.use(express.static("public")); 
  
app.listen(3000, function() { 
    console.log("Server started on port 3000"); 
}); 

步骤4: 在Robo3T上创建一个数据库。考虑一个包含标题和内容的文章数据库。

{   
“title” : “gfg”,   
“content” : “GeeksforGeeks是一个针对计算机科学极客的门户网站。”   
}   
{   
“title” : “REST”,   
“content” : “REST代表REpresentational State Transfer。”   
{   
“title” : “API”,   
“content” : “应用程序编程接口”   
}   
{   
“title” : “richardson-model”,   
“content” : ”根据REST约束对API进行评分”   
}   
{   
“title” : “Http”,   
“content” : “超文本传输协议(HTTP)是一种用于传输超媒体文档的协议。”   
} 
  • 进入Robo3t并创建一个新的连接。
  • 通过点击新连接按钮创建一个名为 gfg-wiki 的数据库。
  • 将创建一个名为 ‘gfg-wiki’ 的数据库。现在点击它并创建一个名为 ‘articles’ 的新集合。
  • 要插入文档,请点击articles并选择插入文档。
  • 逐个复制上述每个文档并插入。
  • 要查看所有文档,请点击articles。

如您所见,数据库的结构如下所示:

Richardson成熟度模型 - RESTful API

下面展示如何创建数据库并插入文档。

Richardson成熟度模型 - RESTful API

步骤5: 设置MongoDB并编写文章的模式以创建模型。要设置MongoDB,我们将使用mongoose。我们将连接我们的应用程序到MongoDB的位置,并将数据库名称添加到URL字符串中。默认情况下,MongoDB使用端口27017。

mongoose.connect("mongodb://localhost:27017/gfg-wiki", {useNewUrlParser: true});

模式定义了我们的集合的结构。我们将创建一个名为articleSchema的模式,其中包含两个字段-文章的标题和内容。

const articleSchema = {
  title: String,
  content: String
};

现在我们将从articleSchema创建一个模型

const Article = mongoose.model("Article", articleSchema);

将以下代码添加到app.js文件中现有的代码中。

app.js

const express = require("express"); 
const bodyParser = require("body-parser"); 
const mongoose = require('mongoose'); 
  
const app = express(); 
  
app.use(bodyParser.urlencoded({ 
    extended: true
})); 
app.use(express.static("public")); 
  
  
// connecting gfg-wiki database to our express application  
mongoose.connect("mongodb://localhost:27017/gfg-wiki", 
    { useNewUrlParser: true }); 
  
// Writing schema for articles collection 
const articleSchema = { 
    title: String, 
    content: String 
}; 
  
//creating a model around articleSchema 
const Article = mongoose.model("Article", articleSchema); 
  
  
  
app.listen(3000, function() { 
    console.log("Server started on port 3000"); 
});

步骤6: 通过GET方法访问所有文章。我们可以通过发送GET请求,指定资源的路径和处理请求的回调函数来获取所有文章。

app.get(route, (req,res)=>{
})

要检索所有文章,我们必须从数据库中查找并阅读文章。

<ModelName>.find({conditions},function(err,results){
//using the result 
});

将以下代码添加到您现有的 app.js 文件中。

// Fetching all the articles  
app.get("/articles", (req, res) => { 
    Article.find((err, foundArticles) => { 
        if (!err) { 
            res.send(foundArticles) 
        } else { 
            res.send(err); 
        } 
    }) 
})

通过运行以下命令开始您的应用程序

node app.js

输出: 我们可以在localhost:3000/articles访问文章。

Richardson成熟度模型 - RESTful API

步骤7: 使用POST方法创建一个新的文章。我们将创建一个将添加到数据库中的新文章。在这里,客户端向服务器发送数据。

我们还没有前端界面,但是我们有一个可以访问数据库的服务器。我们将使用Postman来测试我们的API,而不是创建一个表单或前端界面。我们的目标是向服务器发送POST请求。

我们将使用POST方法:

app.post(route,(req,res)=>{
    ...
})

一旦客户端发送了POST请求,我们需要通过req.body获取该数据。

转到Postman,向localhost:3000/articles发送一个POST请求。在body选项卡下,更改编码为form-url编码,并在键中添加标题和内容,以及表示我们想要与请求一起发送的数据的值。

标题 HTTP动词
内容 最常见的HTTP动词是POST,GET,PUT,PATCH和DELETE。

我们需要将这篇文章保存在我们的数据库中。

const <constantName>=new <ModelName>({
<fieldName>:<fielddata>,..
}); 

将以下代码添加到app.js文件中的先前代码中

app.js

// Posting a new article  
app.post("/articles", (req, res) => { 
  
    const newArticle = new Article({ 
        title: req.body.title, 
        content: req.body.content 
    }); 
  
    // Saving the article  
    newArticle.save(function(err) { 
        if (!err) { 
            res.send("Successfully added a new article."); 
        } else { 
            res.send(err); 
        } 
    }); 
}) 

重新启动您的服务器并使用postman发送POST请求。

输出: 转到Robo3T并刷新您的集合以查看添加的文章。现在我们有一个额外的条目。

Richardson成熟度模型 - RESTful API

步骤8: 获取特定文章。

我们将使用findOne方法从数据库中读取特定文章。

 <ModelName>.findone({conditions},(req,res)=>{
});

在这里,我们将使用标题为REST的文章。

在你的app.js文件中添加以下代码。

app.js

// Fetching a specific article 
app.get("/articles/:articleTitle", function(req, res) { 
  
    Article.findOne({ title: req.params.articleTitle },  
        function(err, foundArticle) { 
        if (foundArticle) { 
            res.send(foundArticle); 
        } else { 
            res.send("No articles matching that title was found."); 
        } 
    }); 
}) 

结果 :我们将在URL中指定文章标题,标题匹配的文章将被显示。

Richardson成熟度模型 - RESTful API

步骤9 :使用PUT方法覆盖文章。

我们希望提交一篇文章的新版本。为了替换现有的文章,我们将发送一个PUT请求。

app.put(route ,(req,res)=>{
    ...
});

我们将使用Mongoose的更新方法更新文章。

覆盖指定我们想要替换整篇文章。

<ModelName>.update(
    {conditions},
    {updates},
    {overwrite:true}
    (err,results)=>{
})

将以下代码添加到您的app.js文件中:

app.js

// Replacing a specific article  
app.put("/articles/:articleTitle", (req, res) => { 
    Article.updateOne({ title: req.params.articleTitle },  
        { title: req.body.title, content: req.body.content }, 
        { overwrite: true }, 
        function(err) { 
            if (!err) { 
                res.send("Successfully updated the selected article."); 
            } 
        } 
    ); 
})

在这种情况下,我们将把标题从API更改为Postman,将其内容从应用程序编程接口更改为Postman是一个API平台。

title: Postman
content: Postman is an API platform 

通过向路由localhost:3000/articles/API发送一个put请求

如果服务器找到一个标题为API的参数,它将用新标题替换标题,并用新内容替换内容。

Richardson成熟度模型 - RESTful API

步骤9: 使用PATCH方法更新文章。

我们将使用标题来发送一个PATCH请求来更新现有的文章。要更新文章,我们必须在body标签中提供要更改的字段。

现在我们只更改文章的一个字段而不是整个文章,当我们调用更新方法来更新数据库时,不需要使用覆盖方法。要更新文章,我们必须在body标签中提供要更改的字段。

在你的app.js文件中添加以下代码来修改文章。

app.js

// Updating an article  
app.patch("/articles/:articleTitle", function(req, res) { 
  
    Article.update({ title: req.params.articleTitle },  
        { $set: req.body }, 
        function(err) { 
            if (!err) { 
                res.send("Successfully updated article."); 
            } else { 
                res.send(err); 
            } 
        } 
    ); 
})

输出 :它仅更新我们提供的字段。文章标题REST已更新为Restful。

Richardson成熟度模型 - RESTful API

步骤10: 使用DELETE方法删除所有文章。

要从我们的数据库中删除所有文章,我们将使用deleteMany mongoose方法,并从postman发送一个删除请求。

将以下代码添加到您的app.js文件中

app.js

// Deleting all the articles 
app.delete("/articles", function(req, res) { 
  
    Article.deleteMany(function(err) { 
        if (!err) { 
            res.send("Successfully deleted all articles."); 
        } else { 
            res.send(err); 
        } 
    }); 
}); 

输出: 我们将发送一个删除请求到 localhost:3000/articles,以删除我们所有的文章。访问 Robo3T 并刷新您的集合。如果我们从 Postman 发送一个删除请求,我们将不会看到任何文章。

Richardson成熟度模型 - RESTful API

最终的 app.js 文件:

app.js

// app.js file 
// Setting up the server  
  
// jshint esversion:6 
  
const express = require("express"); 
const bodyParser = require("body-parser"); 
const mongoose = require('mongoose'); 
  
const app = express(); 
  
app.use(bodyParser.urlencoded({ 
    extended: true
})); 
app.use(express.static("public")); 
  
  
//Connecting gfg-wiki database to our express application  
mongoose.connect("mongodb://localhost:27017/gfg-wiki", 
    { useNewUrlParser: true }); 
  
// Writing schema for articles collection 
const articleSchema = { 
    title: String, 
    content: String 
}; 
  
// Creating a model around articleSchema 
const Article = mongoose.model("Article", articleSchema); 
  
// Fetching all the articles  
app.get("/articles", (req, res) => { 
    Article.find((err, foundArticles) => { 
        if (!err) { 
  
            res.send(foundArticles) 
        } else { 
            res.send(err); 
        } 
    }) 
}) 
  
// Posting a new article  
app.post("/articles", (req, res) => { 
  
    const newArticle = new Article({ 
        title: req.body.title, 
        content: req.body.content 
    }); 
  
    // Saving the article  
    newArticle.save(function(err) { 
        if (!err) { 
            res.send("Successfully added a new article."); 
        } else { 
            res.send(err); 
        } 
    }); 
}) 
  
// Fetching a specific article  
  
app.get("/articles/:articleTitle", function(req, res) { 
  
    Article.findOne({ title: req.params.articleTitle }, 
        function(err, foundArticle) { 
        if (foundArticle) { 
            res.send(foundArticle); 
        } else { 
            res.send("No articles matching that title was found."); 
        } 
    }); 
}) 
  
// Replacing a specific article  
app.put("/articles/:articleTitle", function(req, res) { 
  
    Article.update({ title: req.params.articleTitle },  
        { title: req.body.title, content: req.body.content }, 
        { overwrite: true }, 
        function(err) { 
            if (!err) { 
                res.send("Successfully updated the selected article."); 
            } 
        } 
    ); 
}) 
  
// Modifying an article  
app.patch("/articles/:articleTitle", function(req, res) { 
  
    Article.update({ title: req.params.articleTitle },  
        { $set: req.body }, 
        function(err) { 
            if (!err) { 
                res.send("Successfully updated article."); 
            } else { 
                res.send(err); 
            } 
        } 
    ); 
}) 
  
// Deleting all the articles  
app.delete("/articles", function(req, res) { 
  
    Article.deleteMany(function(err) { 
        if (!err) { 
            res.send("Successfully deleted all articles."); 
        } else { 
            res.send(err); 
        } 
    }); 
}); 
  
  
app.listen(3000, function() { 
    console.log("Server started on port 3000"); 
});

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程