使用 PostgreSQL 开发 CRUD Node.js 应用程序
嘿所有编码员!你好吗?今天我们将开始一系列文章,我们将使用 Node.js 和 PostgreSQL 开发一个 CRUD 应用程序,重点是后端。之后,我们将使用 Azure Functions 将项目迁移到无服务器架构,将本地数据库迁移到 Azure PostgreSQL,最后使用 [GitHub Actions]部署此应用程序(https://docs.microsoft.com/azure/app-service/deploy-github-actions?WT.mc_id=javascript-11915-gllemos)。
我在 GitHub HERE 上创建了一个仓库,这里分配了这个项目的所有源代码以及我将在 5 篇文章中提到的资源。
更新的存储库 HERE。
重要信息:项目的重点将放在后端。如果在项目结束时,我们想测试在前端的某个应用程序中创建的后端 API,那么我可以创建一个通用前端来测试创建的 api!
好吧,我说了很多,我们走吧?!
目录
-
教程中使用的资源
-
安装 PostgreSQL 数据库
-
在 PostgreSQL 中创建表
-
在 Node.js 中创建应用程序架构
-
开发应用程序
-
了解更多关于包的信息:'node-postgres'
-
使用“dotenv”创建环境变量
-
在文件中配置到数据库的连接字符串:'database.js'
-
路线:(POST)'创建产品'
-
路由:(GET) '列出所有产品'
-
路线:(GET) 'List Product by Id'
-
路线:(PUT)“按 ID 更新产品”
-
路线:(DELETE) '按 ID 删除产品'
-
结论
教程中使用的资源
我将在本文中提到一些我们将在开发此应用程序期间使用的资源。他们来了:
-
Visual Studio 代码
-
Node.js
-
邮递员
-
包 - node-postgres
-
PostgreSQL
吸引许多开发人员使用 PostgreSQL 的一件事是它完全免费,可在任何操作系统上使用,最重要的是:它完全是 开源! Uber、Netflix、Spotify、Instagram、Reddit 等无数大公司都在使用 PostgreSQL。这就是 PostgreSQL 如此受欢迎的原因!
PostgreSQL 是我学会使用的第一个数据库,2012 年我在大学的数据库 I 和 II 课程中学习了它。我一直很喜欢 PostgreSQL,因为它非常简单易用!
我们需要在我们的机器上安装 PostgreSQL。但也可以随意使用一些 Docker 映像来继续本教程。
安装PostgreSQL数据库
好吧,我在这里教你如何为不同的操作系统用户安装 PostgreSQL:
-
Windows:对于 Windows 用户,下载 Postgres for Windows 。常见且简单的安装,就像在 Windows 上安装程序一样。
-
macOS:对于 Mac 用户,只需下载软件包 HERE。此外,您需要安装 Homebrew。如果您在安装时遇到一些问题或困难,我建议您观看此视频 HERE
-
Linux:对于 Linux 用户,由于 Linux 有无数不同的版本,我建议你看看这个 PostgreSQL 指南 HERE
就我而言,我将使用 Windows,因为它是我的主要开发机器。我将使用 PostgreSQL 版本 12。安装后,只需搜索 pgAdmin。 http://127.0.0.1:16450/browser/ 上会打开一个浏览器页面,现在我们可以开始使用了!

在PostgreSQL中创建表
我们现在将创建具有属性的表,这些属性将用于持久化以在我们的后端中使用。
班级将是:Product
Class: Product
- productId: integer primary
- product_name_: varchar
- quantity: int
- price: real
进入全屏模式 退出全屏模式
现在打开 PgAdmin。您可能需要包含密码才能在 PgAdmin 中执行某些操作。您可能需要创建一个数据库。只需使用您想要的名称创建即可。创建数据库后,右键单击 Create Script,然后在 PostgreSQL 上运行以下脚本(如下 gif 所示):
CREATE TABLE products (
productId SERIAL PRIMARY KEY,
productName VARCHAR(255) NOT NULL,
quantity INTEGER NOT NULL,
price NUMERIC(5,2)
);
进入全屏模式 退出全屏模式

现在,您所要做的就是访问新创建的表!

伟大的!我们已经创建了我们的表!
在 Node.js 中创建应用程序架构
现在我们的表已经创建好了,让我们在 Node.js 中创建项目。在这个项目中,我将遵循 SOLID & Clean Code 原则。如果您想了解更多关于这两个主题的信息,我强烈建议您查看以下这两个链接:
- 📄 Node.JS 中的 SOLID 代码
好吧,让我们开始构建我们的项目。创建一个名为 API 的文件夹并运行以下命令:
> npm init -y
进入全屏模式 退出全屏模式
此命令创建一个标准的 package.json 文件。现在我们将安装以下软件包:
> npm i --save-dev husky nodemon
进入全屏模式 退出全屏模式
并将其他软件包安装为依赖项:
> npm i cors dotenv express express-promise-router pg
进入全屏模式 退出全屏模式
最后,package.json文件将如下所示:
{
"name": "crud-nodejs-psql",
"version": "1.0.0",
"description": "Aplicação CRUD com Node.js & PostgreSQL",
"main": "server.js",
"scripts": {
"dev": "nodemon",
"lint": "eslint --ext .js,.html -f ./node_modules/eslint-friendly-formatter . --fix",
"prepush": "npm run lint",
"start": "node server.js"
},
"keywords": [
"node.js",
"javascript",
"postgresel",
"azure",
"serverless",
"azure-functions",
"azure-devops",
"azure-storage",
"github-actions",
"app-service",
"express"
],
"author": "Glaucia Lemos",
"license": "MIT",
"bugs": {
"url": "https://github.com/glaucia86/nodejs-postgresql-azure/issues"
},
"homepage": "https://github.com/glaucia86/nodejs-postgresql-azure#readme",
"devDependencies": {
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-plugin-import": "^2.20.1",
"husky": "^4.2.3",
"nodemon": "^2.0.2"
},
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-plugin-html": "^6.0.0",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"pg": "^7.18.2"
}
}
进入全屏模式 退出全屏模式
创建文件夹和文件的结构,如下图所示:

