一个没有框架(如Express)的香草式Node.js REST API
Node.js是一个非常流行的JavaScript框架。它在用于构建后端服务和API时最为闪亮。Node.js开发者经常利用开源框架和库(如Express.js)来开发应用程序。这些库在NPM注册表中是现成的。
每当你使用这些包时,就会有很多抽象;因此你不会利用Node.js的核心功能。你的应用程序的低级逻辑Node.js是隐藏的,因为这些包在幕后处理和执行原始Node.js。
需要注意的一个关键问题是,这些包使Node.js成为一种流行的技术。在另一边,你可以选择使用核心Node.js来开发你的应用程序。这样一来,你就可以利用Vanilla Node.js的功能。本博客将教你如何使用没有框架的vanilla Node.js来构建简单的API。
目标
在本指南中,我们将使用Node.js本身的核心功能构建一个简单的REST API。我们只是使用原始的[Node.js]和[HTTP模块]来创建和管理一个服务器。
这意味着我们将不使用NPM。因此,没有NPM相关的依赖,没有package.json ,没有package-lock.json ,也没有node_module 文件夹。
我们的目标是向你展示Node.js如何以最纯粹的形式工作,以及你如何在没有外部库或框架的情况下使用它。
注意:在任何实际项目中工作时,最好使用Node.js库和包。这样,你将充分利用现成的代码,使你的开发工作流程更简单、更快速。
前提条件
- 确保你的电脑上安装了[Node.js]和[Postman]。
- 熟悉如何使用[Postman]。
- 对[Node.js]有基本了解。
- 对[REST APIs]和[CRUD操作]的基本了解。
- 对[JavaScript]的基本了解。本指南使用[ES6]功能和语法,如[箭头函数](=>)。
设置一个简单的HTTP服务器
在创建REST API之前,我们先创建一个简单的HTTP API,为Hi there语句提供服务。
创建一个项目文件夹和一个app.js 文件。
- 首先要做的是使用
require()方法从Node.js拉出HTTP模块。这个模块是Node.js的原生模块。你不需要任何额外的包或库来访问它,只需要在你的计算机上安装Node.js运行时间。
const http = require("http");
这样,我们使必要的方法和功能可用来建立一个服务器。
- 一旦可用,定义你希望服务器运行的端口,如下图所示。
const PORT = process.env.PORT || 5000;
- 为了创建服务器,你需要从HTTP模块中调用
createServer方法。即:http.createServer。传递一个响应和一个请求,提供你的信息。
然后使用。
req.url来设置请求的访问路线/URL。req.method.res.writeHead设置任何响应头信息。res.write()发送响应的实际内容。res.end()来结束响应。
const server = http.createServer(async (req, res) => {
//set the request route
if (req.url === "/api" && req.method === "GET") {
//response headers
res.writeHead(200, { "Content-Type": "application/json" });
//set the response
res.write("Hi there, This is a Vanilla Node.js API");
//end the response
res.end();
}
// If no route present
else {
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ message: "Route not found" }));
}
});
- 调用
listen()方法并传入PORT变量。然后添加一个console.log()信息,表明服务器已经启动并运行。
server.listen(PORT, () => {
console.log(`server started on port: ${PORT}`);
});
- 服务器已经设置好了。运行
node app.js来测试。这将在你的命令屏幕上记录console.log()消息。

- 如果你在浏览器上打开
http://localhost:5000/api,你将会得到在 中定义的响应。res.write()

