Опираясь на мой последний пост, посвященный Express.js, мы собираемся расширить функциональность нашего приложения, создав приложение To Do и сохраняя данные локально с помощью MongoDB.

Этот пример больше подходит для Express + MongoDB, чем для React Native. Я предоставил шаблонный код с рабочим интерфейсом, чтобы вы начали:



Разверните репо, затем откройте два терминала, перейдите в каталог проекта и введите следующие команды:

Терминал 1 = › /client

cd client
yarn

Терминал 1 = › /backend

cd backend
yarn

Давайте рассмотрим зависимости нашего внутреннего интерфейса. Если вы откроете свой package.json, вы увидите следующее:

{
  "name": "mernn-todo-boilerplate",
  "version": "1.0.0",
    "scripts": {
      "client": "cd client && yarn start",
      "server": "nodemon server.js",
      "dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
     },
  "dependencies": {
    "body-parser": "^1.18.3",
    "cors": "^2.8.5",
    "dotenv": "^8.2.0",
    "express": "^4.16.4",
    "mongoose": "^5.8.9",
    "morgan": "^1.9.1",
    "nodemon": "^2.0.2"
   },
  "devDependencies": {
    "concurrently": "^4.0.1"
     }
   }

Наши зависимости от Express: express, body-parser и morgan. mongoose - это библиотека моделирования объектных данных (ODM) для MongoDB и Node. Он управляет отношениями между данными, обеспечивает проверку схемы и используется для преобразования между объектами в коде и представлением этих объектов в MongoDB. nodemon - это утилита, которая отслеживает любые изменения в вашем источнике и автоматически перезагружает ваш сервер. dotenv - это модуль с нулевой зависимостью, который загружает переменные среды из файла .env в process.

Теперь давайте посмотрим на настройку нашего внутреннего каталога. У нас есть server.js файл, в котором будет жить вся логика нашего серверного / экспресс-приложения. У нас есть каталог для моделей данных, в котором мы будем создавать и определять, что составляет «задачу». Затем у нас есть каталог маршрутов и todos.routes.js файл, в котором будет реализована вся наша логика маршрутизации. Node, на котором построен Express, очень хорошо работает с CommonJS, поэтому мы будем использовать операторы require и сторонние модули, когда они нам понадобятся.

Давайте начнем с расширения нашей базы данных MongoDB. Для этого убедитесь, что на вашем компьютере скачан mongo.



Предпосылки:

  1. У вас должен быть установлен Homebrew
  2. Вам необходимо установить xCode

В вашем терминале в корневом каталоге вашего компьютера выполните следующие команды:

brew tap mongodb/brew
brew install [email protected]

Теперь, когда MongoDB установлен, выполните следующие команды для создания БД:

mongo
use todos

Давайте введем код.

Откройте server.js и давайте установим соединение с нашей новой локальной базой данных.

server.js