开发应用程序
在此之后,我不会解释每个文件的作用。因为文章的主要重点是创建一个 RESTful API,最终还是要持久化在 PostgreSQL 中。
打开 Visual Studio Code 让我们开始开发文件:server.js 并包含以下代码块:
- 文件:server.js
/**
* File: server.js
* Description: arquivo responsável por toda a configuração e execução da aplicação.
* Data: 02/03/2020
* Author: Glaucia Lemos
*/
const app = require('./src/app');
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log('Aplicação executando na porta ', port);
});
进入全屏模式 退出全屏模式
现在,打开src -> app.js文件并包含以下代码块:
- 文件:app.js
const express = require('express');
const cors = require('cors');
const app = express();
// ==> Rotas da API:
const index = require('./routes/index');
// const productRoute = require('./routes/product.routes');
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.json({ type: 'application/vnd.api+json' }));
app.use(cors());
app.use(index);
// app.use('/api/', productRoute);
module.exports = app;
进入全屏模式 退出全屏模式
请注意,在这个app.js file中,有几行代码被注释了,只是为了能够初步执行我们的 API,看看我们是否开发正确。但是,稍后我们将对这个文件进行一些重大更改,然后取消注释这些行。
最后,打开src -> routes -> index.js文件并包含以下代码块:
- 文件:src -> 路由 -> index.js
/**
* File: src/routes/index.js
* Description: arquivo responsável pela chamada da Api da aplicação.
* Data: 02/03/2020
* Author Glaucia Lemos
*/
const express = require('express');
const router = express.Router();
router.get('/api', (req, res) => {
res.status(200).send({
success: 'true',
message: 'Seja bem-vindo(a) a API Node.js + PostgreSQL + Azure!',
version: '1.0.0',
});
});
module.exports = router;
进入全屏模式 退出全屏模式
现在,打开 apifolder 中的命令提示符并运行命令:
> nodemon
进入全屏模式 退出全屏模式
然后打开邮递员并在 (GET) 中包含以下 URL:localhost:3000/api/:

