Создание CRUD-приложения с помощью Node.js и MongoDB

Выбрать правильный инструмент для веб-приложения может быть непросто. Но если вы это сделаете, вам будет намного проще.

В зависимости от вашего приложения, сочетание Node.js и MongoDB в большинстве случаев работает хорошо — особенно если вы используете front-end фреймворк, такой как React (MERN), Angular (MEAN) или Vue (MEVN).

В этом руководстве вы узнаете, как создать CRUD-приложение с использованием Node.js и MongoDB и написать несколько основных тестов для API Node.js. Приложение будет подключаться к базе данных MongoDB и позволит пользователям создавать, читать, обновлять и удалять записи в блоге.

Давайте приступим!

Что такое MongoDB и почему вы должны выбрать именно ее?

MongoDB — это кросс-платформенная программа базы данных с открытым исходным кодом, ориентированная на работу с документами. Она классифицируется как система управления базами данных NoSQL и использует JSON-подобные документы с необязательными схемами.

Вот некоторые из причин, по которым компании и команды разработчиков всех размеров используют MongoDB:

  • Мощная модель документальных данных MongoDB позволяет разработчикам быстро хранить и извлекать данные в своих приложениях.
  • Она имеет отличный пользовательский интерфейс, который позволяет разработчикам установить MongoDB и сразу же начать писать код.
  • MongoDB Atlas доступна в любом крупном публичном облаке (включая AWS, Azure и Google Cloud), в крупных центрах обработки данных через редакцию Enterprise Advanced или бесплатно через редакцию Community с открытым исходным кодом. Горизонтальная, масштабируемая архитектура MongoDB может поддерживать огромные объемы данных и трафика.
  • MongoDB создала большую и хорошо развитую экосистему платформы. Она имеет глобальное сообщество разработчиков и консультантов, что упрощает получение помощи. Она также обеспечивает поддержку на уровне предприятия.

Мы будем использовать MongoDB в нашем приложении на Node.js, потому что Node.js имеет драйвер MongoDB Node.js, который реализует необходимый сетевой протокол и JavaScript API для легкого чтения и записи в локальную или удаленную базу данных MongoDB.

Предварительные условия

Чтобы начать работу с этим учебником, убедитесь, что у вас установлено следующее:

  • Node.js
  • база данных MongoDB
  • Postman

Настройка проекта Node.js

Теперь давайте начнем! Создайте новую папку и инициализируйте новый проект Node.js, выполнив приведенную ниже команду.

mkdir crud-with-mongodb && cd crud-with-mongodb
npm init -y
Войти в полноэкранный режим Выйти из полноэкранного режима

Приведенная выше команда создаст папку crud-with-MongoDB и инициализирует новый проект Node.js путем создания файла package.json.

Создайте новый файл и назовите его app.js в папке проекта. Это корневой файл для вашего проекта Node.js.

Теперь создайте приложение Node.js в файле app.js с помощью приведенного ниже фрагмента кода.

const express = require("express");
const app = express();

//middleware
app.use(express.json());

app.listen(3001, () => {
  console.log("Server is running on port 3001");
});

module.exports = app;
Вход в полноэкранный режим Выход из полноэкранного режима

Вы создали базовое приложение Node.js, которое будет работать на порту 3001, и добавили промежуточное ПО, которое будет разбирать данные в полезной нагрузке запроса.

Установка зависимостей для вашего проекта Node.js

Когда проект настроен, установите Express и Mongoose.

npm i express mongoose
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Вам также потребуется установить Mocha, Chai и chai-http в качестве dev-зависимостей, выполнив приведенную ниже команду.

npm i -D mocha chai chai-http
Войти в полноэкранный режим Выйти из полноэкранного режима

После завершения установки откройте файл package.json и измените скрипты со следующей конфигурацией.

...
"scripts": {
   "start": "node app.js",
   "test": "mocha --timeout 10000"
},
...
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы настроили сценарий запуска и тестирования для вашего приложения. Приложение будет запускать тесты приложения с помощью Mocha.

Настройка базы данных MongoDB для вашего приложения Node.js

Установив необходимые модули, откройте файл app.js и добавьте этот фрагмент кода, чтобы настроить MongoDB для вашего приложения.

...
const mongoose = require("mongoose");
//configure mongoose
mongoose.connect(
  process.env.MONGODB_URI || "mongodb://localhost/CRUD",
  {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  },
  (err) => {
    if (err) {
      console.log(err);
    } else {
      console.log("Connected to MongoDB");
    }
  }
);
...
Вход в полноэкранный режим Выход из полноэкранного режима

Вы импортировали пакет Mongoose и использовали метод connect для установления соединения с базой данных MongoDB.

Построение модели