设置REST API
现在让我们看看如何使用原始Node.js设置REST API。我们将使用一个todos模板来演示。
下面是项目的结构。
\---vanilla-nodejs-rest-api
| app.js
| controller.js
| data.js
| utils.js
No sub-folders exist
添加测试数据
data.js: 保存一些临时测试数据。这些信息被保存在一个todos数组中。每个todo都有一个唯一的ID,一个todo标题,一个简短的描述,以及一个标志着完成todo的布尔值。
//data.js
/** Todos List*/
const todos = [
{
id: 1,
title: "Coding in Javascript",
description: "Working with functions in JavaScript",
completed: false,
},
{
id: 2,
title: "Cooking Supper",
description: "Preparing rice and chicken",
completed: false,
},
{
id: 3,
title: "Taking a walk",
description: "Easy time at the park",
completed: false,
},
{
id: 4,
title: "Watching Netflix",
description: "Enjoying the new premiered series",
completed: false,
},
];
module.exports = todos;
设置控制器
controllers.js:它管理本应用程序中使用的每个路由背后的实际功能和逻辑。它是由Controller 类组成的,它将有以下主要的HTTP方法。
getTodos(): 获取并列出临时data.js文件中列出的所有todos。getTodo(): 获取并列出一个单一的todo的唯一ID。createTodo():创建一个新的临时todo。updateTodo(): 更新现有todo的值。deleteTodo():从列表中删除一个todo。
// controller.js
// Logic behind the functionalities
const data = require("./data");
class Controller {
// getting all todos
async getTodos() {
// return all todos
return new Promise((resolve, _) => resolve(data));
}
// getting a single todo
async getTodo(id) {
return new Promise((resolve, reject) => {
// get the todo
let todo = data.find((todo) => todo.id === parseInt(id));
if (todo) {
// return the todo
resolve(todo);
} else {
// return an error
reject(`Todo with id ${id} not found `);
}
});
}
// creating a todo
async createTodo(todo) {
return new Promise((resolve, _) => {
// create a todo, with random id and data sent
let newTodo = {
id: Math.floor(4 + Math.random() * 10),
...todo,
};
// return the new created todo
resolve(newTodo);
});
}
// updating a todo
async updateTodo(id) {
return new Promise((resolve, reject) => {
// get the todo.
let todo = data.find((todo) => todo.id === parseInt(id));
// if no todo, return an error
if (!todo) {
reject(`No todo with id ${id} found`);
}
//else, update it by setting completed to true
todo["completed"] = true;
// return the updated todo
resolve(todo);
});
}
// deleting a todo
async deleteTodo(id) {
return new Promise((resolve, reject) => {
// get the todo
let todo = data.find((todo) => todo.id === parseInt(id));
// if no todo, return an error
if (!todo) {
reject(`No todo with id ${id} found`);
}
// else, return a success message
resolve(`Todo deleted successfully`);
});
}
}
module.exports = Controller;
实用程序设置
utils.js。控制一个标准的Web API用例。它包括getReqData() 函数,该函数从服务器上的客户端检索数据。
//utils.js
function getReqData(req) {
return new Promise((resolve, reject) => {
try {
let body = "";
// listen to data sent by client
req.on("data", (chunk) => {
// append the string version to the body
body += chunk.toString();
});
// listen till the end
req.on("end", () => {
// send back the data
resolve(body);
});
} catch (error) {
reject(error);
}
});
}
module.exports = { getReqData };
设置服务器和路由
app.js:这包含了。
- 服务器的初始化和配置。
- 适当的路由监听服务器的不同的HTTP方法。
- 一个用于监听的端口号,并在浏览器上设置服务器。
//app.js
const http = require("http");
const Todo = require("./controller");
const { getReqData } = require("./utils");
const PORT = process.env.PORT || 5000;
const server = http.createServer(async (req, res) => {
// /api/todos : GET
if (req.url === "/api/todos" && req.method === "GET") {
// get the todos.
const todos = await new Todo().getTodos();
// set the status code, and content-type
res.writeHead(200, { "Content-Type": "application/json" });
// send the data
res.end(JSON.stringify(todos));
}
// /api/todos/:id : GET
else if (req.url.match(/\/api\/todos\/([0-9]+)/) && req.method === "GET") {
try {
// get id from url
const id = req.url.split("/")[3];
// get todo
const todo = await new Todo().getTodo(id);
// set the status code and content-type
res.writeHead(200, { "Content-Type": "application/json" });
// send the data
res.end(JSON.stringify(todo));
} catch (error) {
// set the status code and content-type
res.writeHead(404, { "Content-Type": "application/json" });
// send the error
res.end(JSON.stringify({ message: error }));
}
}
// /api/todos/:id : DELETE
else if (req.url.match(/\/api\/todos\/([0-9]+)/) && req.method === "DELETE") {
try {
// get the id from url
const id = req.url.split("/")[3];
// delete todo
let message = await new Todo().deleteTodo(id);
// set the status code and content-type
res.writeHead(200, { "Content-Type": "application/json" });
// send the message
res.end(JSON.stringify({ message }));
} catch (error) {
// set the status code and content-type
res.writeHead(404, { "Content-Type": "application/json" });
// send the error
res.end(JSON.stringify({ message: error }));
}
}
// /api/todos/:id : UPDATE
else if (req.url.match(/\/api\/todos\/([0-9]+)/) && req.method === "PATCH") {
try {
// get the id from the url
const id = req.url.split("/")[3];
// update todo
let updated_todo = await new Todo().updateTodo(id);
// set the status code and content-type
res.writeHead(200, { "Content-Type": "application/json" });
// send the message
res.end(JSON.stringify(updated_todo));
} catch (error) {
// set the status code and content type
res.writeHead(404, { "Content-Type": "application/json" });
// send the error
res.end(JSON.stringify({ message: error }));
}
}
// /api/todos/ : POST
else if (req.url === "/api/todos" && req.method === "POST") {
// get the data sent along
let todo_data = await getReqData(req);
// create the todo
let todo = await new Todo().createTodo(JSON.parse(todo_data));
// set the status code and content-type
res.writeHead(200, { "Content-Type": "application/json" });
//send the todo
res.end(JSON.stringify(todo));
}
// No route present
else {
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ message: "Route not found" }));
}
});
server.listen(PORT, () => {
console.log(`server started on port: ${PORT}`);
});
测试应用程序
Vanilla Node.js REST API现在已经设置好了,可以测试一下是否一切正常。现在你需要通过运行以下命令来启动服务器。
node app.js
这将在5000端口设置并运行服务器。

