rest api 示例2_REST API教程– REST Client,REST Service和API调用通过代码示例进行了解释

杨曜瑞
2023-12-01

rest api 示例2

Ever wondered how login/signup on a website works on the back-end? Or how when you search for "cute kitties" on YouTube, you get a bunch of results and are able to stream off of a remote machine?

有没有想过网站上的登录/注册在后端如何工作? 或者,当您在YouTube上搜索“可爱的小猫”时,如何获得大量结果并能够流式传输到远程计算机?

In this beginner friendly guide, I will walk you through the process of setting up a RESTful API. We'll declassify some of the jargon and have a look at how we can code a server in NodeJS. Let's dive a bit deeper into JavaScript!

在本入门指南中,我将引导您完成设置RESTful API的过程。 我们将解密一些术语,并看看如何在NodeJS中编码服务器。 让我们更深入地研究JavaScript!

摆脱那个行话 (Get that jargon away)

So, what is REST? According to Wikipedia:

那么,什么是REST? 根据维基百科:

Representational state transfer (REST) is a software architectural style that defines a set of constraints to be used for creating Web services. RESTful Web services allow the requesting systems to access and manipulate textual representations of Web resources by using a uniform and predefined set of stateless operations

代表性状态转移 ( REST )是一种软件体系结构样式,它定义了一组用于创建Web服务的约束。 RESTful Web服务允许请求系统通过使用统一且预定义的无状态操作集来访问和操纵Web资源的文本表示形式

Let's demystify what that means (hopefully you got the full form). REST is basically a set of rules for communication between a client and server. There are a few constraints on the definition of REST:

让我们揭开其含义的神秘面纱(希望您获得了完整的表格)。 REST基本上是客户端和服务器之间通信的一组规则。 REST的定义有一些限制:

  1. Client-Server Architecture: the user interface of the website/app should be separated from the data request/storage, so each part can be scaled individually.

    客户端-服务器体系结构 :网站/应用程序的用户界面应与数据请求/存储区分开,因此每个部分都可以单独缩放。

  2. Statelessness: the communication should have no client context stored on server. This means each request to the server should be made with all the required data and no assumptions should be made if the server has any data from previous requests.

    无状态性 :通信不应在服务器上存储任何客户端上下文。 这意味着对服务器的每个请求都应包含所有必需的数据,并且如果服务器具有来自先前请求的任何数据,则不应进行任何假设。

  3. Layered system: client should not be able to tell if it is communicating directly with the server or some intermediary. These intermediary servers (be it proxy or load balancers) allow for scalability and security of the underlying server.

    分层系统 :客户端不应该知道客户端是否直接与服务器或某些中介进行通信。 这些中间服务器(无论是代理服务器还是负载平衡器)都可以实现基础服务器的可伸缩性和安全性。

Okay, so now that you know what RESTful services are, here are some of the terms used in the heading:

好的,现在您知道什么是RESTful服务,下面是该标题中使用的一些术语:

  1. REST Client: code or an app that can access these REST services. You are using one right now! Yes, the browser can act as an uncontrolled REST client (the website handles the browser requests). The browser, for a long time, used an in-built function called XMLHttpRequest for all REST requests. But, this was succeeded by FetchAPI, a modern, promise based approach to requests. Others examples are code libraries like axios, superagent and got or some dedicated apps like Postman (or an online version, postwoman!), or a command line tool like cURL!.

    REST客户端 :可以访问这些REST服务的代码或应用程序。 您正在使用一个! 是的,浏览器可以充当不受控制的REST客户端(网站处理浏览器请求)。 很长时间以来,浏览器对所有REST请求都使用了一个名为XMLHttpRequest的内置函数。 但是,这是通过FetchAPI成功实现的, FetchAPI是一种基于请求的现代承诺方法。 其他示例包括诸如axiossuperagentgot之类的代码库,或诸如Postman (或在线版本, postwoman !)之类的一些专用应用程序,或诸如cURL !之类的命令行工具。

  2. REST Service: the server. There are many popular libraries that make creation of these servers a breeze, like ExpressJS for NodeJS and Django for Python.

    REST服务 :服务器。 有许多流行的库使创建这些服务器变得轻而易举,例如ExpressJS for NodeJS和Django for Python。

  3. REST API: this defines the endpoint and methods allowed to access/submit data to the server. We will talk about this in great detail below. Other alternatives to this are: GraphQL, JSON-Pure and oData.

    REST API :这定义了允许访问/向服务器提交数据的端点和方法。 我们将在下面详细讨论。 其他替代方法是:GraphQL,JSON-Pure和oData。