Когда база данных MongoDB подключена к вашему приложению, создайте файл models/Blog.js в корневом каталоге проекта и добавьте следующее.

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const blogSchema = new Schema({
  title: String,
  body: String,
  image: String,
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model("Blog", blogSchema);
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы создали blogSchema и определили свойство. Затем, используя определенную схему, вы создали модель "Blog".

Создание служб

Создайте файл services/BlogService.js в корневом каталоге вашего проекта. Использование этого подхода для создания многократно используемой бизнес-логики является хорошей практикой, которая не позволит вам изобретать велосипед.

Откройте файл services/BlogService.js и добавьте приведенный ниже фрагмент кода.

const BlogModel = require("../models/Blog");

exports.getAllBlogs = async () => {
  return await BlogModel.find();
};

exports.createBlog = async (blog) => {
  return await BlogModel.create(blog);
};
exports.getBlogById = async (id) => {
  return await BlogModel.findById(id);
};

exports.updateBlog = async (id, blog) => {
  return await BlogModel.findByIdAndUpdate(id, blog);
};

exports.deleteBlog = async (id) => {
  return await BlogModel.findByIdAndDelete(id);
};
Вход в полноэкранный режим Выйти из полноэкранного режима

Это импортирует BlogModel из предыдущего раздела, чтобы построить CRUD-операции для вашего приложения.

Настройка контроллеров

Теперь вам нужны контроллеры для потребления созданных вами сервисов. Создайте файл controllers/BlogController.js в корневом каталоге проекта и добавьте в него этот код.

const blogService = require("../services/BlogService");

exports.getAllBlogs = async (req, res) => {
  try {
    const blogs = await blogService.getAllBlogs();
    res.json({ data: blogs, status: "success" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};

exports.createBlog = async (req, res) => {
  try {
    const blog = await blogService.createBlog(req.body);
    res.json({ data: blog, status: "success" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};

exports.getBlogById = async (req, res) => {
  try {
    const blog = await blogService.getBlogById(req.params.id);
    res.json({ data: blog, status: "success" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};

exports.updateBlog = async (req, res) => {
  try {
    const blog = await blogService.updateBlog(req.params.id, req.body);
    res.json({ data: blog, status: "success" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};

exports.deleteBlog = async (req, res) => {
  try {
    const blog = await blogService.deleteBlog(req.params.id);
    res.json({ data: blog, status: "success" });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
};
Вход в полноэкранный режим Выход из полноэкранного режима

Вы создали контроллеры и использовали сервисы для:

  • создать блог
  • получить все блоги
  • получить блог
  • обновить блог
  • удалить блог по его id

Мы используем try catch JavaScript для обработки ошибок и обеспечения того, чтобы сервер не отказал.

Мы возвращаем данные с status в "success" для каждого контроллера. Если произойдет ошибка, мы вернем ошибку со статусом 500.

Создание маршрутов для контроллеров

Теперь давайте создадим маршруты для контроллеров. Создайте файл routes/BlogRoutes.js в корневом каталоге проекта и добавьте фрагмент кода, приведенный ниже.

const express = require("express");
const {
  getAllBlogs,
  createBlog,
  getBlogById,
  updateBlog,
  deleteBlog,
} = require("../controllers/BlogController");

const router = express.Router();

router.route("/").get(getAllBlogs).post(createBlog);
router.route("/:id").get(getBlogById).put(updateBlog).delete(deleteBlog);

module.exports = router;
Вход в полноэкранный режим Выход из полноэкранного режима

Вы импортировали свои контроллеры и определили маршруты для каждого контроллера с помощью Express-маршрутизатора.

Теперь откройте файл app.js, импортируйте blogRouter и добавьте новое промежуточное ПО, чтобы ваше приложение могло использовать определенные маршруты.

...
const blogRouter = require("./routes/BlogRoutes");

...
app.use("/api/blogs", blogRouter);
...
Вход в полноэкранный режим Выход из полноэкранного режима

Когда вы отправляете запрос на маршрут /api/blogs, Express проверит маршруты в папке routes и запросит маршруты, соответствующие URL.

Написание автоматических тестов

Автоматические тесты крайне важны для каждого веб-приложения. Они экономят ваше время, которое иначе пришлось бы потратить на выполнение повторяющихся тестов, чтобы проверить, работает ли ваш код так, как ожидалось. Вы также избежите дополнительных расходов, связанных с выполнением повторяющихся тестов.

Вам нужно написать несколько автоматизированных тестов, чтобы убедиться, что ваш API работает так, как ожидается, и вы сделаете это с помощью модуля chai.

Чтобы начать, создайте файл test/test.js в корневом каталоге проекта и добавьте следующее.

const Blog = require("../models/Blog");
const chai = require("chai");
const chaiHttp = require("chai-http");
const app = require("../app");
chai.should();

chai.use(chaiHttp);

describe("Blogs", () => {
  beforeEach((done) => {
    Blog.deleteMany({}, (err) => {
      done();
    });
  });
  describe("/GET blog", () => {
    it("it should GET all the blogs", (done) => {
      chai
        .request(app)
        .get("/api/blogs")
        .end((err, res) => {
          res.should.have.status(200);
          res.body.data.should.be.a("array");
          res.body.data.length.should.be.eql(0);
          done();
        });
    });
  });
  describe("/POST blog", () => {
    it("it should new POST a blog", (done) => {
      let blog = {
        title: "This is the first blog",
        body: "This is a blog post",
        image:
          "https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
      };
      chai
        .request(app)
        .post("/api/blogs")
        .send(blog)
        .end((err, res) => {
          res.should.have.status(200);
          res.body.data.should.be.a("object");
          res.body.status.should.be.eql("success");
          done();
        });
    });
  });
  describe("/GET/:id blog", () => {
    it("it should GET a blog by the id", (done) => {
      let blog = new Blog({
        title: "This is the first blog",
        body: "This is a blog post",
        image:
          "https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
      });
      blog.save((err, blog) => {
        chai
          .request(app)
          .get("/api/blogs/" + blog.id)
          .send(blog)
          .end((err, res) => {
            res.should.have.status(200);
            res.body.data.should.be.a("object");
            res.body.status.should.be.eql("success");
            done();
          });
      });
    });
  });
  describe("/PUT/:id blog", () => {
    it("it should UPDATE a blog given the id", (done) => {
      let blog = new Blog({
        title: "This is the first blog",
        body: "This is a blog post",
        image:
          "https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
      });
      blog.save((err, blog) => {
        console.log(blog.id);
        chai
          .request(app)
          .put("/api/blogs/" + blog.id)
          .send({
            title: "The first blog was updated",
            body: "This is a blog post",
            image:
              "https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
          })
          .end((err, res) => {
            res.should.have.status(200);
            res.body.data.should.be.a("object");
            res.body.status.should.be.eql("success");
            done();
          });
      });
    });
  });
  describe("/DELETE/:id blog", () => {
    it("it should DELETE a blog given the id", (done) => {
      let blog = new Blog({
        title: "This is the first blog",
        body: "This is a blog post",
        image:
          "https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
      });
      blog.save((err, blog) => {
        chai
          .request(app)
          .delete("/api/blogs/" + blog.id)
          .end((err, res) => {
            res.should.have.status(200);
            res.body.data.should.be.a("object");
            res.body.status.should.be.eql("success");
            done();
          });
      });
    });
  });
});
Вход в полноэкранный режим Выйти из полноэкранного режима

Перед запуском каждого теста мы удаляем все записи в базе данных, чтобы каждый тест начинался с чистого листа. Для всех маршрутов мы ожидаем, что ответ будет содержать объект blog. Мы также ожидаем, что все маршруты вернут status в "success", если все пройдет успешно.

Теперь выполните приведенную ниже команду, чтобы увидеть результат тестов.

npm run test
Войти в полноэкранный режим Выйти из полноэкранного режима

В приведенном выше коде мы использовали модуль chai, который мы установили ранее, для написания автоматизированных тестов для приложения. Мы начали с импорта модуля chai, модели Blog и модуля chai-http для запуска сервера. Модуль chai предоставляет метод describe для описания того, что делает тест. Затем, используя метод it, мы описываем результат каждого теста.

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

Итак, если все идет хорошо с тестами, вы должны увидеть результат, подобный этому.

Тестирование приложения Node.js с помощью Postman

Теперь давайте протестируем приложение с помощью Postman. Postman — это инструмент тестирования RESTful API, который может помочь вам протестировать ваш API или проверить работу API. Он предоставляет удобный пользовательский интерфейс для отправки HTTP-запросов.

Мы начнем с маршрута createBlog и передадим в тело запроса объект ниже в виде JSON.

{
  "title": "The first blog was updated",
  "body": "This is a blog post",
  "image":"https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60"
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы можете увидеть это на скриншоте ниже.

Теперь протестируйте маршрут getAllBlogs.

Протестируйте маршруты получения, обновления и удаления блогов и посмотрите, как все работает.

Подведение итогов и следующие шаги

В этом посте вы узнали, как создать CRUD-приложение с помощью Node.js и MongoDB.

Мы начали со знакомства с MongoDB и рассмотрели, почему разработчик будет использовать ее, прежде чем создать простой API для блога.

Как вы будете использовать Node.js и MongoDB в своем следующем проекте? Не стесняйтесь клонировать проект из этого учебника и поиграть с его возможностями.

Счастливого кодинга!

P.S. Если вам понравился этот пост, подпишитесь на наш список JavaScript Sorcery для ежемесячного глубокого погружения в более волшебные советы и трюки JavaScript.

P.P.S. Если вам нужен APM для вашего Node.js приложения, обратите внимание на AppSignal APM для Node.js.

Оцените статью
devanswers.ru
Добавить комментарий