使用Postman探索API
让我们使用Postman来测试API中设置的不同方法。
取出所有的todos
/API/todos GET。这将获取data.js 中列出的所有todos。
要测试这个GET请求。
- 转到Postman并发送一个
GET请求。请求的URL为http://localhost:5000/api/todos,如下图所示。

- 这将在Postman的响应部分记录一个响应,其中包括所有的todos,如图所示。
data.js

通过id获取一个todo
/API/todos/:id GET。这将只获取一个以todo的id值指定的todo。
要测试这个GET请求。
- 转到Postman并发送一个
GET请求。输入请求的URL为http://localhost:5000/api/todos/:id,其中:id是你要获取的单个todo的id,如下图所示。

- 该请求将记录一个单一的todo到Postman响应部分。

DELETE一个todo
/API/todos/:id DELETE: 这将执行一个单一todo的DELETE 请求。你将只收到一个响应信息,因为数据是临时的,没有存储在数据库中。
为了测试它。
- 转到Postman并发送一个
DELETE请求。输入请求的URL为http://localhost:5000/api/todos/:id,其中:id是你想删除的单个todo的ID,如下图所示。

- 这将在你的Postman响应控制台中记录一个
Todo deleted successfully消息。

更新一个todo
/API/todos/:id PATCH:这将更新一个todo,表示任务已经完成,即true 或false 。你将在postman响应控制台看到效果。
要看看它的效果如何。
- 转到Postman并发送一个
PATCH请求。输入请求的URL为http://localhost:5000/api/todos/:id,其中:id是你要更新的单个todo的ID,如下图所示。

- Postman的响应控制台应该是这样的。

增加一个新的todo
/API/todos POST。这将创建一个新的todo项目。新的todo将作为一个响应被返回,但它不会被记录在data.js 。
要对它进行测试,请做以下工作。
- 转到Postman并打开一个新的标签,选择一个
POST请求并输入请求的URL为http://localhost:5000/api/todos。

转到Body 标签部分,选择raw ,并从右边的下拉选项中选择'JSON'。

- 添加新todo的内容(标题、描述和完成)。
下面是一个简单的说明。
{
"title": "Vannila Node.js REST API",
"description": "Working with responses and requests",
"completed": false
}
- 填写完上述细节后,点击SEND按钮开始POST请求,新添加的todo将被记录在Postman控制台。

注意:因为ID是随机生成的,所以每次你发出新的POST请求时,它可能会有所不同。
就这样:一个完全由Vannila Node.js编写的简单明了的REST API。我希望你能发现这个教程的指导性、信息性和帮助性。