美文网首页程序员
使用 Node, Sequelize, Postgres 和

使用 Node, Sequelize, Postgres 和

作者: 求知久久编程学院 | 来源:发表于2021-02-05 16:07 被阅读0次
    image.png

    在本文中,我们将使用 Node, Sequelize, Postgres 和 Docker 搭建 CURD API。

    原文地址:https://francescociulla.com/crud-api-using-node-sequelize-postgres-and-docker

    GitHub Repository: github.com/FrancescoXX/docker-nsp

    NODE

    image.png

    Node是后端JavaScript运行时环境,这意味着可以在计算机 (例如,您的计算机或安装了Node的计算机) 上执行JavaScript代码。好消息是,通过使用Docker,您实际上不需要安装它,因为我们将使用 Node 的 docker image,因此,我们也可以避免在我的机器上安装的我的 Node 版本和你的之间进行版本控制

    POSTGRES

    image.png

    Postgres (PostgreSQL) 是一个免费的开源关系数据库,非常流行且稳定

    SEQUELIZE

    [图片上传失败...(image-3b0a5f-1612512236595)]

    Sequelize是 Node 的基于 Promise 的对象关系映射 (ORM)。ORM是一种使用面向对象的编程语言从不兼容类型系统转换数据的技术。

    它允许我们在数据库中创建和修改表,而无需执行SQL命令

    它还适用于MySQL、MariaDB、SQLite、Microsoft SQL Server。

    DOCKER

    image.png

    Docker是一个使用容器概念构建运行和共享应用程序的平台。如果你想简单介绍一下,这里有一个简短的视频

    image.png

    youtu.be/eN_O4zd4D9o

    跟着步骤来

    1. 创建一个名为docker-nsp的文件夹 (代表node、sequelize、postgres) 并进入其中

    mkdir docker-nsp && cd docker-nsp
    

    2. 使用npm初始化 Node 应用

    npm init -y
    

    3. 安装依赖

    npm install express pg sequelize
    

    4. 创建结构

    然后创建一个index.js文件

    我们的目录结构应该如下所示:

    image.png

    让我们编写index.js文件

    const express = require('express');
    const bodyParser = require('body-parser');
    
    const sequelize = require('./util/database'); //database initializations
    const User = require('./models/users'); //REQUIRED even if IDE says not used!
    
    //INITIALIZE APP WITH EXPRESS
    const app = express();
    
    //BODYPARSER
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));
    
    //Set proper Headers on Backend
    app.use((req, res, next) => {
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
      res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
      next();
    });
    
    //ROUTES
    app.use('/dev', require('./routes/dev')); //All test routes are placed here
    app.use('/users', require('./routes/users')); //users crud
    
    (async () => {
      try {
        await sequelize.sync(
          { force: false} //Reset db every time
        );
        app.listen(process.env.EXTERNAL_PORT); //DEF in docker.compose.yml
      } catch (error) {
        console.log(error);
      }
    })();
    

    在util文件夹中,让我们创建与postgres db的连接

    创建database.js文件

    const Sequelize = require('sequelize');
    
    //GET ENV VARIABLES FROM
    const sequelize = new Sequelize(
        process.env.PGDATABASE,
        process.env.PGUSER,
        process.env.PGPASSWORD,
        {
            host: process.env.PGHOST,
            dialect: 'postgres'
        });
    
    module.exports = sequelize;
    

    在路由文件夹中,让我们创建几个文件来重定向HTTP请求: dev.js和users.js

    路由文件夹中的dev.js文件:

    const controller = require('../controllers/dev'); 
    const router = require('express').Router();
    
    router.get('/config', controller.getConfig);
    router.get('/version', controller.getVersion);
    router.get('/seq', controller.seq); //test sequelize connection
    
    module.exports = router;
    

    路由文件夹中的users.js文件:

    const controller = require('../controllers/' + 'users');
    const router = require('express').Router();
    
    //CRUD Model-Agnostic. 
    //Keep them at the end of the route file for url parsing requests
    router
      .get('/', controller.getAll)
      .get('/:id', controller.getOne)
      .post('/', controller.createOne)
      .put('/:id', controller.updateOne)
      .delete('/:id', controller.deleteOne);
    
    module.exports = router;
    

    在 “模型” 文件夹中,让我们创建users.js文件以用作用户的模型:

    模型文件夹中的users.js文件:

    const Sequelize = require('sequelize');
    const db = require('../util/database');
    
    const User = db.define('users', {
        id: {
            type: Sequelize.INTEGER,
            autoIncrement: true,
            allowNull: false,
            primaryKey: true
        },
        username: {
            type: Sequelize.STRING,
            allowNull: false,
            unique: true
        },
        email: {
            type: Sequelize.STRING,
            allowNull: false,
        },
        password: {
            type: Sequelize.STRING,
            allowNull: false
        }
    });
    
    module.exports = User;
    

    模型(model)文件夹中的users.js文件:

    控制器(controllers)文件夹中的dev.js文件:

    const packJson = require('../../package.json');
    const sequelize = require('../util/database');
    
    // [GET] ../dev/config
    exports.getConfig = (req, res, next) => {
      return res.status(200).json({ packJson });
    };
    
    // [GET] ../dev/version
    exports.getVersion = (req, res, next) => {
      return res.status(200).json({ 'nps Backend': packJson.version });
    };
    
    // [GET] ../dev/seq
    exports.seq = async (req, res, next) => {
      try {
        await sequelize.authenticate();
        console.log('Sequelize Connection established');
        res.status(200).json('Sequelize Connection established');
        next();
      } catch (error) {
        next(error);
      }
    };
    

    控制器(controllers)文件夹中的users.js文件:

    const User = require("../models/users");
    
    /**
     * CRUD CONTROLLERS
     */
    
    //CREATE-ONE
    exports.createOne = async (req, res, next) => {
        console.log("createOne: [POST] /users/");
        try {
            const USER_MODEL = {
                username: req.body.username,
                email: req.body.email,
                password: req.body.password,
                role: req.body.role,
            }
    
            try {
                const user = await User.create(USER_MODEL);
                console.log("OK createOne USER: ", user);
                return res.status(201).json(user);
            } catch (error) {
                console.log('ERROR in createOne ' + "USER:", error);
                return res.status(500).json(error);
            }
        } catch (error) {
            return res.status(400).json("Bad Request");
        }
    };
    
    //GET-ALL
    exports.getAll = async (req, res, next) => {
        console.log("getAll: [GET] /users/");
        try {
            const ALL = await User.findAll();
            console.log("OK getAll USER: ", ALL.map(el => el.dataValues));
            return res.status(200).json(ALL);
        } catch (error) {
            console.log('ERROR in getAll ' + "USER:", error);
            return res.status(500).json(error);
        }
    };
    
    //GET-ONE
    exports.getOne = async (req, res, next) => {
        console.log("getOne: [GET] /users/:id");
        try {
            const u = await User.findByPk(req.params.id);
            console.log("OK getOne USER: ", u.dataValues);
            return res.status(200).json(u);
        } catch (error) {
            console.log('ERROR in getOne ' + "USER:", error);
            return res.status(500).json(error);
        }
    };
    
    //UPDATE-ONE.
    exports.updateOne = async (req, res, next) => {
        console.log("updateOne: [PUT] /users/:id");
        try {
            const USER_MODEL = {
                username: req.body.username,
                email: req.body.email,
                password: req.body.password,
                role: req.body.role
            }
    
            try {
                const u = await User.update(USER_MODEL, { where: { id: req.params.id } });
                console.log("OK updateOne USER: ", u);
                return res.status(200).json(u);
            } catch (error) {
                console.log('ERROR in updateOne ' + "USER:", error);
                return res.status(500).json(error);
            }
        } catch (error) {
            return res.status(400).json("Bad Request");
        }
    };
    
    //DELETE-ONE
    exports.deleteOne = async (req, res, next) => {
        console.log("[DELETE] /users/:id");
        try {
            const u = await User.destroy({ where: { id: req.params.id } });
            console.log("OK deleteOne USER: ", );
            return res.status(200).json(u);
        } catch (error) {
            console.log('ERROR in deleteOne ' + "USER:", error);
            return res.status(500).json(error);
        }
    };
    

    DOCKER

    image.png

    现在是Docker部分!

    在主文件夹中,创建3个文件:

    • Dockerfile
    • docker-compose.yml
    • .dockerignore (it starts with a dot)

    .dockerignore 文件:

    .git
    node_modules
    npm-debug.log
    

    然后 Dockerfile:

    FROM node:14
    
    EXPOSE 3001
    
    # Use latest version of npm
    RUN npm i npm@latest -g
    
    COPY package.json package-lock.json* ./
    
    RUN npm install --no-optional && npm cache clean --force
    
    # copy in our source code last, as it changes the most
    WORKDIR /opt
    COPY . .
    
    CMD [ "node", "app/index.js" ]
    

    docker-compose.yml 文件:

    version: "3.8"
    services:
      nsp_backend:
        container_name: nsp_backend
        image: francescoxx/nsp-template:0.0.2
        build:
          context: .
        ports:
          - "3001:3001"
        environment:
          - EXTERNAL_PORT=3001
          - PGUSER=francesco
          - PGPASSWORD=12345
          - PGDATABASE=nps_database
          - PGHOST=nsp_db # NAME OF THE SERVICE
        depends_on:
          - nsp_db
      nsp_db:
        container_name: nsp_db
        image: "postgres:12"
        ports:
          - "5432:5432"
        environment:
          - POSTGRES_USER=francesco
          - POSTGRES_PASSWORD=12345
          - POSTGRES_DB=nps_database
        volumes:
          - nps_data:/var/lib/postgresql/data
    volumes:
      nps_data: {}
    

    将docker 镜像 “francescoxx/nsp-模板: 0.0.2” 替换为您选择的 docker 镜像名称!

    让我们启动nsp_db服务:

    docker-compose up -d nsp_db
    

    我们应该有一个Postgres数据库启动并运行!

    让我们检查一下数据库中的内容:

    docker exec -it nsp_db psql -U francesco postgres
    

    一旦我们进入容器 (您可以通过检查postgres = # 终端来验证这一点)

    连接到nsp_database

    这意味着postgres使用我们在开始时传递的环境变量创建了一个名为 “nsp_database” 的数据库

    然后:

    您应该会收到以下消息:

    "没有发现任何表(relations)"

    这是因为我们已经使用环境变量创建了数据库,但是我们还没有创建任何表或关系

    退出

    然后重新进入终端

    是时候去构建我们的Docker 镜像的

    定位到 docker-compose.yml 文件所在的目录,然后运行:

    现在是时候运行我们的 Node 应用程序了

    docker-compose up -d nsp_backend
    

    我们可以使用 “docker ps -a” 命令验证两个容器是否都在运行

    [图片上传失败...(image-71b001-1612512236595)]

    Sequelize将为我们创建一个数据库

    尝试再次启动命令

    docker exec -it nsp_db psql -U francesco postgres
    

    尝试再次启动命令

    现在

    您应该看到表 “users”。这是在我们启动节点应用程序时通过Sequelize创建的。

    无论如何,如果我们执行

    我们应该得到一张空表

    nsp_database=# select * from users; id | username | email | password | createdAt | updatedAt ----+----------+-------+----------+-----------+----------- (0 rows)

    现在有趣的是,让我们测试一下API!

    POSTMAN

    image.png

    我们将使用 postman,但是你可以随时使用你想要的工具

    让我们做一个像这样的GET请求

    image.png

    这意味着我们的服务器已启动并正在运行

    让我们尝试获取所有用户

    image.png

    要添加用户,我们可以发出如下POST请求:

    image.png

    让我们再添加一个

    image.png

    现在,我们再看看用户列表,我们应该会看到这样的内容:

    image.png

    我们还可以通过在URL末尾添加用户的id来检查一个用户:

    image.png

    我们还可以通过PUT请求更新现有用户

    image.png

    如果我们尝试再次获得用户,我们会得到这个

    image.png

    现在,让我们尝试使用具有相对id的DELETE请求删除一个用户

    image.png

    服务器显示一个用户已被删除

    image.png

    如果我们尝试再次获得所有用户,只有id 为 2 的记录被拒绝

    image.png

    结论

    如果您尝试遵循本文,我想知道您是否遇到任何问题。谢谢

    GitHub 仓库: github.com/FrancescoXX/docker-nsp

    其他精彩文章

    相关文章

      网友评论

        本文标题:使用 Node, Sequelize, Postgres 和

        本文链接:https://www.haomeiwen.com/subject/hxcgtltx.html