...
app.use(bodyParser.json());
mongoose.connect("mongodb://127.0.0.1:27017/tasks", { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once("open", function() {
    console.log("MongoDB database connection established successfully");
});
...

Большой. Теперь давайте проверим соединение, раскрутив наш сервер. Откройте терминал, перейдите в внутренний каталог и выполните следующую команду:

node server.js

Вы должны увидеть следующий вывод вашего терминала:

Теперь давайте настроим нашу модель данных To-Do. Откройте /models/todos.model.js, мы будем использовать модуль схемы mongoose для построения нашей модели данных.

/models/todos.model.js

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
let Todo = new Schema(
{
 todo_description: {
   type: String
  },
 todo_responsible: {
   type: String
  },
 todo_priority: {
   type: String
  },
 todo_completed: {
   type: Boolean
  }
 },
  { timestamps: true }
 );
module.exports = mongoose.model("ToDo", Todo);

В новой схеме мы определяем ключи для базы данных и принимаемые значения. Mongo сгенерирует идентификаторы и временные метки. Теперь давайте настроим нашу логику маршрута. Откройте routes/routes.js, чтобы начать.

Мы будем использовать модуль Express Router в этом файле для настройки логики. Мы также собираемся импортировать нашу только что созданную модель Todo. Я добавил несколько маршрутов, чтобы начать работу, поэтому все, что нам нужно сделать, это добавить логику. Начнем с нашего GET запроса. Поэтому, когда наш интерфейс делает запрос http://localhost:3000/todos/, мы отправляем ответ, содержащий все наши задачи.

router.route("/").get((req, res) => {
  Todo.find(function(err, todos) {
    if (err) {
     console.log(err);
    } else {
     res.json(todos);
    }
  });
 });

Достаточно просто! Но, допустим, мы хотим иметь возможность отображать неполные задачи отдельно от завершенных без необходимости реализации какой-либо сложной логики во внешнем интерфейсе. Чтобы не тянуть за волосы, давайте создадим собственный маршрут для выполненных и незавершенных задач.

router.route("/completed").get((req, res) => {
  Todo.find(function(err, todos) {
   if (err) {
    console.log(err);
   } else {
    let completedTodos = todos.filter(todo => todo.todo_completed);
    res.json(completedTodos);
   }
  });
});
router.route("/incomplete").get((req, res) => {
 Todo.find(function(err, todos) {
    if (err) {
     console.log(err);
    } else {
    let incompleteTodos = todos.filter(todo => !todo.todo_completed);    
    res.json(incompleteTodos);
    }
  });
});

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

router.route("/:id").get((req, res) => {
  let id = req.params.id;
    Todo.findById(id, (err, todo) => {
   res.json(todo);
  });
});

Если наш интерфейс делает запрос к http://localhost:3000/1234, наш сервер отправит обратно эту единственную задачу. Это касается наших GET запросов, давайте перейдем к следующему маршруту RESTful. Чтобы добавить задачу, нам нужно будет сделать POST запрос из нашего внешнего интерфейса.

router.route("/add").post((req, res) => {
   const todo = new Todo(req.body);
   todo
    .save()
    .then(todo => {
        res
         .status(200)
         .json({ addedTodo: todo, todos: "Task added successfully." });
     })
     .catch(err => {
         res.status(400).json({ todos: "ERROR: Task could not be added." });
     });
 });

И в качестве последнего маршрута давайте рассмотрим логику PATCH, чтобы мы могли обновлять задачи (отмечать их как выполненные).

router.route("/update/:id").post(function(req, res) {
   Todo.findById(req.params.id, function(err, todo) {
     if (!todo) res.status(404).send("data is not found");
     else todo.todo_description = req.body.todo_description;
          todo.todo_responsible = req.body.todo_responsible;
          todo.todo_priority = req.body.todo_priority;
          todo.todo_completed = req.body.todo_completed;
    todo
      .save()
      .then(todo => {
        res.json("Task Updated!");
       })
      .catch(err => {
        res.status(400).send("Cannot update task");
       });
   });
 });

Вернитесь к своему server.js файлу, чтобы мы могли связать все вместе. Это соглашение об отделении маршрутов от вашего файла сервера не обязательно, но оно делает код более кратким. Вы можете поместить всю логику маршрутов в server.js, но вскоре файл станет очень длинным и запутанным. Далее все, что нам нужно сделать, это указать нашему приложению Express использовать роутер todos. Мы можем добиться этого, добавив следующий код в server.js:

...
const todosRouter = require("./routes/todos");
app.use("/todos", todosRouter);
app.listen(PORT, function() {
   console.log("Server is running on Port: " + PORT);
});

Вот и все! Наша внутренняя логика настроена для простого приложения To-Do. Мы можем раскрутить оба, чтобы проверить это. Откройте отдельные терминалы и введите следующее:

Терминал 1 = ›/ клиент

cd client
yarn start

Терминал 2 = ›/ backend

cd backend
node server.js

Хорошо пойти! Если все было добавлено правильно (или я не ошибся), вы должны увидеть следующее:

Добавьте несколько задач:

Выполните одно или два задания:

Вот и все. Вы создали сервер Express и сохранили данные в локальной базе данных, предоставленной MongoDB. Не так уж и сложно, правда? Этого никогда не бывает.

Продолжайте шлифовать!