如果屏幕显示与您在上面看到的一样,这意味着我们的 API 工作正常!现在,让我们更深入地了解开发。开始了!
了解更多关于包的信息:'node-postgres'
您可能已经注意到,当我们安装一些包时,我们包含了 node-postgres 包。这个包对于我们在 Node.js 上使用 PostgreSQL 客户端是必不可少的。
这个包是**开源**项目。它有简单直接的文档 - 教我们如何在 Promises 或使用 Async / Await 中实现这个包。它对我开发本教程帮助很大!
我建议阅读包文档,可以在这里找到 HERE。
在这个项目中,我决定使用 node-postgres 而不是 Sequelize,Sequelize 对于使用 PostgreSQL、MySQL、MariaDB、SQLite 和 Microsoft SQL Server 的人来说是一种广泛使用的 ORM。只是为了让这个project-1更容易。
由于我们一开始已经安装了 node-postgres 包,让我们继续吧!
使用“dotenv”创建环境变量
您可能已经注意到的另一点是我们还安装了 dotenv 包。这个服务器包很重要,这样我们就可以存储我们不想在您执行commit时向公众提供的环境变量。
至于我们将如何使用数据库连接字符串以及这个连接字符串如何包含敏感数据,我们不想让所有人都可以使用它。我们现在将在我们的项目中解决这个问题。为此,请按照以下步骤操作:
DATABASE_URL=postgres://{db_username}:{db_password}@{host}:{port}/{db_name}
进入全屏模式 退出全屏模式
如果您不知道您的 PostgreSQL db_username 是什么,只需右键单击 PgAdmin 服务器并转到 Properties -> Connections 即可找到用户名。请看下面的 gif:

在文件中配置到数据库的连接字符串:'database.js'
现在我们已经在 .env 文件中包含了我们的connectionstring,现在是时候开始开发和配置我们的应用程序与 PostgreSQL 的数据库连接了。
为此,请打开database.js文件并包含以下代码块:
- 配置/database.js:
/**
* Arquivo: config/database.js
* Descrição: arquivo responsável pelas 'connectionStrings da aplicação: PostgreSQL.
* Data: 04/03/2020
* Author: Glaucia Lemos
*/
const { Pool } = require('pg');
const dotenv = require('dotenv');
dotenv.config();
// ==> Conexão com a Base de Dados:
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
pool.on('connect', () => {
console.log('Base de Dados conectado com sucesso!');
});
module.exports = {
query: (text, params) => pool.query(text, params),
};
进入全屏模式 退出全屏模式
这个块与我们的连接字符串连接,以便我们最终可以开始使用 Node.js 在 PostgreSQL 中持久化数据。
请注意,我们使用的是 node-postgres 包。如果你想进一步了解pg.Pool,我推荐阅读**HERE**,因为从现在开始我们会大量使用它,包括这个builder的属性!
路线:(POST)'创建产品'
我们已经完成了应用程序的配置,并且已经建立了与数据库的连接!现在游戏将开始!为此,我们将开发第一条路线。为此,我们将从现在开始大量使用两个文件:product.controller.js 和 product.routes.js。
按着这些次序:
在 product.routes.js 文件中包含以下代码块
- 文件:product.routes.js
// @ts-nocheck
/**
* Arquivo: src/routes/product.routes.js
* Descrição: arquivo responsável pelas rotas da api relacionado a classe 'Product'.
* Data: 04/03/2020
* Author Glaucia Lemos
*/
const router = require('express-promise-router')();
const productController = require('../controllers/product.controller');
// ==> Definindo as rotas do CRUD - 'Product':
// ==> Rota responsável por criar um novo 'Product': (POST): localhost:3000/api/products
router.post('/products', productController.createProduct);
module.exports = router;
进入全屏模式 退出全屏模式
现在我们将在文件product.controller.js中开发方法 createProduct 的逻辑
- 控制器/product.controller.js
const db = require("../config/database");
// ==> Método responsável por criar um novo 'Product':
exports.createProduct = async (req, res) => {
const { product_name, quantity, price } = req.body;
const { rows } = await db.query(
"INSERT INTO products (product_name, quantity, price) VALUES ($1, $2, $3)",
[product_name, quantity, price]
);
res.status(201).send({
message: "Product added successfully!",
body: {
product: { product_name, quantity, price }
},
});
};
进入全屏模式 退出全屏模式
请注意,我们只是在代码中使用插入查询,就像在 SQL 脚本中一样。就这样。当然,要返回所有输入的值,我们会发送一条消息以确认创建的产品并返回该产品的所有值。
现在我们需要在测试我们的应用程序之前更新 app.js 文件。为此,请取消注释 product.routes 所在的行:
- 文件:app.js
/**
* Arquivo: app.js
* Descrição: arquivo responsável por toda a configuração da aplicação.
* Data: 02/03/2020
* Author: Glaucia Lemos
*/
const express = require('express');
const cors = require('cors');
const app = express();
// ==> Rotas da API:
const index = require('./routes/index');
const productRoute = require('./routes/product.routes');
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.json({ type: 'application/vnd.api+json' }));
app.use(cors());
app.use(index);
app.use('/api/', productRoute);
module.exports = app;
进入全屏模式 退出全屏模式
打开命令提示符并在 api 文件夹中键入以下命令
> nodemon
进入全屏模式 退出全屏模式
- 现在我们可以测试我们创建的第一个路由。所以现在,在以下端点打开 Postman:(POST) localhost: 3000/api/products,如下图所示:

如果出现如下信息:
{
"message": "Product added successfully!",
"body": {
"product": {
"product_name": "Logitech MK270 Wireless Keyboard and Mouse Combo",
"quantity": "2",
"price": "18.99"
}
}
}
进入全屏模式 退出全屏模式
这是因为它完美地坚持了下来。为确保这一点,请打开已创建表的 PgAdmin 并按照以下 gif 所示进行操作:

完美的!一旦我们设法创建了第一条路线,其他路线就很容易了!
让我们继续!
路线:(GET)'列出所有产品'
现在我们将创建一个路由来列出所有在 PostgreSQL 中创建和持久化的产品。由于已经创建了 POST 路线,因此如果您包含更多数据以帮助未来的路线,那将对您有好处!
再次返回 product.routes.js 文件并添加路由以列出所有产品:
- 文件:product.routes.js
// ==> Rota responsável por listar todos os 'Products': (GET): localhost:3000/api/products
router.get('/products', productController.listAllProducts);
进入全屏模式 退出全屏模式
现在,回到 product.controller.js 文件,让我们开发 listAllProducts 方法的逻辑:
- 文件:product.controller.js
// ==> Método responsável por listar todos os 'Products':
exports.listAllProducts = async (req, res) => {
const response = await db.query('SELECT * FROM products ORDER BY product_name ASC');
res.status(200).send(response.rows);
};
进入全屏模式 退出全屏模式
请注意,我在这里所做的查询是:SELECT * FROM products ORDER BY product_name ASC。在这里,我要求按字母顺序返回所有保留在 PostegreSQL 中的产品!我这样做是为了让它有点不同! ;)
让我们测试一下。打开 Postman 看看结果:

它工作得很好!请注意,如果我们需要对子查询进行更精细的 SELECT,遵循逻辑,它将完美地工作! :)
路线:(GET)“按 ID 列出产品”
现在,这很容易。只需将我们的 SQL 知识与我们已经在其他 Node.js 应用程序中创建的其他 CRUD 结合起来。
现在让我们创建通过 Id 列出特定产品的路线。再次,打开文件 product.routes.js 并包含另外一个路由:
- 文件:product.routes.js
(...)
// ==> Rota responsável por selecionar 'Product' pelo 'Id': (GET): localhost:3000/api/products/:id
router.get('/products/:id', productController.findProductById);
(...)
进入全屏模式 退出全屏模式
现在打开文件product.controller.js,我们将开发这条路线的逻辑:
- 文件:product.controller.js
(...)
// ==> Método responsável por selecionar 'Product' pelo 'Id':
exports.findProductById = async (req, res) => {
const productId = parseInt(req.params.id);
const response = await db.query('SELECT * FROM products WHERE productid = $1', [productId]);
res.status(200).send(response.rows);
}
进入全屏模式 退出全屏模式
现在让我们在 Postman 上测试这条路线,看看会发生什么:

