Написание масштабируемой архитектуры для Nodejs

1656487819 napisanie masshtabiruemoj arhitektury dlya nodejs

автор Зафар Салим

N13a8PnzzW4pClaPjtY05UUp5tqE4NKANVHf

Написать логику бэкенда для любого проекта сегодня достаточно легко благодаря полному стеку JavaScript. Особенно это касается введения десятков фреймворков для реализации как на стороне клиента, так и на стороне сервера.

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

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

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

В этом блоге будет четыре части.

  1. Базовая настройка архитектуры
  2. Регистрация
  3. Войти
  4. Приборная панель

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

Базовая настройка архитектуры

Сначала создайте новый каталог в вашей файловой системе и вызовите его auth (или что угодно).

mkdir auth

Теперь cd в этот каталог и создайте файл package.json. Добавьте в него строчки ниже.

{    "name": "auth",    "version": "0.0.0",    "private": true,    "main": "index.js",    "scripts": {      "start": "node index.js"    },    "dependencies": {      "bcrypt": "latest",      "body-parser": "^1.18.2",      "cookie-parser": "~1.4.3",      "express": "~4.15.5",      "jsonwebtoken": "^8.1.1",      "mongoose": "^5.0.3",      "lodash": "^4.17.11",      "morgan": "^1.9.0",      "passport": "^0.4.0",      "passport-jwt": "^3.0.1",      "serve-favicon": "~2.4.5"    }  }

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

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

npm install

После того, как он установит все вышеперечисленные зависимости, создайте файл index.js файл в вашей корневой папке, как показано ниже:

touch index.js

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

'use strict';
const server = require('./server')();const config = require('./configs');const db = require('./configs/db');
server.create(config, db);server.start();

Как видите, для этого файла нужны три файла:

  1. сервер
  2. конфиг
  3. дБ

Дальше мы их создадим.

Затем код выше вызывает create метод на серверном модуле Наконец, это вызывает start метод, запускающий сервер.

1. Создайте server папку

mkdir server

Сделав, cd в эту папку и создайте другую index.js файл.

touch index.js

Теперь добавьте код ниже в этот файл:

