Бессерверная структура позволяет ссылаться на внешние файлы JSON, YML и JS, используя синтаксис ${file:(fileName):propertyName}. Однако вы не можете настроить эти внешние файлы конфигурации с помощью аргументов времени выполнения.

Читатель спросил меня:

«У меня есть этот шаблон, который многократно повторяется в моем serverless.yml, как мне повторно использовать шаблон, но переопределить только определенные поля?»

Это интересный вопрос, и вот несколько возможных решений.

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

Якоря YML

Самое простое решение - использовать якоря YML. Вы можете определить и применить привязку и переопределить определенные поля. Например:

Если шаблон большой, вы можете поместить его в отдельный файл. К сожалению, я не нашел способа заставить якоря работать с внешними файлами конфигурации в serverless.yml. Я не могу импортировать содержимое привязки из другого файла (как показано ниже). Пожалуйста, дайте мне знать в комментариях, если вы знаете, что я здесь сделал не так.

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

defaultPerson: &defaultPerson
  location: 
    city: Amsterdam
    country: Netherlands
  occupation:
    title: independent consultant
    expertise:
      - serverless
      - aws

Предположим, я хочу изменить location.city и вставить новое поле occupation.company. Посмотрите, что произойдет, если я применю переопределения до и после привязки:

AFAIK, единственный способ сделать эту работу - объявить несколько якорей:

defaultPerson: &defaultPerson
  location: &defaultLocation
    city: Amsterdam
    country: Netherlands
  occupation: &defaultOccupation
    title: independent consultant
    expertise:
      - serverless
      - aws
Yan: 
  <<: *defaultPerson
  location: 
    <<: *defaultLocation
    city: Amstelveen
  occupation:
    <<: *defaultOccupation
    company: theburningmonk ltd

Хотя становится немного беспорядочно.

Объекты JS Proxy

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

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

index:
  handler: index.handler
  events:
    - http: ${file(defaultHttp.js):withMethod("get")}
    - http: ${file(defaultHttp.js):withMethod("post")}

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

const generateConfig = (method) => ({
  path: '/',
  method
});
module.exports.get = () => generateConfig('get');
module.exports.post = () => generateConfig('post');

Тогда я смогу сослаться на них в serverless.yml:

index:
  handler: index.handler
  events:
    - http: ${file(defaultHttp.js):get}
    - http: ${file(defaultHttp.js):post}

Это двухэтапный процесс. К счастью, с ES6 Proxy мы можем добиться большего!

Мы можем вернуть Proxy, который блокирует любую попытку доступа к свойству экспортируемого объекта. Имя запрашиваемого свойства (например, get) используется для создания фактического объекта конфигурации, который мы вернем.

const handler = {
  get: function (obj, method) {
    return () => ({
      path: '/',
      method
    });
  }
}
module.exports = new Proxy({}, handler);

И вот что происходит, когда я ссылаюсь на ${file(xyz.js):get}:

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

const handler = {
  get: function (obj, city) {
    return () => ({
      location: {
        city, // customize a nested field
        country: 'Netherlands'
      },
      occupation: {
        title: "independent consultant",
        expertise: ["serverless", "aws"]
      }
    });
  }
}
module.exports = new Proxy({}, handler);

И импортируйте конфиг вот так:

custom: 
  yan: ${file(defaultPerson.js):Amstelveen}

Но ждать! Могу ли я вставить / обновить свойство в произвольном месте, как в примере defaultPerson ранее?

Ну да, это можно сделать, вернув еще Proxy из первого Proxy.

Например, следующий объект конфигурации позволяет вам обновить path или method или вставить новое поле.

const _ = require('lodash');
const template = {
  path: '/',
  method: 'get'
};
const handler = {
  get: function (obj, path) {
    const x = _.cloneDeep(obj);
    return () => new Proxy(x, {
      get: function (obj, value) {
        _.set(obj, path, value);
        return obj;
      }
    });
  }
}
module.exports = new Proxy(template, handler);

Затем вы можете ссылаться на него в serverless.yml следующим образом:

functions:
  index:
    handler: index.handler
    events:
      - http: ${file(defaultHttp.js):path./index}
      - http: ${file(defaultHttp.js):method.post}

При этом конечные точки создаются так, как вы и ожидали:

endpoints:
  GET -https://xxx.execute-api.us-east-1.amazonaws.com/dev/index
  POST -https://xxx.execute-api.us-east-1.amazonaws.com/dev/

Вот что происходит, когда я ссылаюсь на ${file(xyz.js}:method.post}:

Но подождите еще раз! Можете ли вы настроить конфигурацию с более чем одной переменной? Например. что, если я хочу настроить и path, и method?

У вас может быть Proxy, который возвращает другой Proxy, который возвращает еще Proxy, и так далее. Возможно, это возможно.

Как предложил Филипп Бо, вы также можете создать схему для поддержки пар "ключ-значение", разделенных запятыми. Например, ${file(xyz.js):key0_value0-key1_value1}

Я оставлю это вам, читатели, в качестве упражнения. Дайте волю своему воображению и дайте мне знать, какие практические проблемы вы пытаетесь решить. (Я люблю хорошие хаки, но решение реальных проблем всегда приносит больше удовольствия ;-))

Привет, меня зовут Ян Цуй. Я AWS Serverless Hero и автор книги Production-Ready Serverless. Я выполнял масштабную производственную нагрузку в AWS почти 10 лет, и я был архитектором или главным инженером в различных отраслях, от банковского дела, электронной коммерции, спортивных трансляций до мобильных игр. В настоящее время я работаю независимым консультантом, специализирующимся на AWS и бессерверных технологиях.

Вы можете связаться со мной через Электронная почта, Twitter и LinkedIn.

Ознакомьтесь с моим новым курсом Полное руководство по AWS Step Functions.

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

Получите свой экземпляр здесь.

Узнайте об операционных ЛУЧШИХ ПРАКТИКАХ для AWS Lambda: CI / CD, локальные функции тестирования и отладки, ведение журнала, мониторинг, распределенная трассировка, стандартные развертывания, управление конфигурацией, аутентификация и авторизация, VPC, безопасность, обработка ошибок , и больше.

Вы также можете получить скидку 40% от номинальной стоимости, используя код ytcui.

Получите свой экземпляр здесь.

Первоначально опубликовано на https://theburningmonk.com 5 августа 2019 г.