所以现在告诉我,REST看起来如何? (So tell me now, how does REST look?)

In very broad terms, you ask the server for a certain data or ask it to save some data, and the server responds to the requests.

概括地说,您要求服务器提供某些数据或要求它保存一些数据,然后服务器会响应请求。

In programming terms, there is an endpoint (a URL) that the server is waiting to get a request. We connect to that endpoint and send in some data about us (remember, REST is stateless, no data about the request is stored) and the server responds with the correct response.

用编程的术语来说,有一个端点(URL),服务器正在等待获取请求。 我们连接到该端点并发送有关我们的一些数据(请记住,REST是无状态的,没有存储有关请求的数据),并且服务器以正确的响应进行响应。

Words are boring, let me give you a demonstration. I will be using Postman to show you the request and response:

话无聊,让我给你示范。 我将使用邮差向您显示请求和响应:

The returned data is in JSON (JavaScript Object Notation) and can be accessed directly.

返回的数据采用JSON(JavaScript对象表示法)格式,可以直接访问。

Here, https://official-joke-api.appspot.com/random_joke is called an endpoint of an API. There will be a server listening on that endpoint for requests like the one we made.

在这里, https://official-joke-api.appspot.com/random_joke称为API的端点。 将会有一个服务器在该端点上侦听类似我们发出的请求。

REST的剖析: (Anatomy of REST:)

Alright, so now we know that data can be requested by the client and the server will respond appropriately. Let's look deeper into how a request is formed.

好了,现在我们知道客户端可以请求数据了,服务器将做出适当的响应。 让我们更深入地了解请求的形成方式。

  1. Endpoint: I have already told you about this. For a refresher, it is the URL where the REST Server is listening.

    端点 :我已经告诉过你了。 对于复习,它是REST Server侦听的URL。

  2. Method: Earlier, I wrote that you can either request data or modify it, but how will the server know what kind of operation the client wants to perform? REST implements multiple 'methods' for different types of request, the following are most popular:

    方法 :之前,我写道您可以请求数据或对其进行修改,但是服务器如何知道客户端要执行哪种操作? REST为不同类型的请求实现了多种“方法”,以下是最受欢迎的方法:

    -

    --

    GET: Get resource from the server.

    GET :从服务器获取资源。

    -

    --

    POST: Create resource to the server.

    POST :为服务器创建资源。

    -

    --

    PATCH or PUT: Update existing resource on the server.

    PATCHPUT :更新服务器上的现有资源。

    -

    --

    DELETE: Delete existing resource from the server.

    删除 :从服务器删除现有资源。

    DELETE: Delete existing resource from the server.

    删除 :从服务器删除现有资源。

  3. Headers: The additional details provided for communication between client and server (remember, REST is stateless). Some of the common headers are:

    标头 :为客户端和服务器之间的通信提供的其他详细信息(请记住,REST是无状态的)。 一些常见的标头是:

    Headers: The additional details provided for communication between client and server (remember, REST is stateless). Some of the common headers are:Request:

    标头 :为客户端和服务器之间的通信提供的其他详细信息(请记住,REST是无状态的)。 一些常见的标头是: 请求:

    -

    --

    host: the IP of client (or from where request originated)

    host :客户端的IP(或发出请求的源)

    -

    --

    accept-language: language understandable by the client

    接受语言 :客户可以理解的语言

    -

    --

    user-agent: data about client, operating system and vendor

    用户代理 :有关客户端,操作系统和供应商的数据

    user-agent: data about client, operating system and vendorResponse:

    用户代理 :有关客户端,操作系统和供应商的数据响应

    -

    --

    status: the status of request or HTTP code.

    status :请求或HTTP代码的状态。

    -

    --

    content-type: type of resource sent by server.

    content-type :服务器发送的资源类型。

    -

    --

    set-cookie: sets cookies by server

    set-cookie :按服务器设置cookie

  4. Data: (also called body or message) contains info you want to send to the server.

    数据 :(也称为正文或消息)包含要发送到服务器的信息。

