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

Сегодня я покажу вам, как легко создать небольшое веб-приложение с помощью Node. JS, улучшенный с помощью TypeScript, PostgreSQL в качестве нашей базы данных и способы ее докеризации.

Эта статья начинается с базовой настройки нашего приложения Node.JS, сервера Express и конфигурации PostgreSQL. Часть Docker описана в конце истории, поэтому, если вы хотите увидеть настройку Docker только для этого приложения, прокрутите вниз.

Создание приложения Node.JS

Я предполагаю, что вы уже устанавливали Node.JS раньше. Создание каждого приложения Node.JS начинается с простой команды npm init. Если вы добавите -y, оно заполнит весь ввод за вас и создаст файл package.json, необходимый для управления зависимостями нашего приложения, необходимыми для его запуска.

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

Затем мы установим TypeScript и tslint в наш проект, набрав следующее:

npm install typescript tslint --save-dev

Эта команда установит TypeScript в наши зависимости разработчика. После установки TypeScript мы отредактируем наш файл package.json и добавим tsc команду для доступа к командам TypeScript. Мы будем использовать эту команду для запуска и сборки нашего приложения.

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

tsc --init

Поскольку мы будем использовать Express, важно установить пакет, который поможет TypeScript идентифицировать экспресс-типы, набрав:

npm i @types/express @types/node --save-dev

Таким образом, TypeScript сможет распознавать классы Express и глобальные типы узлов. Например, после установки пакета типов вы сможете напрямую импортировать типы запросов и ответов из Express.

Если мы инициализируем tsconfig.json первой командой, мы получим такой файл:

Это наш файл tsconfig.json с множеством параметров компилятора, которые вы можете настроить.

Мы заменим его следующим:

{
 "compilerOptions": {
 "module": "commonjs",
 "esModuleInterop": true,
 "target": "es6",
 "moduleResolution": "node",
 "sourceMap": true,
 "outDir": "dist/src"
},
 "lib": ["es2015"]
}

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

Создание и запуск нашего сервера с использованием TypeScript

Всегда рекомендуется разделять сценарии для определения сервера и запускать приложение с использованием этой конфигурации сервера.

На данный момент структура нашего проекта выглядит так:

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

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

Мы объясним конфигурацию по ходу дела. Во-первых, мы инициализируем наше экспресс-приложение, переходим к настройкам конкретного сервера, таким как настройка body-parser для обработки наших входящих данных. В конце концов, есть общедоступный метод, который мы будем использовать для запуска нашего сервера в нашем файле app.ts. Мы также настроили нашу маршрутизацию, чтобы использовать отдельную конфигурацию маршрутизатора для получения всех задач.

Здесь мы вызываем наш метод «start» и регистрируем в случае успеха или неудачи.

Конфигурация Postgres

Пул - это процесс создания соединений и их кеширования для повторного использования. Нет потери ресурсов, как если бы вы каждый раз создавали новое соединение.

Ниже приводится объяснение упомянутых свойств конфигурации:

Я использую pgAdmin4 для доступа к кластеру базы данных и управления своими базами данных.

TodosController

Мы создадим TodosController и маршрут для получения всех задач из базы данных.

Контроллер будет выглядеть так:

  • Импорт пула из нашего класса конфигурации базы данных
  • Инициализация нового соединения и создание экземпляра клиента pg
  • Отправка необработанного запроса в метод query нашего клиента - асинхронный
  • Разрыв соединения - ЭТО ВАЖНО!
  • Возврат полученных данных

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

Маршрутизатор Todos

Мы настроим наш маршрутизатор в отдельном файле, хранящемся в src / routers, и дадим ему маршрут к методу GET, определенному выше в нашем TodosController.

Теперь все, что нам нужно сделать, это зарегистрировать этот маршрутизатор в нашем server.ts, где мы настроили наш сервер.

