Как интегрировать MongoDB с вашим Node-приложением

Вступление

Работая сNode.js, вы можете обнаружить, что разрабатываете проект, который хранит и запрашивает данные. В этом случае вам нужно будет выбрать решение для базы данных, которое имеет смысл для данных вашего приложения и типов запросов.

В этом руководстве вы интегрируете базу данныхMongoDB с существующим приложением Node. NoSQL databases, такие как MongoDB, могут быть полезны, если ваши требования к данным включают масштабируемость и гибкость. MongoDB также хорошо интегрируется с Node, поскольку он предназначен для асинхронной работы с объектамиJSON.

Чтобы интегрировать MongoDB в свой проект, вы будете использоватьObject Document Mapper (ODM)Mongoose для создания схем и моделей для данных вашего приложения. Это позволит вам организовать код вашего приложения в соответствии с архитектурным шаблономmodel-view-controller (MVC), который позволяет вам отделить логику того, как ваше приложение обрабатывает ввод пользователя, от того, как ваши данные структурированы и отображаются для пользователя. Использование этого шаблона может облегчить дальнейшее тестирование и разработку путем введения разделения проблем в вашу кодовую базу.

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

Shark Output

Предпосылки

  • Локальная машина или сервер разработки под управлением Ubuntu 18.04 вместе с пользователем без полномочий root с привилегиямиsudo и активным брандмауэром. Инструкции по их настройке на сервере 18.04 см. ВInitial Server Setup guide.

  • Node.js and npm installed on your machine or server, following these instructions on installing with the PPA managed by NodeSource.

  • MongoDB, установленный на вашем компьютере или сервере, после шага 1How To Install MongoDB in Ubuntu 18.04.

[[step-1 -—- created-a-mongo-user]] == Шаг 1. Создание пользователя Mongo

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

Сначала убедитесь, что MongoDB работает на вашем сервере:

sudo systemctl status mongodb

Следующий вывод показывает, что MongoDB работает:

Output● mongodb.service - An object/document-oriented database
   Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2019-01-31 21:07:25 UTC; 21min ago
...

Затем откройте оболочку Mongo, чтобы создать своего пользователя:

mongo

Это поместит вас в административную оболочку:

OutputMongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
...
>

Когда вы откроете оболочку, вы увидите несколько административных предупреждений из-за вашего неограниченного доступа к базе данныхadmin. Вы можете узнать больше об ограничении этого доступа, прочитавHow To Install and Secure MongoDB on Ubuntu 16.04, когда вы переходите к производственной установке.

На данный момент вы можете использовать свой доступ к базе данныхadmin, чтобы создать пользователя с привилегиямиuserAdminAnyDatabase, который позволит защищенный паролем доступ к базам данных вашего приложения.

В оболочке укажите, что вы хотите использовать базу данныхadmin для создания своего пользователя:

use admin

Затем создайте роль и пароль, добавив имя пользователя и пароль с помощью командыdb.createUser. После ввода этой команды оболочка будет добавлять три точки перед каждой строкой, пока команда не будет завершена. Обязательно замените предоставленные здесь имя пользователя и пароль на свое имя пользователя и пароль:

