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。我们只是使用带有HTTP 模块的vanilla Node.js的基本结构来创建和管理服务器。
这意味着我们不会使用 NPM。因此没有与 NPM 相关的依赖项、 no package.json
、 nopackage-lock.json
和 nonode_module
文件夹。
目标是向您展示 Node.js 如何以最纯粹的形式工作,以及如何在没有外部库或框架的情况下使用它。
注意:在处理任何实际项目时,最好使用 Node.js 库和包。这样,您将充分利用现成的代码,使您的开发工作流程更轻松、更快捷。
先决条件
- 确保您的计算机上安装了Node.js和Postman 。
- 熟悉如何使用Postman。
- Node.js的基础知识。
- 基本了解REST API和CRUD 操作。
- 对JavaScript的基本了解。本指南使用ES6特性和语法,例如箭头函数(=>)。
设置一个简单的 HTTP 服务器
在创建 REST API 之前,让我们创建一个简单的HTTP API来提供Hi there语句。
创建一个项目文件夹和一个app.js
文件。
- 首先要做的是使用方法从 Node.js中拉出HTTP 模块。
require()
这个模块是 Node.js 的原生模块。您不需要任何额外的包或库来访问它,只需在您的计算机上安装 Node.js 运行时。
const http = require("http");
这样,我们就可以使用必要的方法和功能来设置服务器。
- 一旦可用,定义您希望服务器运行的端口,如下所示。
const PORT = process.env.PORT || 5000;
- 要创建服务器,您需要
createServer
从 HTTP 模块调用该方法。即,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
文件中列出的所有待办事项。getTodo()
:通过其唯一 ID 获取和列出单个待办事项。createTodo()
:创建一个新的临时待办事项。updateTodo()
:更新现有待办事项的值。deleteTodo()
:从列表中删除待办事项。
// 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 中设置的不同方法。如果您不熟悉 Postman API 测试,请阅读本教程以开始使用。
获取所有待办事项
/API/todos GET:这将获取data.js
.
要测试这个 GET 请求:
- 转到邮递员并发送请求
GET
。请求网址http://localhost:5000/api/todos
如下图:
- 这将在 Postman 响应部分记录一个响应,其中列出了所有待办事项
data.js
通过 id 获取 todo
/API/todos/:id GET:这将只获取一个由 todo 的 id 值指定的 todo。
要测试这个 GET 请求:
- 转到邮递员并发送请求
GET
。输入请求 URL 为http://localhost:5000/api/todos/:id
,其中:id
是您要获取的单个 todo 的 id,如下所示。
- 该请求会将单个待办事项记录到 Postman 响应部分。
删除待办事项
/API/todos/:id DELETE:这将执行DELETE
单个 todo 的请求。您只会收到一条响应消息,因为数据是临时的并且没有存储在数据库中。
进行测试:
- 转到邮递员并发送请求
DELETE
。输入请求 URL 为http://localhost:5000/api/todos/:id
,其中:id
是你要删除的单个 todo 的 id,如下图。
- 这将
Todo deleted successfully
在您的 Postman 响应控制台中记录一条消息。
更新待办事项
/API/todos/:id PATCH:这将更新待办事项以指示任务已完成,即true
或false
。您将在邮递员响应控制台上看到效果。
要查看它的效果如何:
- 转到邮递员并发送请求
PATCH
。输入请求 URL 为http://localhost:5000/api/todos/:id
,其中:id
是您要更新的单个 todo 的 id,如下图所示。
- Postman 响应控制台应如下所示:
添加一个新的待办事项
/API/todos POST:这将创建一个新的待办事项。新的 todo 将作为响应返回,但不会记录在data.js
.
要对其进行测试,请执行以下操作:
- 转到 Postman 并打开一个新选项卡,选择一个
POST
请求并将请求 URL 输入为http://localhost:5000/api/todos
.
转到Body
选项卡部分,选择raw
,然后从右侧的下拉选项中选择“JSON”。
- 添加新待办事项的内容(标题、描述和已完成)。
这是一个简单的例子:
{
"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。我希望您发现本教程具有指导性、信息性和帮助性。