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的定義有一些限制:
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.
客戶端-服務器體系結構 :網站/應用程序的用戶界面應與數據請求/存儲區分開,因此每個部分都可以單獨縮放。
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.
無狀態性 :通信不應在服務器上存儲任何客戶端上下文。 這意味著對服務器的每個請求都應包含所有必需的數據,并且如果服務器具有來自先前請求的任何數據,則不應進行任何假設。
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服務,下面是該標題中使用的一些術語:
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是一種基于請求的現代承諾方法。 其他示例包括諸如axios , superagent和got之類的代碼庫,或諸如Postman (或在線版本, postwoman !)之類的一些專用應用程序,或諸如cURL !之類的命令行工具。
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。
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.
好了,現在我們知道客戶端可以請求數據了,服務器將做出適當的響應。 讓我們更深入地了解請求的形成方式。
Endpoint: I have already told you about this. For a refresher, it is the URL where the REST Server is listening.
端點 :我已經告訴過你了。 對于復習,它是REST Server偵聽的URL。
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.
PATCH或PUT :更新服務器上的現有資源。
-
--
DELETE: Delete existing resource from the server.
刪除 :從服務器刪除現有資源。
DELETE: Delete existing resource from the server.
刪除 :從服務器刪除現有資源。
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
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,并且路徑中的node
和npm
都可用。 我將使用節點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
,它帶有兩個參數req
和res
(我將在后面解釋)并發送一個“ 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
代表response
, req
代表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作為a
和b
發送,并使用它們作為正文。 郵遞員將此數據附加到請求并發送。 當服務器接收到請求時,它可以像上面的代碼一樣解析來自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返回,并將a
和b
都轉換為整數。
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.
現在,我們將使用這兩個值a
和b
調用服務器。 我們將為此使用每個瀏覽器內置的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服務器來處理GET
和POST
請求,并構建了一個使用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