db.createUser(
  {
    user: "sammy",
    pwd: "your_password",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)

Это создает запись для пользователяsammy в базе данныхadmin. Выбранное вами имя пользователя и база данныхadmin будут служить идентификаторами для вашего пользователя.

Вывод для всего процесса будет выглядеть следующим образом, включая сообщение о том, что запись прошла успешно:

Output> db.createUser(
...  {
...    user: "sammy",
...    pwd: "your_password",
...    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
...  }
...)
Successfully added user: {
        "user" : "sammy",
        "roles" : [
                {
                        "role" : "userAdminAnyDatabase",
                        "db" : "admin"
                }
        ]
}

Создав свой пароль и пользователь, вы можете выйти из оболочки Mongo:

exit

Теперь, когда вы создали пользователя базы данных, вы можете перейти к клонированию кода начального проекта и добавлению библиотеки Mongoose, которая позволит вам реализовывать схемы и модели для коллекций в ваших базах данных.

[[step-2 -—- add-mongoose-and-database-information-to-the-project]] == Шаг 2 - Добавление информации о мангусте и базе данных в проект

Следующими нашими шагами будет клонирование начального кода приложения и добавление в проект данных Mongoose и нашей базы данных MongoDB.

В домашнем каталоге пользователя без полномочий root клонируйтеnodejs-image-demo repository изDigitalOcean Community GitHub account. Этот репозиторий включает код из настройки, описанной вHow To Build a Node.js Application with Docker.

Клонируйте репозиторий в каталог с именемnode_project:

git clone https://github.com/do-community/nodejs-image-demo.git node_project

Перейдите в каталогnode_project:

cd  node_project

Прежде чем изменять код проекта, давайте взглянем на структуру проекта с помощью командыtree.

[.Примечание]##

Tip:tree - полезная команда для просмотра структур файлов и каталогов из командной строки. Вы можете установить его с помощью следующей команды:

sudo apt install tree

Чтобы использовать его, введитеcd в указанный каталог и введитеtree. Вы также можете указать путь к начальной точке с помощью такой команды:

tree /home/sammy/sammys-project

Введите следующее, чтобы просмотреть каталогnode_project:

tree

Структура текущего проекта выглядит следующим образом:

Output├── Dockerfile
├── README.md
├── app.js
├── package-lock.json
├── package.json
└── views
    ├── css
    │   └── styles.css
    ├── index.html
    └── sharks.html

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

Затем добавьте в проект пакетmongoose npm с помощью командыnpm install:

npm install mongoose

Эта команда создаст каталогnode_modules в каталоге вашего проекта, используя зависимости, перечисленные в файле проектаpackage.json, и добавитmongoose в этот каталог. Он также добавитmongoose к зависимостям, перечисленным в вашем файлеpackage.json. Для более подробного обсужденияpackage.json см.Step 1 вHow To Build a Node.js Application with Docker.

Перед созданием любых схем или моделей Mongoose мы добавим информацию о подключении к нашей базе данных, чтобы наше приложение могло подключиться к нашей базе данных.

Чтобы максимально разделить проблемы вашего приложения, создайте отдельный файл для информации о соединении с базой данных с именемdb.js. Вы можете открыть этот файл с помощьюnano или вашего любимого редактора:

nano db.js

Сначала импортируйтеmongoosemodule с помощью функцииrequire:

~/node_project/db.js

const mongoose = require('mongoose');

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

Затем добавьте следующиеconstants, чтобы определить информацию для URI подключения Mongo. Хотя имя пользователя и пароль необязательны, мы включим их, чтобы мы могли требовать аутентификацию для нашей базы данных. Обязательно замените имя пользователя и пароль, указанные ниже, на свою собственную информацию и не стесняйтесь называть базу данных чем-то другим, кроме'sharkinfo', если вы предпочитаете:

~/node_project/db.js

const mongoose = require('mongoose');

const MONGO_USERNAME = 'sammy';
const MONGO_PASSWORD = 'your_password';
const MONGO_HOSTNAME = '127.0.0.1';
const MONGO_PORT = '27017';
const MONGO_DB = 'sharkinfo';

Поскольку наша база данных работает локально, мы использовали127.0.0.1 в качестве имени хоста. Это изменится в других контекстах разработки: например, если вы используете отдельный сервер базы данных или работаете с несколькими узлами в контейнерном рабочем процессе.

Наконец, определите константу для URI и создайте соединение с помощью методаmongoose.connect():

~/node_project/db.js

...
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

mongoose.connect(url, {useNewUrlParser: true});

Обратите внимание, что в URI мы указалиauthSource для нашего пользователя как базу данныхadmin. Это необходимо, поскольку мы указали имя пользователя в нашей строке подключения. Использование флагаuseNewUrlParser сmongoose.connect() указывает, что мы хотим использовать Mongo'snew URL parser.

Сохраните и закройте файл, когда вы закончите редактирование.

В качестве последнего шага добавьте информацию о подключении к базе данных в файлapp.js, чтобы приложение могло его использовать. Открытьapp.js:

nano app.js

Первые строки файла будут выглядеть так:

~/node_project/app.js

const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
...

Под определением константыrouter, расположенным в верхней части файла, добавьте следующую строку:

~/node_project/app.js

...
const router = express.Router();
const db = require('./db');

const path = __dirname + '/views/';
...

Это указывает приложению использовать информацию о соединении с базой данных, указанную вdb.js.

Сохраните и закройте файл, когда вы закончите редактирование.

Имея информацию о вашей базе данных и добавив Mongoose в ваш проект, вы готовы создавать схемы и модели, которые будут формировать данные в вашей коллекцииsharks.

[[step-3 -—- created-mongoose-schemas-and-models]] == Шаг 3 - Создание схем и моделей Mongoose

Нашим следующим шагом будет подумать о структуре коллекцииsharks, которую пользователи будут создавать в базе данныхsharkinfo со своими входными данными. Какую структуру мы хотим, чтобы эти созданные документы имели? Страница с информацией об акулах нашего текущего приложения содержит некоторые сведения о различных акулах и их поведении:

Shark Info Page

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

Чтобы ваши схемы и модели отличались от других частей вашего приложения, создайте каталогmodels в каталоге текущего проекта:

mkdir models

Затем откройте файл с именемsharks.js, чтобы создать схему и модель:

nano models/sharks.js

Импортируйте модульmongoose в начало файла:

~/node_project/models/sharks.js

const mongoose = require('mongoose');

Ниже определите объектSchema, который будет использоваться в качестве основы для вашей схемы акулы:

~/node_project/models/sharks.js

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

Теперь вы можете определить поля, которые вы хотели бы включить в свою схему. Поскольку мы хотим создать коллекцию с отдельными акулами и информацией об их поведении, давайте добавим ключиnamekey иcharacter. Добавьте следующую схемуShark под определениями констант:

~/node_project/models/sharks.js

...
const Shark = new Schema ({
        name: { type: String, required: true },
        character: { type: String, required: true },
});

Это определение включает информацию о типе ввода, который мы ожидаем от пользователей - в данном случаеstring - и о том, требуется ли этот ввод.

Наконец, создайте модельShark с помощью Mongoosemodel() function. Эта модель позволит вам запрашивать документы из вашей коллекции и проверять новые документы. Добавьте следующую строку внизу файла:

~/node_project/models/sharks.js

...
module.exports = mongoose.model('Shark', Shark)

Эта последняя строка делает нашу модельShark доступной в виде модуля с использованиемmodule.exports property. Это свойство определяет значения, которые модуль будет экспортировать, делая их доступными для использования в другом месте приложения.

Готовый файлmodels/sharks.js выглядит так:

~/node_project/models/sharks.js

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

const Shark = new Schema ({
        name: { type: String, required: true },
        character: { type: String, required: true },
});

module.exports = mongoose.model('Shark', Shark)

Сохраните и закройте файл, когда вы закончите редактирование.

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

[[step-4 -—- Creating-controllers]] == Шаг 4 - Создание контроллеров

Нашим следующим шагом будет создание компонента контроллера, который будет определять, как вводимые пользователем данные сохраняются в нашей базе данных и возвращаются пользователю.

Сначала создайте каталог для контроллера:

mkdir controllers

Затем откройте в этой папке файл с именемsharks.js:

nano controllers/sharks.js

В верхней части файла мы импортируем модуль с нашей модельюShark, чтобы мы могли использовать его в логике нашего контроллера. Мы также импортируемpath module для доступа к утилитам, которые позволят нам указать путь к форме, в которую пользователи будут вводить своих акул.

Добавьте в начало файла следующие функцииrequire:

~/node_project/controllers/sharks.js

const path = require('path');
const Shark = require('../models/sharks');

Затем мы напишем последовательность функций, которые мы будем экспортировать с модулем контроллера, используяexports shortcut узла. Эти функции будут включать в себя три задачи, связанные с данными об акулах нашего пользователя:

  • Отправка пользователям формы ввода акулы.

  • Создание новой записи акулы.

  • Отображение акул обратно к пользователям.

Для начала создайте функциюindex для отображения страницы акул с формой ввода. Добавьте эту функцию ниже вашего импорта:

~/node_project/controllers/sharks.js

...
exports.index = function (req, res) {
    res.sendFile(path.resolve('views/sharks.html'));
};

Затем под функциейindex добавьте функцию с именемcreate, чтобы сделать новую запись акулы в вашей коллекцииsharks:

~/node_project/controllers/sharks.js

...
exports.create = function (req, res) {
    var newShark = new Shark(req.body);
    console.log(req.body);
    newShark.save(function (err) {
            if(err) {
            res.status(400).send('Unable to save shark to database');
        } else {
            res.redirect('/sharks/getshark');
        }
  });
               };

Эта функция будет вызываться, когда пользователь отправляет данные об акулах в форму на страницеsharks.html. Мы создадим маршрут с этой конечной точкой POST позже в руководстве, когда создадим маршруты нашего приложения. С помощьюbody запроса POST наша функцияcreate создаст новый объект документа акулы, здесь называемыйnewShark, используя модельShark, которую мы импортировали. Мы добавилиconsole.log method для вывода записи об акуле в консоль, чтобы проверить, работает ли наш метод POST, как задумано, но вы можете пропустить это, если хотите.

Используя объектnewShark, функцияcreate затем вызоветmodel.save() method Mongoose, чтобы создать новый документ акулы, используя ключи, которые вы определили в моделиShark. Этотcallback function следует заstandard Node callback pattern:callback(error, results). В случае ошибки мы отправим сообщение об ошибке нашим пользователям, а в случае успеха мы будем использоватьres.redirect() method для отправки пользователей на конечную точку, которая вернет им информацию об их акулах. в браузере.

Наконец, функцияlist вернет пользователю содержимое коллекции. Добавьте следующий код под функциейcreate:

~/node_project/controllers/sharks.js

...
exports.list = function (req, res) {
        Shark.find({}).exec(function (err, sharks) {
                if (err) {
                        return res.send(500, err);
                }
                res.render('getshark', {
                        sharks: sharks
             });
        });
};

Эта функция использует модельShark сmodel.find() method Mongoose для возврата акул, которые были введены в коллекциюsharks. Он делает это, возвращая объект запроса - в данном случае все записи в коллекцииsharks - в качестве обещания, используяexec() function Mongoose. В случае ошибки функция обратного вызова отправит ошибку 500.

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

Готовый файл будет выглядеть так:

~/node_project/controllers/sharks.js

const path = require('path');
const Shark = require('../models/sharks');

exports.index = function (req, res) {
    res.sendFile(path.resolve('views/sharks.html'));
};

exports.create = function (req, res) {
    var newShark = new Shark(req.body);
    console.log(req.body);
    newShark.save(function (err) {
            if(err) {
            res.status(400).send('Unable to save shark to database');
        } else {
            res.redirect('/sharks/getshark');
        }
  });
               };

exports.list = function (req, res) {
        Shark.find({}).exec(function (err, sharks) {
                if (err) {
                        return res.send(500, err);
                }
                res.render('getshark', {
                        sharks: sharks
             });
        });
};

Имейте в виду, что хотя мы не используем здесьarrow functions, вы можете захотеть включить их при повторении этого кода в своем собственном процессе разработки.

Сохраните и закройте файл, когда вы закончите редактирование.

Перед тем как перейти к следующему шагу, вы можете снова запуститьtree из каталогаnode_project, чтобы просмотреть структуру проекта на этом этапе. На этот раз для краткости мы скажемtree опустить каталогnode_modules, используя параметр-I:

tree -I node_modules

С учетом внесенных вами изменений структура вашего проекта будет выглядеть следующим образом:

Output├── Dockerfile
├── README.md
├── app.js
├── controllers
│   └── sharks.js
├── db.js
├── models
│   └── sharks.js
├── package-lock.json
├── package.json
└── views
    ├── css
    │   └── styles.css
    ├── index.html
    └── sharks.html

Теперь, когда у вас есть компонент контроллера, который управляет тем, как пользовательский ввод сохраняется и возвращается пользователю, вы можете перейти к созданию представлений, которые будут реализовывать логику вашего контроллера.

[[step-5 -—- using-ejs-and-express-middleware-to-collect-and-render-data]] == Шаг 5. Использование EJS и Express Middleware для сбора и визуализации данных

Чтобы наше приложение могло работать с пользовательскими данными, мы сделаем две вещи: во-первых, мы включим встроенную функцию промежуточного программного обеспечения Express,urlencoded(), которая позволит нашему приложению анализировать введенные пользователем данные. Во-вторых, мы добавим теги шаблона в наши представления, чтобы обеспечить динамическое взаимодействие с пользовательскими данными в нашем коде.

Чтобы работать с функциейurlencoded() в Express, сначала откройте файлapp.js:

nano app.js

Над функциейexpress.static() добавьте следующую строку:

~/node_project/app.js

...
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
...

Добавление этой функции позволит получить доступ к проанализированным данным POST из нашей формы информации об акулах. Мы указываемtrue с параметромextended, чтобы обеспечить большую гибкость в типе данных, которые наше приложение будет анализировать (включая такие вещи, как вложенные объекты). Пожалуйста, смотритеfunction documentation для получения дополнительной информации о параметрах.

Сохраните и закройте файл, когда вы закончите редактирование.

Далее мы добавим функциональность шаблона к нашим представлениям. Сначала установитеejs package сnpm install:

npm install ejs

Затем откройте файлsharks.html в папкеviews:

nano views/sharks.html

На шаге 3 мы посмотрели на эту страницу, чтобы определить, как мы должны написать нашу схему и модель Mongoose:

Shark Info Page

Теперь вместо двух столбцовlayout мы представим третий столбец с формой, в которую пользователи могут вводить информацию об акулах.

В качестве первого шага измените размеры существующих столбцов на4, чтобы создать три столбца одинакового размера. Обратите внимание, что вам нужно будет внести это изменение в две строки, которые в настоящее время читают<div class="col-lg-6">. Оба они станут<div class="col-lg-4">:

~/node_project/views/sharks.html

...

Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
Sawshark

Other sharks are known to be friendly and welcoming!
Sammy the Shark

Для ознакомления с сеточной системой Bootstrap, включая макеты строк и столбцов, см. Этотintroduction to Bootstrap.

Затем добавьте еще один столбец, который включает именованную конечную точку для запроса POST с данными акулы пользователя и тегами шаблона EJS, которые будут захватывать эти данные. Этот столбец будет находиться под закрывающими тегами</p> и</div> из предыдущего столбца и над закрывающими тегами для строки, контейнера и HTML-документа. Эти закрывающие теги уже есть в вашем коде; они также отмечены ниже с комментариями. Оставьте их на месте, добавив следующий код для создания нового столбца:

~/node_project/views/sharks.html

...
       

Enter Your Shark

В тегеform вы добавляете конечную точку"/sharks/addshark" для данных об акулах пользователя и указываете метод POST для их отправки. В полях ввода вы указываете поля для"Shark Name" и"Shark Character" в соответствии с модельюShark, которую вы определили ранее.

Чтобы добавить вводимые пользователем данные в коллекциюsharks, вы используете теги шаблона EJS (<%=,%>) вместе с синтаксисом JavaScript, чтобы сопоставить записи пользователя с соответствующими полями во вновь созданном документ. Дополнительные сведения об объектах JavaScript см. В нашей статье оUnderstanding JavaScript Objects. Дополнительные сведения о тегах шаблонов EJS см. ВEJS documentation.

Весь контейнер со всеми тремя столбцами, включая столбец с вашей формой ввода акулы, будет выглядеть следующим образом:

~/node_project/views/sharks.html

...

Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
Sawshark

Other sharks are known to be friendly and welcoming!
Sammy the Shark

Enter Your Shark

Сохраните и закройте файл, когда вы закончите редактирование.

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

Скопируйте недавно измененный файлsharks.html в файл с именемgetshark.html:

cp views/sharks.html views/getshark.html

Открытьgetshark.html:

nano views/getshark.html

Внутри файла мы изменим столбец, который мы использовали для создания формы ввода акул, заменив его столбцом, в котором будут отображаться акулы из нашей коллекцииsharks. Опять же, ваш код будет находиться между существующими тегами</p> и</div> из предыдущего столбца и закрывающими тегами для строки, контейнера и HTML-документа. Не забудьте оставить эти теги на месте при добавлении следующего кода для создания столбца:

~/node_project/views/getshark.html

...
       

Your Sharks
    <% sharks.forEach(function(shark) { %>

    Name: <%= shark.name %>

    Character: <%= shark.character %>

    <% }); %>

Здесь вы используете теги шаблона EJS иforEach() method для вывода каждого значения в вашей коллекцииsharks, включая информацию о последней добавленной акуле.

Весь контейнер со всеми тремя столбцами, включая столбец с вашей коллекциейsharks, после завершения будет выглядеть так:

~/node_project/views/getshark.html

...

Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
Sawshark

Other sharks are known to be friendly and welcoming!
Sammy the Shark

Your Sharks
    <% sharks.forEach(function(shark) { %>

    Name: <%= shark.name %>

    Character: <%= shark.character %>

    <% }); %>

Сохраните и закройте файл, когда вы закончите редактирование.

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

nano app.js

Выше того места, где вы добавили функциюexpress.urlencoded(), добавьте следующие строки:

~/node_project/app.js

...
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));

