Мы видим, что все больше и больше компаний используют 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