tl; dr: проверьте репозиторий кода на странице https://github.com/teamzerolabs/config-service-reference.

Ваш проект подключается к базам данных или стороннему Apis?

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

Есть много разных способов загрузить эти учетные данные в программу:

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

Уровень 2: загрузка из объекта process.env в том месте, где происходит соединение. Это лучше, чем жесткое кодирование, но со временем переменная среды становится немного сложной. выслеживать. Потому что вы не можете перейти к одному файлу, чтобы найти все переменные среды, на которые есть ссылки.

Уровень 3: загрузите все конфигурации среды из одного файла - это предусмотрено в этой статье и в примере кода! Это дает вам преимущество знать, где искать конфигурации, и позволяет программе преждевременно выйти из строя, если были предоставлены неверные значения.

Уровень 4. Превратите сценарий конфигурации в службу. Таким образом мы получаем возможность делать другие интересные вещи: проверять типы загруженных значений и загружать дополнительные конфигурации из S3 или базы данных перед другой инициализацией. код работает.

Прежде чем ты начнешь

  • Подготовьте среду выполнения Node.JS (Версия ›10)
  • Скачайте Postman, если у вас его нет. Кроме того, вы можете использовать браузер или curl, чтобы попасть в Api.
  • Проверьте https://github.com/teamzerolabs/config-service-reference в своем локальном пространстве.
  • Установите и запустите MySQL: я включил файл docker-compose в папку db-setup, вы можете развернуть его, перейдя туда и запустив docker-compose up -d.

Краткий пример - минимальная книжная служба, которая возвращает книги, хранящиеся в базе данных MySQL

В первой папке node-starthere у нас есть два файла:

  • main.js - здесь мы настраиваем express сервер для обслуживания запроса на localhost:3000/books
  • models / index.js - мы подключимся к MySQL с mysql2 и sequelize.
  • Запустите yarn start, чтобы начать.

Вы можете увидеть, как учетные данные базы данных в настоящее время хранятся в models/index.js:

Оборотная сторона жесткого кодирования учетных данных базы данных

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

Шаг №1 - Загрузите каждый из них из переменных среды

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

DB_NAME=configexample DB_HOST=localhost DB_USER=root DB_PASSWORD=dIKnUfyfUPURi9irSplTOqGO4OtE0 DB_PORT=3306 yarn start
....
// In the program
const sequelize = new Sequelize(
  process.env.DB_NAME,
  process.env.DB_USER,
  process.env.DB_PASSWORD,
  {
    dialect: "mysql",
    host: process.env.DB_HOST,
    port: parseInt(process.env.DB_PORT)
  }
);

Этот подход хорош, если у вас небольшое количество конфигураций, но, как мы все знаем, любые проекты, пережившие первый месяц использования, начнут интегрироваться с большим количеством сервисов. (В моем недавнем 4-месячном проекте 40 переменных! Представьте, что вы набираете их в приведенном выше заявлении о начале пряжи, это слишком много).

Шаг № 2 - Загрузите переменные среды во время выполнения для локальной разработки перед использованием.

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

const dotenv = require("dotenv");
let env = process.env.NODE_ENV;
if (env !== "production") {
  // Development will use .env.
  // Anything else will use .env.<NODE_ENV>
  if (env === "development") {
    env = "";
  }

  const path = `src/config/.env${env ? `.${env}` : ""}`;
  // Well, it's better to use winston logger, perhaps we can cover in another tutorial
  console.log(`Loading config from environment file ${path}`);
  dotenv.config({ path });
}

Поместите свой код в src, создайте папку config и создайте внутри нее файл .env:

DATABASE_URL=localhost
DATABASE_PORT=3306
DATABASE_USERNAME=root
DATABASE_PASSWORD=dIKnUfyfUPURi9irSplTOqGO4OtE0
DATABASE_NAME=configexample

И dotenv.config загрузит переменные из текстовых файлов в process.env, теперь вы можете пропустить ввод переменных в yarn start!

Шаг № 3 - Удобные методы для анализа значений и досрочного выхода, если они отсутствуют

Единственное, что опаснее неправильно настроенной программы, - это неправильно настроенная программа, работающая месяцами.

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

Если вы посмотрите на вторую папку node-with-config-service, вы увидите, что следующие служебные методы добавлены и используются для анализа переменных:

/**
 * Retrieves environment variable and throws if missing without default
 *
 * @param name name of environment variable
 * @param defaultVal
 */
function parseEnv(name, defaultVal) {
  let env = process.env[name];
  if (!env) {
    if (isNullOrUndefined(defaultVal)) {
      throw new Error(`Missing environment variable for ${name}`);
    }
    env = defaultVal;
  }

  return env;
}

/**
 * Retrieves environment variable as a number and throws if missing without default
 *
 * @param name name of environment variable
 * @param defaultVal
 */
function parseEnvNumber(name, defaultVal) {
  const number = parseInt(parseEnv(name, `${defaultVal}`));
  if (isNaN(number)) {
    throw new Error(`Bad environment variable for ${name}: Not a Number`);
  }
  return number;
}

/**
 * Retrieves environment variable as a boolean and throws if missing without default
 *
 * @param name name of environment variable
 * @param defaultVal
 */
function parseEnvBoolean(name, defaultVal) {
  return parseEnv(name, `${defaultVal}`).toLowerCase() === "true";
}

И перепишем раздел подключения к базе данных так:

// in src/config/index.js
const config = {
  app: {
    port: parseEnvNumber("APP_PORT", 3000)
  },
  mysql: {
    host: parseEnv("DATABASE_URL"),
    port: parseEnvNumber("DATABASE_PORT", 3306),
    username: parseEnv("DATABASE_USERNAME"),
    password: parseEnv("DATABASE_PASSWORD"),
    database: parseEnv("DATABASE_NAME")
  }
};
// in src/models/index.js
const config = require("../config");

const sequelize = new Sequelize(
  config.mysql.database,
  config.mysql.username,
  config.mysql.password,
  {
    dialect: "mysql",
    host: config.mysql.host,
    port: config.mysql.port
  }
);

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

У этого подхода есть еще два расширения: вы можете применять те же шаблоны в TypeScript и пойти дальше, настроив фактическую вспомогательную службу в NestJS. Оба включены в репозиторий git. Мы рассмотрим это в будущей статье о TypeScript + NestJs!

Используйте шаблон конфигурации для вашего демонстрационного проекта / прототипа / портфолио

Ваш коллега / DevOps / партнер по обзору кода / в будущем вы через 3 месяца поблагодарит вас за это, :)

Есть вопросы о том, где разместить конфигурации? Спрашивайте нас в любое время по адресу [email protected]