...

Методapp.engine указывает приложению сопоставить механизм шаблонов EJS с файлами HTML, аapp.set определяет механизм просмотра по умолчанию.

Ваш файлapp.js теперь должен выглядеть так:

~/node_project/app.js

const express = require('express');
const app = express();
const router = express.Router();
const db = require('./db');

const path = __dirname + '/views/';
const port = 8080;

router.use(function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/',function(req,res){
  res.sendFile(path + 'index.html');
});

router.get('/sharks',function(req,res){
  res.sendFile(path + 'sharks.html');
});

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

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

[[step-6 -—- Creating-routes]] == Шаг 6 - Создание маршрутов

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

Сначала создайте каталогroutes:

mkdir routes

Затем откройте в этом каталоге файл с именемindex.js:

nano routes/index.js

Этот файл сначала импортирует объектыexpress,router иpath, что позволит нам определить маршруты, которые мы хотим экспортировать с помощью объектаrouter, и сделав возможным работать динамически с путями к файлам. Добавьте следующий код вверху файла:

~/node_project/routes/index.js

const express = require('express');
const router = express.Router();
const path = require('path');

Затем добавьте следующую функциюrouter.use, которая загружаетmiddleware function, который будет регистрировать запросы маршрутизатора и передавать их в маршрут приложения:

~/node_project/routes/index.js

...

router.use (function (req,res,next) {
  console.log('/' + req.method);
  next();
});

Сначала запросы к корню нашего приложения будут направлены сюда, и отсюда пользователи будут перенаправлены на целевую страницу нашего приложения, маршрут, который мы определим следующим. Добавьте следующий код под функциейrouter.use, чтобы определить маршрут к целевой странице:

~/node_project/routes/index.js

...

router.get('/',function(req,res){
  res.sendFile(path.resolve('views/index.html'));
});

Когда пользователи посещают наше приложение, мы в первую очередь хотим отправить их на целевую страницуindex.html, которая находится в нашем каталогеviews.

Наконец, чтобы сделать эти маршруты доступными как импортируемые модули в другом месте приложения, добавьте закрывающее выражение в конец файла для экспорта объектаrouter:

~/node_project/routes/index.js

...

module.exports = router;

Готовый файл будет выглядеть так:

~/node_project/routes/index.js

const express = require('express');
const router = express.Router();
const path = require('path');

router.use (function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/',function(req,res){
  res.sendFile(path.resolve('views/index.html'));
});

module.exports = router;

Сохраните и закройте этот файл, когда вы закончите редактирование.

Затем откройте файл с именемsharks.js, чтобы определить, как приложение должно использовать различные конечные точки и представления, которые мы создали для работы с вводом акулы нашего пользователя:

nano routes/sharks.js

Вверху файла импортируйте объектыexpress иrouter:

~/node_project/routes/sharks.js

const express = require('express');
const router = express.Router();

Затем импортируйте модуль с именемshark, который позволит вам работать с экспортированными функциями, которые вы определили с помощью своего контроллера:

~/node_project/routes/sharks.js

const express = require('express');
const router = express.Router();
const shark = require('../controllers/sharks');

Теперь вы можете создавать маршруты, используя функцииindex,create иlist, которые вы определили в вашем файле контроллераsharks. Каждый маршрут будет связан с соответствующим методом HTTP: GET в случае рендеринга целевой страницы с информацией об акулах и возврата пользователю списка акул и POST в случае создания новой записи об акулах:

~/node_project/routes/sharks.js

...

router.get('/', function(req, res){
    shark.index(req,res);
});

router.post('/addshark', function(req, res) {
    shark.create(req,res);
});

router.get('/getshark', function(req, res) {
    shark.list(req,res);
});

Каждый маршрут использует связанную функцию вcontrollers/sharks.js, поскольку мы сделали этот модуль доступным, импортировав его в начало этого файла.

Наконец, закройте файл, прикрепив эти маршруты к объектуrouter и экспортировав их:

~/node_project/routes/index.js

...

module.exports = router;

Готовый файл будет выглядеть так:

~/node_project/routes/sharks.js

const express = require('express');
const router = express.Router();
const shark = require('../controllers/sharks');

router.get('/', function(req, res){
    shark.index(req,res);
});

router.post('/addshark', function(req, res) {
    shark.create(req,res);
});

router.get('/getshark', function(req, res) {
    shark.list(req,res);
});

module.exports = router;

Сохраните и закройте файл, когда вы закончите редактирование.

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

nano app.js

Ниже вашей константыdb добавьте следующий импорт для ваших маршрутов:

~/node_project/app.js

...
const db = require('./db');
const sharks = require('./routes/sharks');

Затемreplace функцияapp.use, которая в настоящее время монтирует ваш объектrouter, со следующей строкой, которая будет монтировать модуль маршрутизатораsharks:

~/node_project/app.js

...
app.use(express.static(path));
app.use('/sharks', sharks);

app.listen(port, function () {
        console.log("Example app listening on port 8080!")
})

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

Окончательная версия вашего файлаapp.js будет выглядеть так:

~/node_project/app.js

const express = require('express');
const app = express();
const router = express.Router();
const db = require('./db');
const sharks = require('./routes/sharks');

const path = __dirname + '/views/';
const port = 8080;

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
app.use('/sharks', sharks);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