Мы импортируем наш маршрутизатор todos и говорим нашему серверу Express, что каждый раз, когда кто-то нажимает «/ todos» в URL-адресе, передайте экземпляр todosRouter для обработки всех запросов с этим маршрутом.

Структура проекта

Пока что у нас есть следующая структура проекта:

Создание нашего приложения

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

Сначала мы запустим следующую команду с нашего терминала

npm run build

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

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

"main": "dist/src/app.js",

Наш раздел скриптов в package.json должен быть таким:

"scripts": {
"build": "tsc",
"start": "tsc && node dist/app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},

Теперь, если вы проверите свое дерево каталогов, вы увидите новый каталог dist, как мы указали в tsconfig.json.

Тестируем наше приложение

Чтобы запустить ваше приложение, введите и проверьте свой терминал:

npm start

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

Теперь, если мы зайдем в браузер и посетим:

http://localhost:4000/todos

мы должны получить результат из нашей базы данных

Такой хороший совет!

Докеризация нашего приложения

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

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

Контейнеры запускают экземпляры наших изображений.

Подробнее о контейнерах можно прочитать здесь.

Докер сочиняет

Мы создадим файл с именем docker-compose.yml, в котором мы сможем настроить конфигурацию для всех сервисов, которые будет использовать наше приложение.

Нам нужна служба для нашего веб-приложения, работающего на Node.JS, и служба базы данных PostgreSQL.

Мы используем docker-compose для запуска нескольких контейнеров для нашего приложения.

Наш файл docker-compose будет выглядеть так:

Если вы посмотрите на наш контейнер Postgres в нашей конфигурации docker-compose, вы увидите, что мы используем образ Postgres 10.4 для создания нашего контейнера, предоставляем порт «5432» на нашем локальном компьютере и сопоставьте его с портом 5432 контейнера. Это означает, что если я хочу получить доступ к моему экземпляру Postgres, работающему внутри моего контейнера, я бы использовал порт localhost: 5432 вместе с определенным именем пользователя и паролем.

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

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

Было бы здорово инициализировать базу данных схемой, чтобы не создавать ее вручную.

- ./src/migrations/dbinit.sql:/docker-entrypoint-initdb.d/dbinit.sql

Этот фрагмент кода в нашем файле docker-compose запускает наш файл dbinit.sql из нашего проекта и использует его для выполнения любого SQL, который мы написали внутри него.

Dockerfile

Наш Dockerfile будет выглядеть так:

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

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

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

Контейнер может быть готов, а наша база данных - нет !!!

Что это за часть с этим URL-адресом? Похоже, мы также что-то загружаем и запускаем при создании нашего образа, что-то вроде процесса ожидания.

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

Наша окончательная структура проекта

Запуск наших сервисов приложений с помощью Docker

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

docker-compose up --build -d

-d указывает запустить контейнер в фоновом режиме, а — build создает образ перед запуском контейнеров. Это важно, потому что вы часто хотите иметь доступ к командной строке во время работы контейнера.

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

docker ps

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

Было бы неплохо посмотреть, что происходит внутри наших контейнеров, какие-то логи или что-то в этом роде.

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

docker logs {container}

Это результат нашего приложения Node - тот же результат, что и при выполнении npm start. Это результат запуска нашего приложения, которое теперь выполняется в контейнере.

PgAdmin

Мы также видим, что наше управление базой данных выполняется на порту 80. Если мы перейдем на «localhost: 8080», мы получим страницу входа в систему управления базой данных, где мы можем войти в нашу систему.

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

Вы видите, что у нас уже есть todo-db и таблица задач .

Тестирование нашего маршрута / todos

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

Я отправлю простой запрос CURL к нашему TodosController с конвейером форматирования JSON.

curl 'http://localhost:4000/todos' | json_pp

Вот и наши данные.

Заключение

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

Спасибо за чтение. Надеюсь, вы узнали что-то полезное!

Репозиторий GitHub: https://github.com/CyberZujo/todo-app