'use strict';
const express = require('express');const bodyParser = require('body-parser');const logger = require('morgan');const mongoose = require('mongoose');const passport = require('passport');const cookieParser = require('cookie-parser');
module.exports = function() {  let server = express(),      create,      start;
   create = function(config, db) {      let routes = require('./routes');
       // Server settings       server.set('env', config.env);       server.set('port', config.port);       server.set('hostname', config.hostname);
       // Returns middleware that parses json       server.use(bodyParser.json());       server.use(bodyParser.urlencoded({ extended: false }));       server.use(cookieParser());       server.use(logger('dev'));       server.use(passport.initialize());       mongoose.connect(db.database);       require('../configs/passport')(passport);
       // Set up routes       routes.init(server);   };
   start = function() {       let hostname = server.get('hostname'),       port = server.get('port');
       server.listen(port, function () {          console.log('Express server listening on -  + hostname + ':' + port);        });    };
    return {       create: create,       start: start    };};

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

Затем мы экспортируем анонимную функцию из этого модуля с помощью module.exports. Внутри этой функции создайте три переменных: server, create и start.

The server переменная предназначена для сервера Express.js. Итак, звоните express() функцию и назначьте ее server. Мы назначим анонимные функции create и start переменные.

Теперь пора написать а create функция с двумя параметрами: config и db.

Затем установите несколько параметров сервера с помощью функции server.use(), то есть env, порт и имя хоста. Затем используйте cookieParser, bodyParser, logger and passport промежуточное программное обеспечение Затем подключите к mongoose базу данных и, наконец, требуйте файл конфигурации паспорта и вызовите его с нужным паспортом.

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

Теперь пришло время конечных точек API, то есть маршрутов. Просто позвоните init функция на маршрутах и ​​перевалах server в это.

Далее напишите start функция. Набор hostname и port и запустите сервер с listen команду внутри этой функции.

Затем верните оба create и start функции, чтобы сделать их доступными для использования другими модулями.

2. Создайте папку config

На корневом уровне создайте a configs папка:

mkdir configs

cd в эту папку и создайте файл index.js:

touch index.js

Добавьте следующий код в файл index.js:

'use strict';
const _ = require('lodash');const env = process.env.NODE_ENV || 'local';const envConfig = require('./' + env);
let defaultConfig = {  env: env};
module.exports = _.merge(defaultConfig, envConfig);

Теперь создайте файл local.js:

touch local.js

Откройте его и добавьте код ниже:

'use strict';
let localConfig = {  hostname: 'localhost',  port: 3000};
module.exports = localConfig;

Этот тоже прост. Мы создаем а localConfig объект и добавив несколько свойств, например hostname и port. Затем экспортируйте его, чтобы использовать его, как мы делаем в ./index.js файл.

3. Теперь создайте базу данных

touch db.js

Откройте db.js в своем любимом редакторе и вставьте в него следующий код.

module.exports = {   'secret': 'putsomethingsecretehere',  'database': 'mongodb://127.0.0.1:27017/formediumblog'};

Мы экспортируем объект JavaScript со свойствами secret и database. Они используются для подключения к базе данных MongoDB посредством промежуточного программного обеспечения под названием mongoose.

Создание программы

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

cd в server папку и создайте следующие папки:

mkdir controllers models routes services

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

touch index.js

И вставьте следующий код в этот файл:

'use strict';
const apiRoute = require('./apis');
function init(server) {  server.get('*', function (req, res, next) {    console.log('Request was made to: ' + req.originalUrl);    return next();  });
  server.use('/api', apiRoute);}
module.exports = {  init: init};

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

Во-вторых, создайте an init функция. Мы вызываем эту функцию с server/index.js файл внутри create функция внизу и прохождение server как параметр. Он просто получает все маршруты и возвращает следующую функцию обратного вызова.

Затем используйте apiRoute которые мы требуем выше. Наконец, экспортируйте функцию init, чтобы сделать эту функцию доступной в другой части проекта.

Теперь создайте файл apis папку. В этой папке создайте файл index.js .

mkdir apistouch index.js

Вставьте код ниже в файл index.js файл.

'use strict';
const express = require('express');const v1ApiController = require('./v1');
let router = express.Router();
router.use('/v1', v1ApiController);
module.exports = router;

Этот файл требует express и папку версии API, то есть v1. Затем создайте маршрутизатор и сделайте /v1 конечная точка использования router.use() метод. Наконец-то экспортируйте маршрутизатор.

Пора творить apis/v1.js файл. Вставьте код ниже внутрь v1.js файл:

'use strict';
const registerController = require('../../controllers/apis/register');const express = require('express');
let router = express.Router();
router.use('/register', registerController);
module.exports = router;

Нам необходимо зарегистрировать контроллер и express.js и сделать маршрутизатор. Тогда нам нужно разоблачить register Конечные точки API используются на стороне клиента. Наконец, мы должны экспортировать маршрутизатор из этого модуля.

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

Теперь мы закончили с папкой routes, и пришло время папки controllers. Идите вперед и компакт-диск в эту папку и создайте папку apis .

mkdir apis

Теперь у нас есть папка apis внутри controllersмы собираемся создать следующие три контроллера и их соответствующие services.

  1. Базовая настройка архитектуры
  2. Регистрация
  3. Войти
  4. Приборная панель

Первое – это registerController. Создайте следующий файл.

touch register.js

Откройте этот файл в своем любимом редакторе и вставьте в него следующий код:

'use strict';
const express = require('express');const registerService = require('../../services/authentication/register');
let router = express.Router();
router.post('/', registerService.registerUser);
module.exports = router;

Во-первых, это требует express.js и register сервис (о котором мы напишем позже). Затем создайте маршрутизатор с помощью express.Router() методом и отправьте запрос на сообщение в '/' путь. Затем вызовите метод registerUser в registerService (который мы собираемся написать позже). Наконец, экспортируйте маршрутизатор из этого модуля.

Теперь нам нужен этот контроллер внутри routes/apis/v1.js файл, который мы уже сделали.

Теперь регистрация контроллера завершена. Пора добраться до services папку. CD в ​​эту папку и создайте файл authentication папку. Прежде всего, компакт-диск authentication и создать а register.js файл.

touch register.js

Затем откройте register.js файл и вставьте в него следующий код:

'use strict';
const express = require('express');const User = require('../../models/User');
const httpMessages = {  onValidationError: {    success: false,    message: 'Please enter email and password.'  },  onUserSaveError: {    success: false,    message: 'That email address already exists.'  },  onUserSaveSuccess: {    success: true,    message: 'Successfully created new user.'  }}
// Register new usersfunction registerUser(request, response) {  let { email, password } = request.body;
  if (!email || !password) {    response.json(httpMessages.onValidationError);  } else {    let newUser = new User({      email: email,      password: password    });
    // Attempt to save the user    newUser.save(error => {      if (error) {        return response.json(httpMessages.onUserSaveError);      }      response.json(httpMessages.onUserSaveSuccess);    });  }}
module.exports = {  registerUser: registerUser};

В register услуги, сначала мы нуждаемся expressjs и User модель. Затем мы создаем объект JavaScript, то есть httpMessages это в основном список всех сообщений, которые мы собираемся посылать клиентам через API, когда клиент посылает запрос.

Затем функция registerUser фактически выполняющий процесс регистрации. Перед сохранением пользователя проверяется, указал ли пользователь свой адрес и пароль. Если они сделали, то создайте нового пользователя с помощью new ключевое слово с предоставленными по электронной почте и паролем.

Тогда просто позвоните save функция включена newUser чтобы сохранить этого пользователя в базе данных и отправить ответный ответ с помощью response.json.

Наконец, экспортируйте эту функцию с помощью module.exports использовать его в остальном проекте. Мы используем это внутри controllers/register.js файл.

Прежде чем тестировать это, чтобы проверить, работает ли это, сначала нам нужно создать файл a User модель. Создайте файл User.js внутри models папку.

touch User.js

И вставьте этот код в файл выше:

const mongoose = require('mongoose');const bcrypt = require('bcrypt');
const UserSchema = new mongoose.Schema({  email: {    type: String,    lowercase: true,    unique: true,    required: true  },  password: {    type: String,    required: true  },  role: {    type: String,    enum: ['Client', 'Manager', 'Admin'],    default: 'Client'  }});
UserSchema.pre('save', function(next) {  let user = this;
   if (this.isModified('password') || this.isNew) {      bcrypt.genSalt(10, (err, salt) => {        if (err) {          console.log(err);          return next(err);        }
        bcrypt.hash(user.password, salt, (err, hash) => {          if (err) {            console.log(err);            return next(err);          }
          user.password = hash;          next();        });      });  } else {    return next();  }});
// Create method to compare password input to password saved in databaseUserSchema.methods.comparePassword = function(pw, cb) {  bcrypt.compare(pw, this.password, function(err, isMatch) {    if (err) {      return cb(err);    }
    cb(null, isMatch);  });};
module.exports = mongoose.model('User', UserSchema);

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

Создайте UserSchema с email, password and role свойства. Затем перед сохранением пользователя выполните некоторые проверки перед хешированием пароля.

Последняя функция – сравнить пароли. Он сравнивает пароль пользователя с хэшированным паролем в базе данных.

Теперь, чтобы проверить этот код, откройте postman (если вы не установили postman, установите его отсюда). Откройте почтальон и введите URL-адрес ниже:

http://localhost:3000/api/v1/register

Выберите POST в качестве запроса, выберите вкладку тела и form-urlencoded и введите адрес электронной почты и пароль. Нажмите кнопку отправки, и вы увидите сообщение об успехе ниже.

v24ai9wIGdPv0m2RrvssyzNtBa1c3MK1yA3k

Теперь регистровая часть выполнена.

  1. Базовая настройка архитектуры
  2. Регистрация
  3. Войти
  4. Приборная панель

Пора сосредоточиться на входе. Создать login.js файл внутри controllers папку.

touch login.js

Теперь откройте его и вставьте следующий код:

'use strict';
const express = require('express');const loginService = require('../../services/authentication/login');
let router = express.Router();
router.post('/', loginService.loginUser);
module.exports = router;

Снова все просто и так же, как модуль реестра: после импорта express.js и loginService мы создаем маршрутизатор и делаем запрос на сообщение к корневому пути '/' с loginUser включена функция обратного вызова loginService . Наконец-то экспортируйте маршрутизатор.

Пора требовать loginController в routes/apis/v1.js файл. Ваш v1.js файл должен выглядеть, как показано ниже.

'use strict';
const registerController = require('../../controllers/apis/register');const loginController = require('../../controllers/apis/login');
const express = require('express');
let router = express.Router();
router.use('/register', registerController);router.use('/login', loginController);
module.exports = router;

Теперь для службы входа создайте a login.js файл внутри services/authentication/:

touch login.js

И вставьте код ниже в этот файл:

'use strict';
const express = require('express');const apiRoutes = express.Router();
const jwt = require('jsonwebtoken');const passport = require('passport');const db = require('../../../configs/db');
const User = require('../../models/User');
const httpResponse = {  onUserNotFound: {    success: false,    message: 'User not found.'  },  onAuthenticationFail: {    success: false,    message: 'Passwords did not match.'  }}
function loginUser(request, response) {   let { email, password } = request.body;
User.findOne({    email: email  }, function(error, user) {    if (error) throw error;
    if (!user) {      return response.send(httpResponse.onUserNotFound);    }
    // Check if password matches    user.comparePassword(password, function(error, isMatch) {      if (isMatch && !error) {        var token = jwt.sign(user.toJSON(), db.secret, {           expiresIn: 10080        });
        return response.json({           success: true, token: 'JWT ' + token        });      }
      response.send(httpResponse.onAuthenticationFail);    });  });};