Сохраните и закройте файл, когда вы закончите редактирование.

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

tree -I node_modules

Структура вашего проекта теперь будет выглядеть так:

Output├── Dockerfile
├── README.md
├── app.js
├── controllers
│   └── sharks.js
├── db.js
├── models
│   └── sharks.js
├── package-lock.json
├── package.json
├── routes
│   ├── index.js
│   └── sharks.js
└── views
    ├── css
    │   └── styles.css
    ├── getshark.html
    ├── index.html
    └── sharks.html

Создав и установив все компоненты приложения, вы готовы добавить тестовую акулу в свою базу данных!

Если вы выполнили первоначальные инструкции по настройке сервера в предварительных условиях, вам нужно будет изменить брандмауэр, поскольку в настоящее время он допускает только трафик SSH. Чтобы разрешить трафик на порт8080, выполните:

sudo ufw allow 8080

Запустите приложение:

node app.js

Затем перейдите в браузере кhttp://your_server_ip:8080. Вы увидите следующую целевую страницу:

Application Landing Page

Щелкните по кнопкеGet Shark Info. Вы увидите следующую информационную страницу с добавленной формой ввода акулы:

Shark Info Form

В форму добавьте акулу по вашему выбору. В целях демонстрации мы добавимMegalodon Shark в полеShark Name иAncient в полеShark Character:

Filled Shark Form

Щелкните по кнопкеSubmit. Вы увидите страницу с этой информацией об акулах, отображенной для вас:

Shark Output

Вы также увидите вывод в своей консоли, указывающий, что акула была добавлена ​​в вашу коллекцию:

OutputExample app listening on port 8080!
{ name: 'Megalodon Shark', character: 'Ancient' }

Если вы хотите создать новую запись об акуле, вернитесь на страницуSharks и повторите процесс добавления акулы.

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

Заключение

В этом руководстве вы создали приложение Node, интегрировав базу данных MongoDB и переписав логику приложения, используя архитектурный шаблон MVC. Это приложение может стать хорошей отправной точкой для полноценного приложенияCRUD.

Дополнительные ресурсы по шаблону MVC в других контекстах см. В нашихDjango Development series илиHow To Build a Modern Web Application to Manage Customer Information with Django and React on Ubuntu 18.04.

Для получения дополнительной информации о работе с MongoDB см. Нашу библиотекуtutorials on MongoDB.

Related