Node.js

Как достать данные из модуля с базой в Node.js Express

Короткий ответ: модуль с базой должен экспортировать функцию, которая возвращает данные, а Express-роут должен вызвать эту функцию через await и отправить результат в res.json. Не нужно пытаться “достать переменную” из асинхронного кода: в Node.js данные приходят позже, поэтому их передают через promise или async-функцию

Этот запрос почти всегда появляется в момент, когда код уже разделили на файлы, но логика асинхронности еще не до конца понятна. Файл db.js вроде получает данные, файл server.js хочет их показать, а в ответе получается undefined, пустой массив или promise вместо результата

Минимальная структура проекта

Сделаем простой пример

project/
  db.js
  server.js
  package.json

Установите Express

npm init -y
npm install express

Модуль базы должен возвращать данные

Начнем без реальной базы, чтобы увидеть саму механику. Файл db.js

async function getUsers() {
  return [
    { id: 1, name: "Анна" },
    { id: 2, name: "Илья" }
  ];
}

module.exports = {
  getUsers
};

Здесь важно, что getUsers не пишет данные в глобальную переменную, а именно возвращает результат. Express сможет дождаться этой функции

Express-роут вызывает функцию через await

Файл server.js

const express = require("express");
const { getUsers } = require("./db");

const app = express();

app.get("/users", async (req, res) => {
  try {
    const users = await getUsers();
    res.json(users);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Не удалось получить пользователей" });
  }
});

app.listen(3000, () => {
  console.log("Сервер запущен: http://localhost:3000");
});

Запуск

node server.js

Откройте в браузере

http://localhost:3000/users

Если все сделано правильно, вы увидите JSON-массив пользователей

Пример с PostgreSQL

Если используется PostgreSQL и пакет pg, модуль может выглядеть так

npm install pg

db.js

const { Pool } = require("pg");

const pool = new Pool({
  connectionString: process.env.DATABASE_URL
});

async function getUsers() {
  const result = await pool.query("select id, name from users order by id");
  return result.rows;
}

module.exports = {
  getUsers
};

server.js остается почти таким же

const express = require("express");
const { getUsers } = require("./db");

const app = express();

app.get("/users", async (req, res) => {
  try {
    const users = await getUsers();
    res.json(users);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Ошибка базы данных" });
  }
});

app.listen(3000, () => {
  console.log("Сервер запущен");
});

Ключевая идея не меняется: модуль базы возвращает result.rows, а роут ждет результат через await

Почему не работает вариант с внешней переменной

Плохой пример

let users = [];

async function loadUsers() {
  users = await getUsersFromDatabase();
}

loadUsers();

module.exports = { users };

На первый взгляд кажется, что можно экспортировать users. Но loadUsers работает асинхронно, и в момент экспорта массив может быть еще пустым. Даже если он заполнится позже, другой файл может уже прочитать старое значение

Правильнее экспортировать функцию

module.exports = {
  getUsers
};

И каждый раз получать данные в роуте или в сервисном слое

Как передать параметр из Express в модуль базы

Например, нужно получить пользователя по id

db.js

async function getUserById(id) {
  const result = await pool.query(
    "select id, name from users where id = $1",
    [id]
  );

  return result.rows[0] || null;
}

module.exports = {
  getUserById
};

server.js

app.get("/users/:id", async (req, res) => {
  try {
    const user = await getUserById(req.params.id);

    if (!user) {
      res.status(404).json({ message: "Пользователь не найден" });
      return;
    }

    res.json(user);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Ошибка базы данных" });
  }
});

Так роут отвечает за HTTP, а модуль базы отвечает за запрос к базе. Это нормальное разделение обязанностей

Мини-практика

Сделайте модуль db.js, который возвращает массив задач

async function getTasks() {
  return [
    { id: 1, title: "Установить Node.js" },
    { id: 2, title: "Запустить Express" }
  ];
}

module.exports = { getTasks };

Затем создайте роут /tasks, вызовите await getTasks() и верните результат через res.json. После этого замените массив на реальный запрос к базе

Частые ошибки

Забыли await Если написать const users = getUsers(), в переменной будет promise, а не готовые данные

Экспортируют переменную вместо функции Для асинхронной базы лучше экспортировать функцию, которая возвращает результат

Смешивают Express и SQL в одном файле Для маленькой проверки это допустимо, но в нормальном проекте удобнее разделять роуты, бизнес-логику и доступ к базе

Не обрабатывают ошибку базы Если запрос упал, пользователь должен получить 500-ответ, а сервер не должен молча зависнуть

Что почитать дальше по Node.js

Если нужен общий маршрут по теме, откройте рубрику Node.js. Для соседних задач пригодятся эти разборы:

Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные

Настройки cookie

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x