足够的细节-给我看代码。 (Enough with the details – show me the code.)

Let's begin coding a REST Service in Node. We will be implementing all the things we learnt above. We will also be using ES6+ to write our service in.

让我们开始在Node中编码REST服务。 我们将实现上面学到的所有东西。 我们还将使用ES6 +编写服务。

Make sure you have Node.JS installed and node and npm are available in your path. I will be using Node 12.16.2 and NPM 6.14.4.

确保已安装Node.JS,并且路径中的nodenpm都可用。 我将使用节点12.16.2和NPM 6.14.4。

Create a directory rest-service-node and cd into it:

创建一个目录rest-service-node并进入cd:

mkdir rest-service-node
cd rest-service-node

Initialize the node project:

初始化节点项目:

npm init -y

The -y flag skips all the questions. If you want to fill in the whole questionnaire, just run npm init.

-y标志跳过所有问题。 如果要填写整个问卷,只需运行npm init

Let's install some packages. We will be using the ExpressJS framework for developing the REST Server. Run the following command to install it:

让我们安装一些软件包。 我们将使用ExpressJS框架来开发REST Server。 运行以下命令进行安装:

npm install --save express body-parser

What's body-parser there for? Express, by default, is incapable of handling data sent via POST request as JSON. body-parser allows Express to overcome this.

body-parser有什么用? 默认情况下,Express无法处理通过POST请求以JSON格式发送的数据。 body-parser使Express可以克服这一问题。

Create a file called server.js and add the following code:

创建一个名为server.js的文件,并添加以下代码:

const express = require("express");
const bodyParser = require("body-parser");

const app = express();

app.use(bodyParser.json());

app.listen(5000, () => {
  console.log(`Server is running on port 5000.`);
});

The first two lines are importing Express and body-parser.

前两行将导入Express和body-parser。

Third line initializes the Express server and sets it to a variable called app.

第三行初始化Express服务器并将其设置为名为app的变量。

The line, app.use(bodyParser.json()); initializes the body-parser plugin.

该行app.use(bodyParser.json()); 初始化body-parser插件。

Finally, we are setting our server to listen on port 5000 for requests.

最后,我们将服务器设置为在端口5000上侦听请求。

从REST服务器获取数据: (Getting data from the REST Server:)

To get data from a server, we need a GET request. Add the following code before app.listen:

要从服务器获取数据,我们需要一个GET请求。 在app.listen之前添加以下代码:

const sayHi = (req, res) => {
  res.send("Hi!");
};

app.get("/", sayHi);

We have created a function sayHi which takes two parameters req and res (I will explain later) and sends a 'Hi!' as response.

我们创建了一个函数sayHi ,它带有两个参数reqres (我将在后面解释)并发送一个“ Hi!”。 作为回应。

app.get() takes two parameters, the route path and function to call when the path is requested by the client. So, the last line translates to: Hey server, listen for requests on the '/' (think homepage) and call the sayHi function if a request is made.

app.get()具有两个参数,即路由路径和客户端请求路径时要调用的函数。 因此,最后一行转换为:嘿,服务器,在“ /”(想想主页)上侦听请求,并在发出请求时调用sayHi函数。

app.get also gives us a request object containing all the data sent by the client and a response object which contains all the methods with which we can respond to the client. Though these are accessible as function parameters, the general naming convention suggests we name them res for response and req for request.

app.get还为我们提供了一个request对象,其中包含客户端发送的所有数据,以及一个response对象,其中包含我们可以用来响应客户端的所有方法。 尽管可以将它们作为函数参数进行访问,但一般的命名约定建议我们将它们分别命名为res代表responsereq代表request