module.exports = {  loginUser: loginUser};

Сначала нужны некоторые необходимые модули, такие как: express.js, jsonwebtoken, passport, db and User model. Создайте объект JavaScript, который содержит список сообщений, которые необходимо отправить клиенту, когда в эту службу сделан http-запрос.

Создайте функцию loginUser, а внутри нее создайте пару переменных, например электронную почту и пароль, и назначьте электронную почту и пароль, отправленные пользователем, этим переменным, которые находятся в request.body.

Затем используйте findOne() метод на User модель, чтобы найти приложение на основе электронной почты, отправленной пользователем от клиента. Функция обратного вызова findOne() принимает 2 параметра, error and user. Сначала проверьте, указано ли выше findOne() метод выдает любую ошибку – если это так, то выдает ошибку.

Затем выполните проверку: если пользователь не найден, отправьте ответный ответ с сообщением из списка сообщений, который мы объявили выше в этом модуле.

Затем сравните пароль, отправленный пользователем, с паролем в базе данных с помощью compare функцию, которую мы написали в User модель раньше в этом блоге.

Если пароль совпадает и он не возвращает ошибку, мы создаем маркер с помощью jsonwebtoken модуль и поверните этот маркер с помощью json.response() к клиенту. В противном случае мы присылаем authenticationFail сообщения.

