Сегодня, в период стремительного развития веб-технологий, опытному фронтэнд-разработчику нужно всегда оставаться в тренде, каждый день углубляя свои познания. А что делать, если Вы только начинаете свой путь в мире веб? Вы уже переболели вёрсткой и на этом не хотите останавливаться. Вас тянет в загадочный мир JavaScript! Если это про Вас, надеюсь данная статья придётся к стати.  Имея за плечами полуторагодовой опыт работы в качестве фронтэнд-разработчика, я, утомившись монотонной вёрсткой очередного рядового проекта, задался целью углубить познания в сфере веб-программирования. У меня возникло желание создать своё первое single page application. Выбор стека технологий был очевиден, так как я всегда был не равнодушен к Node.js, методология MEAN стала тем, что доктор прописал.  Сегодня в интернете существует бесчисленное количество разных туториалов, в которых создают множество приложений helloworld, todo, management agency и т.д. Но просто бездумно следовать шагам туториала — не мой выбор. Я же решил создать некое подобие мессенджера: приложение с возможностью регистрации новых пользователей, созданием диалогов между ними, общения с chat-ботом для тестовых пользователей. И так, тщательно продумав план действий, я приступил к работе. Далее мой рассказ опишет основные моменты создания данного приложения, а для большей наглядности демо я оставлю тут (ссылка на github). *Также хочу отметить, что цель данной статьи, быть может, помочь обучающимся не наступить на грабли, на которые в своё время наступил я, и дать возможность более опытным разработчикам просмотреть код и высказать своё мнение в комментариях. Составим план действий: Подготовка рабочего места — это неотъемлемый процесс любой разработки, а качественное выполнение данной задачи — залог успеха в дальнейшем. Первым делом, нужно установить Express и настроить единую систему конфигурирования нашего проекта. Если с первым и так всё понятно, то на втором я остановлюсь по подробнее.  И так, воспользуемся замечательным модулем nconf. Давайте создадим папку с названием config, а в её индексный файл запишем: Далее в этой папке создадим файл с названием config.json и внесём в него первую настройку — порт, который слушает наше приложение: Чтоб внедрить данную настройку в приложение, нужно всего ничего, написать одну/две строки кода: Но стоит отметить, это будет работать в случае, если порт будет задан таким образом: Следующая наша задача — настроить единую систему логгирования в нашем приложении. Как писал автор статьи "О логгировании в Node.js": Для этой задачи воспользуемся модулем winston: Конечно, настройка может быть и более гибкой, но на данном этапе нам этого будет достаточно. Чтоб воспользоваться нашим новоиспечённым логгером, нужно всего-ничего подключить данный модуль в ваш рабочий файл и вызвать его в нужном месте: Следующей нашей задачей станет настройка правильной обработки ошибок при обычных и ajax запросах. Для этого мы внесём некие изменения в код, который заранее был сгенерирован Express (в примере указан только development error handler): Мы практически закончили с подготовительными работами, осталась одна маленькая, но отнюдь не маловажная деталь: настроить работу с базой данных. Первым делом настроим подключение к MongoDB с помощью модуля mongoose: В mongoose.connect мы передаём два аргумента: uri и options, которые я заранее прописал в конфиге (подробнее о них можно прочесть в документации к модулю). Процесс создания моделей пользователей и диалогов я описывать не буду, так как схожий процесс отлично описал автор веб-ресурса learn.javascript.ru в своём скринкасте по Node.js в видеоуроке "Создаём модель для пользователя / Основы Mongoose", лишь упомяну, что каждый пользователь будет иметь такие свойства, как username, hashedPassword, salt, dialogs и created. Свойство dialogs, в свою очередь, будет возвращать объект: ключ — id собеседника, значение — id диалога.  Если кому-то всё-таки интересно взглянуть на код данных моделей:  Осталось всего-ничего — прикрутить сессии к костяку нашего приложения. Для этого создадим файл session.js и подключим в него такие модули, как express-session, connect-mongo, и созданный нами модуль из файла mongoose.js: Выносить данную настройку в отдельный файл важно, но не обязательно. Это предоставит возможность в дальнейшем без особого труда помирить сессии и веб-соккеты между собой. Теперь подключим данный модуль в app.js: При чём, app.use(session) обязательно нужно указать после app.use(cookieParser()), чтобы cookie уже успели быть прочитанными. Всё! Теперь мы имеем возможность сохранять сессии в нашу базу данных. И на этом подготовительные работы — окончены. Пора приступать к самому интересному! Создание системы авторизации будет делиться на два основных этапа: фронтэнд и бэкэнд. Так как, затеивая данное приложение, я собирался всё время учить что-то новое, а с Angular1.x я уже имел опыт работы, фронтэнд часть решил организовывать на Angular2. Тот факт, что, когда я создавал приложение, уже была выпущена четвёртая (а сейчас пятая) предрелизная версия данного фреймворка, вселил во мне уверенность, что оф-релиз уже не за горами. И так, собравшись с мыслями, я сел за написание авторизации. Для ребят, которые ещё не сталкивались с разработкой на Angular2, прошу не удивляться, если в коде ниже вы встретите не известный вам ранее синтаксис javascript. Всё дело в том, что весь Angular2 построен на typescript. И нет, это вовсе не означает, что работать с данным фреймворком используя обычный javascript нельзя! Вот к примеру отличная статья, в ходе которой автор рассматривает разработку на Angular2 с использованием ES6.  Но typescript — это javascript, который масштабируется. Являясь компилируемым надмножеством javascript, этот язык добавляет в него все фичи из ES6 & ES7, настоящее ООП с блэк-джеком и классами, строгую типизацию и ещё много крутейших штук. И пугаться здесь нечего: ведь всё, что валидно в javascript, будет работать и в typescript!  Первым делом создадим файл user-authenticate.service.ts, в нём будет находиться сервис авторизации: Далее внутри нашего класса создадим несколько методов: login, logout, singup, isLoggedIn. Все эти методы однотипны: каждый выполняет свою задачу по отправке запроса типа post на соответствующий адрес. Не сложно догадаться, какую логическую нагрузку несёт каждый из них. Рассмотрим код метода login: Чтоб вызвать данный метод из компонента Angular2, нужно внедрить данный сервис в соответствующий компонент: Стоит отметить: для получения доступа к одному и тому же экземпляру сервиса из разных компонентов, его нужно внедрять в общий родительский компонент. И на этом мы оканчиваем фронтэнд этап создания системы авторизации. Приступая к бэкэнд разработке, рекомендую вам ознакомиться с интересным модулем async (документация к модулю). Он станет мощным инструментом в вашем арсенале для работы с асинхронными функциями javascript. Давайте создадим файл authentication.js в уже существующей директории routes. Теперь укажем данный middleware в app.js: Далее просто создадим обработчик для запроса пост на адрес authentication/login. Чтоб не писать длинную простыню из различных if...else воспользуемся методом waterfall из вышеупомянутого модуля async. Данный метод позволяет выполнять коллекцию асинхронных задач по-порядку, передавая результаты предидущей задачи в аргументы следующей, а на выходе выполнить какой-нибудь полезный колбек. Давайте сейчас и напишем данный колбек: Для собственного удобства я заранее подготовил конструктор Response: Нам осталось только записать функции в нужном нам порядке в массив, переданный первым аргументом в async.waterfall. Давайте создадим эти самые функции: Вкратце опишу, что здесь происходит: мы ищем пользователя в базе данных, если такового здесь нет, вызываем колбек с ошибкой 'username', в случае удачного поиска передаём пользователя в колбек; вызываем метод checkPassword, опять же, если пароль верный, передаём пользователя в колбек, в противном случае вызываем колбек с ошибкой 'password'; далее сохраняем сессию в базу данных и вызываем завершающий колбек. Вот и всё! Теперь пользователи нашего приложения имеют возможность авторизации. Мы подошли к написанию функции, несущей в себе основную смысловую нагрузку нашего приложения. В данном разделе мы организуем алгоритм подключения к диалогам (chat-rooms) и функцию отправки/получения сообщений. Для этого мы воспользуемся библиотекой Socket.io, которая позволяет очень просто реализовать обмен данными между браузером и сервером в реальном времени.  Создадим файл sockets.js и подключим данный модуль в bin/www (входной файл Express): Так как Socket.io работает с протоколом web-sockets, нам необходимо придумать способ передать ей сессию текущего пользователя. Для этого в уже созданный нами файл sockets.js запишем: Socket.io построена таким образом, что браузер и сервер всё время обмениваются различными событиями: браузер генерирует события, на которые реагирует сервер, и на оборот, сервер генерирует события, на которые реагирует браузер. Давайте напишем обработчики событий на стороне клиента: В коде выше мы создали три обработчика событий: connect, joined to dialog, message. Каждый из них вызывает соответствующую ему функцию. Так, событие connect вызывает функцию joinDialog(), которая в свою очередь генерирует серверное событие join dialog, с которым передаёт id собеседника. Далее всё просто: событие joined to dialog получает массив с сообщениями пользователей, событие message добавляет новые сообщения в выше упомянутый массив. Чтоб в дальнейшем уже не возвращаться к фронтэнду, давайте создадим функцию, которая будет отправлять сообщения пользователя: Данная функция генерирует событие message, с которым и передаёт текст отправленного сообщения. Дело осталось за малым — написать обработчики событий на стороне сервера!  В переменные currentDialog и currentOpponent мы будем сохранять идентификаторы текущего диалога и собеседника.  Приступим к написанию алгоритма подключения к диалогу. Для этого воспользуемся библиотекой async, а именно вышеупомянутым методом watterfall. Очерёдность наших действий:  На этом алгорим подключения к диалогу закончен, осталось всего ничего написать обработчик для события message: В данном примере кода мы сохранили в переменные текст сообщения и идентификатор пользователя, затем с помощью заранее созданного конструктора Message создали объект нового сообщения, добавили его в массив и, сохранив обновлённый диалог в базу данных, сгенерировали событие message в данной комнате, с которым и передали сообщение.  Вот и всё наше приложение готово! Хех, вы всё-таки дочитали?! Не смотря на объёмы статьи, я не успел обозреть все детали создания приложения, так как мои возможности ограничены данным форматом. Но выполняя данную работу я не только значительно углубил свои познания в сфере веб-программирования, но и получил море удовольствия от выполненной работы. Ребят, никогда не бойтесь браться за что-то новое, сложное, ведь, если тщательно подойти к делу, постепенно разбираясь с всплывающими вопросами, даже с нулевым опытом на старте, можно создать что-то действительно хорошее! Веб-разработчик, frontend developer