Enough chatter. Let's fire up the server! Run the following server:

chat不休。 让我们启动服务器! 运行以下服务器:

node server.js

If everything is successful, you should see a message on console saying: Server is running on port 5000.

如果一切顺利,您应该在控制台上看到一条消息: 服务器正在端口5000上运行。

Note: You can change the port to whatever number you want.

注意:您可以将端口更改为所需的任何数字。

Open up your browser and navigate to http://localhost:5000/ and you should see something like this:

打开浏览器并导航到http://localhost:5000/ ,您应该看到类似以下内容:

There you go! Your first GET request was successful!

你去! 您的第一个GET请求成功!

将数据发送到REST服务器: (Sending data to REST Server:)

As we have discussed earlier, let's setup how we can implement a POST request into our server. We will be sending in two numbers and the server will return the sum of the numbers. Add this new method below the app.get :

如前所述,让我们设置如何在服务器中实现POST请求。 我们将发送两个数字,服务器将返回数字的总和。 在app.get下面添加此新方法:

app.post("/add", (req, res) => {
  const { a, b } = req.body;
  res.send(`The sum is: ${a + b}`);
});

Here, we will be sending the data in JSON format, like this:

在这里,我们将以JSON格式发送数据,如下所示:

{
    "a":5,
    "b":10
}

Let's get over the code:

让我们看一下代码:

On line 1, we are invoking the .post() method of ExpressJS, which allows the server to listen for POST requests. This function takes in the same parameters as the .get() method. The route that we are passing is /add, so one can access the endpoint as http://your-ip-address:port/add or in our case localhost:5000/add. We are inlining our function instead of writing a function elsewhere.

在第1行,我们正在调用。 ExpressJS的post()方法,该方法允许服务器侦听POST请求。 该函数采用与.get()方法相同的参数。 我们传递的路由是/add ,因此可以访问端点作为http://your-ip-address:port/add ,在我们的示例中是localhost:5000/add 。 我们内联函数,而不是在其他地方编写函数。

On line 2, we have used a bit of ES6 syntax, namely, object destructuring. Whatever data we send via the request gets stored and is available in the body of the req object. So essentially, we could've replaced line 2 with something like:

在第2行中,我们使用了一些ES6语法,即对象分解。 我们通过请求发送的任何数据都将存储起来,并在req对象的body中可用。 因此,从本质上讲,我们可以将第2行替换为:

const num1 = req.body.a;
const num2 = req.body.b;

On line 3, we are using the send() function of the res object to send the result of the sum. Again, we are using template literals from ES6. Now to test it (using Postman):

在第3行中,我们使用res对象的send()函数发送求和结果。 同样,我们使用ES6中的模板文字。 现在进行测试(使用Postman):

So we have sent the data 5 and 10 as a and b using them as the body. Postman attaches this data to the request and sends it. When the server receives the request, it can parse the data from req.body , as we did in the code above. The result is shown below.

因此,我们已将数据5和10作为ab发送,并使用它们作为正文。 邮递员将此数据附加到请求并发送。 当服务器接收到请求时,它可以像上面的代码一样解析来自req.body的数据。 结果如下所示。

Alright, the final code:

好了,最后的代码:

const express = require("express");
const bodyParser = require("body-parser");

const app = express();

app.use(bodyParser.json());

const sayHi = (req, res) => {
  res.send("Hi!");
};

app.get("/", sayHi);

app.post("/add", (req, res) => {
  const { a, b } = req.body;
  res.send(`The sum is: ${a + b}`);
});

app.listen(5000, () => {
  console.log(`Server is running on port 5000.`);
});

REST客户端: (REST Client:)

Okay, we have created a server, but how do we access it from our website or webapp? Here the REST client libraries will come in handy.

好的,我们已经创建了服务器,但是如何从我们的网站或Web应用程序访问它呢? REST客户端库将在这里派上用场。

We will be building a webpage which will contain a form, where you can enter two numbers and we will display the result. Let's start.