Наконец-то экспортируйте loginUser функция с exports.module чтобы мы могли использовать его в наших контроллерах и где угодно.

Пора проверить функциональность входа. Вернитесь к почтальону и на этот раз замените register с login как конечная точка API в URL-адресе. Введите адрес электронной почты и пароль и нажмите кнопку Отправить. Вы должны иметь возможность получить токены. Скопируйте это в буфер обмена, потому что вы будете использовать его позже для доступа к информационной панели.

NgY6nezWpJkKbuOU7555pCd4abpZBNzzPvBd
  1. Базовая настройка архитектуры
  2. Регистрация
  3. Войти
  4. Приборная панель

Теперь настало время для dashboard.js файл. Создайте dashboard.js файл внутриcontrollers папку.

touch dashboard.js

Откройте его и вставьте код ниже:

'use strict';
const passport = require('passport');const express = require('express');const dashboardService = require('../../services/dashboard/dashboard');
let router = express.Router();
router.get('/', passport.authenticate('jwt', { session: false }), dashboardService.getDashboard);
module.exports = router;

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

По этой причине мы также импортируем паспорт, а для запроса на получение мы используем passport.authenticate() функция до getDashboard обслуживание.

Снова нужно требовать dashboardController в routes/apis/v1.js файл. Ваш v1.js файл должен выглядеть так:

'use strict';
const registerController = require('../../controllers/apis/register');const loginController = require('../../controllers/apis/login');const dashboardController = require('../../controllers/apis/dashboard');
const express = require('express');
let router = express.Router();
router.use('/register', registerController);router.use('/login', loginController);router.use('/dashboard', dashboardController);
module.exports = router;

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

'use strict';
function getDashboard(request, response) {  response.json('This is from dashboard');}
module.exports = {  getDashboard: getDashboard}

Никаких фантастических вещей не происходит. В целях демонстрации я просто отвечаю текстовым сообщениям This is from dashboard. Затем экспортируйте этот метод для использования в соответствующем контроллере, который мы уже сделали.

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

cQtptcZskXGs8nrmEPsRlDuRxsJjxv5a9gE1

Вы должны увидеть сообщение This is from dashboard как ответ.

Как видите, когда мы создаем новый сервис, нам нужен ему один контроллер, и мы можем продолжать добавлять новые сервисы в архитектуру. Если вы хотите изменить версию API, а также сохранить текущую, просто добавьте новую v2.js файл и перенаправить все запросы на эту конечную точку. Это один обычный пример.

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

ОБНОВЛЕНИЕ: Если вы хотите реализовать его клиентскую сторону, нажмите здесь, где я использовал react.js для проверки подлинности на этом сервере.

Добавить комментарий

Ваш адрес email не будет опубликован.