路线:(PUT)'按 ID 更新产品'
现在让我们回到 product.routes.js 文件来创建 updateProductById 路由,该路由将负责通过 Id 更新产品:
- 文件:product.routes.js
(...)
// ==> Rota responsável por atualizar 'Product' pelo 'Id': (PUT): localhost: 3000/api/products/:id
router.put('/products/:id', productController.updateProductById);
进入全屏模式 退出全屏模式
让我们回到updateProductById文件来开发product.controller.js方法的逻辑:
- 文件:product.controller.js
(...)
// ==> Método responsável por atualizar um 'Product' pelo 'Id':
exports.updateProductById = async (req, res) => {
const productId = parseInt(req.params.id);
const { product_name, quantity, price } = req.body;
const response = await db.query(
"UPDATE products SET product_name = $1, quantity = $2, price = $3 WHERE productId = $4",
[product_name, quantity, price, productId]
);
res.status(200).send({ message: "Product Updated Successfully!" });
};
进入全屏模式 退出全屏模式
它正在完美更新!请看下面的 gif:

现在让我们去我们的最后一条路线吧!
路线:(DELETE)'按 ID 删除产品'
终于到了我们api的最后一条路线!让我们回到 product.routes.js 文件并为 deleteProductById 方法创建路由:
- 文件:product.routes.js
(...)
// ==> Rota responsável por excluir 'Product' pelo 'Id': (DELETE): localhost:3000/api/products/:id
router.delete('/products/:id', productController.deleteProductById);
(...)
进入全屏模式 退出全屏模式
最后,在 product.controller.js 文件中开发此路由的逻辑:
- 文件:product.controller.js
(...)
// ==> Método responsável por excluir um 'Product' pelo 'Id':
exports.deleteProductById = async (req, res) => {
const productId = parseInt(req.params.id);
await db.query('DELETE FROM products WHERE productId = $1', [
productId
]);
res.status(200).send({ message: 'Product deleted successfully!', productId });
};
进入全屏模式 退出全屏模式
一切正常,如果我们打开 PostgreSQL,我们会看到现在我们只有 5 个注册产品!

结论
今天我们学习了如何创建一个 CRUD API RESTFul,Node.js 在 PostgreSQL 本地持久化。在下一篇文章中,我将教你如何在 Azure 应用服务中部署这个应用程序!执行此部署后,我们将在 Postman 上进行测试,然后在 Swagger 上进行测试!
在这里,我想分享一些关于 Node.js、Azure 数据库 PostgreSQL 和 GitHub Actions 的好资源:
-
✅ 使用 Node.js 构建 JavaScript 应用程序
-
✅ Azure Database for PostgreSQL 文档
-
✅ 快速入门:使用 Azure 门户创建 Azure Database for PostgreSQL 服务器
-
✅ 教程:使用 Azure Database for PostgreSQL 设计实时分析仪表板 - 超大规模 (Citus)
-
✅ 适用于 JavaScript 和 Node.js 开发人员的 Azure
-
✅ 免费电子书 - Azure Serverless Computing Cookbook
-
✅ 免费课程 - 创建无服务器应用程序
并且要保持在其他几个新闻的顶部,请务必在 Twitter 上关注我!

并订阅我的 Youtube 频道 - Glaucia Lemos 每周观看有关 Web 开发、Node.js 和 JavaScript 的新视频!

再见! 😍
更多推荐
所有评论(0)