我们将构建一个包含表单的网页,您可以在其中输入两个数字并显示结果。 开始吧。

First, let's change the server.js a bit:

首先,让我们更改一下server.js

const path = require("path");
const express = require("express");
const bodyParser = require("body-parser");

const app = express();

app.use(bodyParser.json());

app.get("/", (req, res) => {
  res.sendFile(path.join(__dirname, "index.html"));
});

app.post("/add", (req, res) => {
  const { a, b } = req.body;
  res.send({
    result: parseInt(a) + parseInt(b)
  });
});

app.listen(5000, () => {
  console.log(`Server is running on port 5000.`);
});

We imported a new package path, which is provided by Node, to manipulate path cross-platform. Next we changed the GET request on '/' and use another function available in res, ie. sendFile, which allows us to send any type of file as response. So, whenever a person tries to navigate to '/', they will get our index.html page.

我们导入了Node提供的新程序包path ,以操纵跨平台的路径。 接下来,我们更改'/'上的GET请求,并使用res可用的另一个函数,即。 sendFile ,它允许我们发送任何类型的文件作为响应。 因此,每当有人尝试导航到“ /”时,他们都会获得我们的index.html页面。

Finally, we changed our app.post function to return the sum as JSON and convert both a and b to integers.

最后,我们更改了app.post函数以将总和作为JSON返回,并将ab都转换为整数。

Let's create an html page, I will call it index.html, with some basic styling:

让我们创建一个html页面,我将其称为index.html ,具有一些基本样式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>REST Client</title>
  </head>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .container {
      height: 100vh;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    form {
      display: flex;
      flex-direction: column;
      margin-bottom: 20px;
    }
    label,
    input[type="submit"] {
      margin-top: 20px;
    }
  </style>
  <body>
    <div class="container">
      <h1>Simple POST Form</h1>
      </h1>
      <form>
        <label>Number 1:</label>
        <input id="num1" type="number" />
        <label>Number 2:</label>
        <input id="num2" type="number" />
        <input type="submit" value="Add"/>
      </form>
      <div class="result">Click Add!</div>
    </div>
  </body>
</html>

Let's add a script tag just before the closing body tag, so we don't need to maintain a .js file. We will begin by listening for the submit event and call a function accordingly:

让我们在结束body标记之前添加一个script标记,所以我们不需要维护.js文件。 我们将从侦听submit事件开始,并相应地调用一个函数:

<script>
	document.addEventListener("submit", sendData);
</script>

First we need to prevent page refresh when the 'Add' button is clicked. This can be done using the preventDefault() function. Then, we will get the value of the inputs at that instant:

首先,我们需要在单击“添加”按钮时防止页面刷新。 可以使用preventDefault()函数来完成。 然后,我们将在那一刻获得输入的值:

function sendData(e) {
    e.preventDefault();
    const a = document.querySelector("#num1").value;
    const b = document.querySelector("#num2").value;
}

Now we will make the call to the server with both these values a and b. We will be using the Fetch API, built-in to every browser for this.

现在,我们将使用这两个值ab调用服务器。 我们将为此使用每个浏览器内置的Fetch API

Fetch takes in two inputs, the URL endpoint and a JSON request object and returns a Promise. Explaining them here will be out-of-bounds here, so I'll leave that for you.

Fetch接受两个输入,即URL端点和JSON请求对象,并返回Promise 。 在这里解释它们将超出范围,因此我将留给您。

Continue inside the sendData() function:

继续在sendData()函数内部:

fetch("/add", {
        method: "POST",
        headers: {
            Accept: "application/json",
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            a: parseInt(a),
            b: parseInt(b)
        })
    })
    .then(res => res.json())
    .then(data => {
        const {
            result
        } = data;
        document.querySelector(
            ".result"
        ).innerText = `The sum is: ${result}`;
    })
    .catch(err => console.log(err));

First we are passing the relative URL of the endpoint as the first parameter to fetch. Next, we are passing an object which contains the method we want Fetch to use for the request, which is POST in this case.

