让我们在 JavaScript 中创建一个 CRUD rest API,使用:
- 节点.js 
- 表达 
- 续集 
- Postgres 
- 码头工人 
- 码头工人组成 
介绍
这是我们将要创建的应用程序架构的架构:
 
   我们将为基本的 CRUD 操作创建 5 个端点:
- 创造 
- 阅读全部 
- 读一个 
- 更新 
- 删除 
我们将使用以下方法创建一个 Node.js 应用程序:
- 表达为框架 
- 序列化为 ORM 
- 我们将 Dockerize Node.js 应用程序 
- 我们将有一个 Postgres 实例,我们将使用 Tableplus 对其进行测试 
- 我们将创建一个 docker compose 文件来运行这两个服务 
- 我们将使用 Postman 测试 API 
分步指南
这是一个分步指南。
新建一个文件夹
mkdir node-crud-api步入其中
cd node-crud-api初始化一个新的 npm 项目
npm init -y安装依赖项
npm i express pg sequelize- express 是 Node.js 框架 
- pg 是与 Postgres 数据库连接的驱动程序 
- sequelize 是 ORM,所以我们避免输入 SQL 查询 
创建4个文件夹
mkdir controllers routes util models使用您喜欢的 IDE 打开文件夹。如果你有 Visual Studio Code,你可以从终端输入:
code .你现在应该有一个类似于这个的文件夹:
 
   现在让我们开始编码。
数据库连接
在“util”文件夹中创建一个名为“database.js”的文件。
此文件将包含内部配置以允许 Node.js 应用程序和正在运行的 Postgres 实例之间的连接。
填充 util/database.js 文件
constSequelize=require('sequelize');constsequelize=newSequelize(process.env.PG_DB,process.env.PG_USER,process.env.PG_PASSWORD,{host:process.env.PG_HOST,dialect:'postgres',});module.exports=sequelize;用户模型
在“models”文件夹中创建一个名为“user.js”的文件。
该文件将包含模型,在本例中为具有自动递增 ID、名称和电子邮件的用户。
填充 models/user.js 文件:
constSequelize=require('sequelize');constdb=require('../util/database');constUser=db.define('user',{id:{type:Sequelize.INTEGER,autoIncrement:true,allowNull:false,primaryKey:true},name:Sequelize.STRING,email:Sequelize.STRING});module.exports=User;控制器
该文件包含所有要执行的函数,以便与数据库交互并具有 4 个基本功能:
在“controllers”文件夹中创建一个名为“users.js”的文件
填充 controllers/users.js 文件
constUser=require('../models/user');// CRUD Controllers//get all usersexports.getUsers=(req,res,next)=>{User.findAll().then(users=>{res.status(200).json({users:users});}).catch(err=>console.log(err));}//get user by idexports.getUser=(req,res,next)=>{constuserId=req.params.userId;User.findByPk(userId).then(user=>{if(!user){returnres.status(404).json({message:'User not found!'});}res.status(200).json({user:user});}).catch(err=>console.log(err));}//create userexports.createUser=(req,res,next)=>{constname=req.body.name;constemail=req.body.email;User.create({name:name,email:email}).then(result=>{console.log('Created User');res.status(201).json({message:'User created successfully!',user:result});}).catch(err=>{console.log(err);});}//update userexports.updateUser=(req,res,next)=>{constuserId=req.params.userId;constupdatedName=req.body.name;constupdatedEmail=req.body.email;User.findByPk(userId).then(user=>{if(!user){returnres.status(404).json({message:'User not found!'});}user.name=updatedName;user.email=updatedEmail;returnuser.save();}).then(result=>{res.status(200).json({message:'User updated!',user:result});}).catch(err=>console.log(err));}//delete userexports.deleteUser=(req,res,next)=>{constuserId=req.params.userId;User.findByPk(userId).then(user=>{if(!user){returnres.status(404).json({message:'User not found!'});}returnUser.destroy({where:{id:userId}});}).then(result=>{res.status(200).json({message:'User deleted!'});}).catch(err=>console.log(err));}航线
在“routes”文件夹中创建一个名为“users.js”的文件。
填充 routes/users.js 文件
constcontroller=require('../controllers/users');constrouter=require('express').Router();// CRUD Routes /usersrouter.get('/',controller.getUsers);// /usersrouter.get('/:userId',controller.getUser);// /users/:userIdrouter.post('/',controller.createUser);// /usersrouter.put('/:userId',controller.updateUser);// /users/:userIdrouter.delete('/:userId',controller.deleteUser);// /users/:userIdmodule.exports=router;索引文件
要运行我们的应用程序,我们需要在根级别创建更多文件。这是将由 docker 容器执行的文件。
在根文件夹中,创建一个名为 index.js 的文件
填充“index.js 文件”:
constexpress=require('express');constbodyparser=require('body-parser');constsequelize=require('./util/database');constUser=require('./models/user');constapp=express();app.use(bodyparser.json());app.use(bodyparser.urlencoded({extended:false}));app.use((req,res,next)=>{res.setHeader('Access-Control-Allow-Origin','*');res.setHeader('Access-Control-Allow-Methods','GET, POST, PUT, DELETE');next();});//test routeapp.get('/',(req,res,next)=>{res.send('Hello World');});//CRUD routesapp.use('/users',require('./routes/users'));//error handlingapp.use((error,req,res,next)=>{console.log(error);conststatus=error.statusCode||500;constmessage=error.message;res.status(status).json({message:message});});//sync databasesequelize.sync().then(result=>{console.log("Database connected");app.listen(3000);}).catch(err=>console.log(err));码头部分
让我们在根级别再创建 3 个文件:
- .dockerignore(以点开头) 
- Dockerfile(大写字母 D) 
- docker-compose.yml 
结构应如下所示:
 
   .dockerignore 将包含一行:
node_modules 
   Dockerfile
要创建 Docker 镜像,我们需要一个简单但功能强大的文件。这就是所谓的“Dockerfile”(大写字母 D)。我们可能会使用不同的名称,但让我们暂时保持简单。
FROM node:14# Create app directoryWORKDIR /appCOPY package*.json ./RUN npm install# Bundle app sourceCOPY . .EXPOSE 3000CMD [ "node", "index.js" ]Docker 组合文件
要运行多个服务,一种简单的方法是创建一个名为“docker-compose.yml”的文件
docker-compose.yml 文件:
version:"3.9"services:node_app:container_name:node_appbuild:.image:francescoxx/node_live_appports:-"3000:3000"environment:-PG_DB=node_live_db-PG_USER=francesco-PG_PASSWORD=12345-PG_HOST=node_dbdepends_on:-node_dbnode_db:container_name:node_dbimage:postgres:12ports:-"5432:5432"environment:-POSTGRES_DB=node_live_db-POSTGRES_USER=francesco-POSTGRES_PASSWORD=12345volumes:-node_db_data:/var/lib/postgresql/datavolumes:node_db_data:{}构建 Docker 镜像并运行 docker 容器
在容器中运行 Postgres
首先,让我们运行 postgres 容器:
docker compose up -d node_db要检查日志,我们可以键入:
docker compose logs你应该得到类似于这个的输出:
 
   如果我们看到“数据库系统已准备好接受连接”,我们就可以开始了!
让我们使用 TablePlus 对其进行测试。
单击 + 创建新连接
 
   从 docker-compose.yml 文件复制值。(如果您保留原值,密码为 12345)
 
   构建并运行 Docker 服务
其次,让我们构建我们的 Docker iamge:
docker compose build 
   最后,让我们启动服务:
docker compose up node_app这应该是终端上的输出
 
   使用 Postman 测试应用
让我们使用 Postman 测试应用程序。
向 localhost:3000 发出 GET 请求
 
   向 localhost:3000/users 发出 GET 请求
我们应该有一个空数组作为响应
 
   让我们创建 3 个用户:aaa、bbb 和 ccc
 
    
    
   让我们再次检查所有用户:
向 localhost:3000/users 发出 GET 请求
我们应该看到 3 个用户:
 
   让我们得到一个用户,例如用户 2
向 localhost:3000/users/2 发出 GET 请求
 
   让我们更新现有用户,例如同一用户 2
使用不同的主体向 localhost:3000/users/2 发出 PUT 请求
 
   最后,让我们删除用户号 3
对 localhost:3000/users/3 进行删除请求
我们还可以使用 TablePlus 检查值
 
   结论
这是一个基本示例,说明如何使用 Node.js、Express、Sequelize、Postres、Docker 和 Docker Compose 构建 CRUD rest API。



















