如何用Express.js和PostgreSQL创建一个REST API(附代码)

609 阅读4分钟

Node + Express + PostgreSQL是一个强大的技术栈,用于后端应用程序提供CRUD操作。它为你提供了暴露API(Express路线)、添加业务逻辑(Express中间件和Express路线中的逻辑)以及使用真实数据的数据库(PostgreSQL)的一切。它是建立PERN(PostgreSQL、Express、React、Node)、PEAN(PostgreSQL、Express、Angular、Node)或PEVN(PostgreSQL、Express、Vue、Node)技术栈的理想选择。一切都会缺少的是用React、Angular、Vue或其他东西的前端应用程序。但这是另一节的内容了。

本节的重点是为我们的REST API连接PostgreSQL和Express。之前我们已经在Express.js应用程序中设置了PostgreSQL,并在数据库中加入了初始数据,但在Express中还没有将其用于RESTful API。现在我们要确保每个CRUD操作通过这个REST API读取或写入PostgreSQL数据库,而不是像以前那样在我们的Express路由中使用样本数据。这就是为什么我们需要通过Sequelize将我们的Express路由与PostgreSQL连接起来,以实现两个世界的融合。

在我们的src/index.js中,我们用 PostgreSQL 数据库设置并启动了 Express 应用程序,我们已经有一个 Express 中间件,它将模型作为上下文传递给我们所有的 Express 路由。之前,这些模型一直是样本数据。现在,我们正在使用Sequelize模型,它将我们与PostgreSQL数据库相连。由于文件夹/文件的数据结构和以前一样,在将模型作为上下文传递给Express路由时没有任何变化。

import express from 'express';
...

import models, { sequelize } from './models';

const app = express();

...

app.use((req, res, next) => {
  req.context = {
    models,
    me: models.users[1],
  };
  next();
});

...

然而,我的用户(认证用户)可以从数据库的种子数据中检索出来。在models对象上不再有users 数组作为样本数据,因为models现在是我们与PostgreSQL数据库的接口。

import express from 'express';
...

import models, { sequelize } from './models';

const app = express();

...

app.use(async (req, res, next) => {
  req.context = {
    models,
    me: await models.User.findByLogin('rwieruch'),
  };
  next();
});

...

即使我们还不知道认证的用户,因为我们没有从外部为它传递任何数据给REST API,我们只是取任何我们知道存在于我们数据库中的用户,因为之前的PostgreSQL数据库播种。findByLogin 方法在我们的模型上是可用的,因为我们之前已经实现了它作为自定义方法,让它通过用户名或电子邮件来检索用户。

现在让我们深入了解一下我们的Express路由。我们有针对会话、用户和消息实体的路由。会话实体是第一位的。同样,我们可以使用模型的接口--由Sequelize提供的接口--来与数据库进行交互,而不是使用之前在模型上提供的样本数据。在src/routes/session.js中修改以下几行代码。

import { Router } from 'express';

const router = Router();

router.get('/', async (req, res) => {
  const user = await req.context.models.User.findByPk(
    req.context.me.id,
  );
  return res.send(user);
});

export default router;

路由函数变成了一个异步函数,因为我们现在正在处理对PostgreSQL数据库的异步请求。我们用async/await来处理该函数的异步性。

由于我们之前通过上下文对象将模型方便地传递给了每个有应用程序范围的Express中间件的Express路由,所以我们可以在这里利用它。我们之前从PostgreSQL数据库中任意抽取的认证用户,可以用来从数据库中检索当前会话用户。

让我们来处理src/routes/user.js文件中的用户路由,它提供了 RESTful API 端点,用于获取用户或按 id 获取单个用户。这两个API请求都会导致对PostgreSQL数据库的读取操作。

import { Router } from 'express';

const router = Router();

router.get('/', async (req, res) => {
  const users = await req.context.models.User.findAll();
  return res.send(users);
});

router.get('/:userId', async (req, res) => {
  const user = await req.context.models.User.findByPk(
    req.params.userId,
  );
  return res.send(user);
});

export default router;

第一个获取用户列表的API端点并没有从请求中获得任何输入参数。但是第二个API端点可以访问用户标识符,以便从PostgreSQL数据库中读取正确的用户。

最后但并非最不重要的是src/routes/message.js文件中的消息路由。除了按标识符读取消息和单一消息外,我们还有创建消息和删除消息的API端点。这两种操作都会导致对PostgreSQL数据库的写操作。

import { Router } from 'express';

const router = Router();

router.get('/', async (req, res) => {
  const messages = await req.context.models.Message.findAll();
  return res.send(messages);
});

router.get('/:messageId', async (req, res) => {
  const message = await req.context.models.Message.findByPk(
    req.params.messageId,
  );
  return res.send(message);
});

router.post('/', async (req, res) => {
  const message = await req.context.models.Message.create({
    text: req.body.text,
    userId: req.context.me.id,
  });

  return res.send(message);
});

router.delete('/:messageId', async (req, res) => {
  const result = await req.context.models.Message.destroy({
    where: { id: req.params.messageId },
  });

  return res.send(true);
});

export default router;

基本上,这就是用Sequelize连接PostgreSQL和Express路线的方法。所有用Sequelize设置的模型都可以作为你的PostgreSQL数据库的接口。一旦用户点击了你的REST API,你就可以在Express路由中对你的PostgreSQL数据库进行读或写操作。