首先,我们将端点的相对URL作为要fetch的第一个参数。 接下来,我们传递一个对象,该对象包含希望Fetch用于请求的方法,在这种情况下为POST

We are also passing headers, which will provide information about the type of data we are sending (content-type) and the type of data we accept as response (accept).

我们还将传递headers ,该headers将提供有关我们正在发送的数据类型( content-type )和我们接受作为响应的数据类型( accept )的信息。

Next we pass body. Remember we typed the data as JSON while using Postman? We're doing kind of a similar thing here. Since express deals with string as input and processes it according to content-type provided, we need to convert our JSON payload into string. We do that with JSON.stringify(). We're being a little extra cautious and parsing the input into integers, so it doesn't mess up our server (since we haven't implemented any data-type checking).

接下来我们传递body 。 还记得我们在使用Postman时将数据键入为JSON吗? 我们在这里做类似的事情。 由于express将字符串作为输入处理,并根据提供的内容类型对其进行处理,因此我们需要将JSON有效负载转换为字符串。 我们使用JSON.stringify()做到这JSON.stringify() 。 我们要格外谨慎,将输入解析为整数,这样就不会弄乱我们的服务器(因为我们还没有实现任何数据类型检查)。

Finally, if the promise (returned by fetch) resolves, we will get that response and convert it into JSON. After that, we will get the result from the data key returned by the response. Then we are simply displaying the result on the screen.

最后,如果promise(通过获取返回)得到解决,我们将获得该响应并将其转换为JSON。 之后,我们将从响应返回的data键中获取结果。 然后,我们只是在屏幕上显示结果。

At the end, if the promise is rejected, we will display the error message on the console.

最后,如果承诺被拒绝,我们将在控制台上显示错误消息。

Here's the final code for index.html:

这是index.html的最终代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>REST Client</title>
  </head>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .container {
      height: 100vh;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    form {
      display: flex;
      flex-direction: column;
      margin-bottom: 20px;
    }
    label,
    input[type="submit"] {
      margin-top: 20px;
    }
  </style>
  <body>
    <div class="container">
      <h1>Simple POST Form</h1>
      </h1>
      <form>
        <label>Number 1:</label>
        <input id="num1" type="number" />
        <label>Number 2:</label>
        <input id="num2" type="number" />
        <input type="submit" value="Add"/>
      </form>
      <div class="result">Click Add!</div>
    </div>
    <script>
      document.addEventListener("submit", sendData);
      function sendData(e) {
        e.preventDefault();
        const a = document.querySelector("#num1").value;
        const b = document.querySelector("#num2").value;

        fetch("/add", {
          method: "POST",
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json"
          },
          body: JSON.stringify({
            a: parseInt(a),
            b: parseInt(b)
          })
        })
          .then(res => res.json())
          .then(data => {
            const { result } = data;
            document.querySelector(
              ".result"
            ).innerText = `The sum is: ${result}`;
          })
          .catch(err => console.log(err));
      }
    </script>
  </body>
</html>

I have spun up a little app on glitch for you to test.

我已经启动了一个小故障小应用程序供您测试。

结论: (Conclusion:)

So in this post, we learnt about REST architecture and the anatomy of REST requests. We worked our way through by creating a simple REST Server that serves GET and POST requests and built a simple webpage that uses a REST Client to display the sum of two numbers.

因此,在这篇文章中,我们了解了REST体系结构和REST请求的结构。 我们通过创建一个简单的REST服务器来处理GETPOST请求,并构建了一个使用REST Client显示两个数字之和的简单网页,从而完成了工作。

You can extend this for the remaining types of requests and even implement a full featured back-end CRUD app.

您可以将其扩展为其余类型的请求,甚至实现功能齐全的后端CRUD应用程序

I hope you have learned something from this. If you have any questions, feel free to reach out to me over twitter! Happy Coding!

希望您从中学到了一些东西。 如果您有任何疑问,请随时通过Twitter与我联系! 编码愉快!

翻译自: https://www.freecodecamp.org/news/rest-api-tutorial-rest-client-rest-service-and-api-calls-explained-with-code-examples/

rest api 示例2

 类似资料: