Разрабатывайте собственные плагины

Вы просматриваете документацию Apigee Edge .
Перейдите к документации Apigee X.
информация

Edge Microgateway v. 3.1.x

Аудитория

Этот раздел предназначен для разработчиков, желающих расширить возможности Edge Microgateway путем написания собственных плагинов. Если вы хотите написать новый плагин, необходим опыт работы с JavaScript и Node.js.

Что такое специальный плагин Edge Microgateway?

Плагин — это модуль Node.js, который добавляет функциональность Edge Microgateway. Модули подключаемых модулей следуют единому шаблону и хранятся в месте, известном Edge Microgateway, что позволяет их обнаруживать и запускать автоматически. При установке Edge Microgateway предоставляется несколько предопределенных плагинов. К ним относятся плагины для аутентификации, блокировки пиков, квот и аналитики. Эти существующие плагины описаны в разделе «Использование плагинов» .

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

Куда поместить собственный код плагина

Папка для пользовательских плагинов включена в установку Edge Microgateway здесь:

[prefix]/lib/node_modules/edgemicro/node_modules/microgateway-plugins

где [prefix] — это каталог префикса npm , как описано в разделе «Где установлен Edge Microgateway» в разделе «Установка Edge Microgateway ».

Вы можете изменить этот каталог плагинов по умолчанию. См. Где найти плагины .

Обзор предустановленных плагинов

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

[prefix]/lib/node_modules/edgemicro/node_modules/microgateway-plugins

где [prefix] — каталог префикса npm . См. также «Где установлен Edge Microgateway» в разделе «Установка Edge Microgateway ».

Дополнительные сведения см. также в разделе «Предварительно определенные плагины, поставляемые с Edge Microgateway» .

Напишите простой плагин

В этом разделе мы рассмотрим шаги, необходимые для создания простого плагина. Этот плагин переопределяет данные ответа (какими бы они ни были) строкой «Hello, World!» и печатает его на терминал.

  1. Если Edge Microgateway запущен, остановите его сейчас:
    edgemicro stop
    
  2. cd в каталог пользовательского плагина:

    cd [prefix]/lib/node_modules/edgemicro/plugins

    где [prefix] — это каталог префикса npm , как описано в разделе «Где установлен Edge Microgateway» в разделе «Установка Edge Microgateway ».

  3. Создайте новый проект плагина под названием response-override и cd к нему:
    mkdir response-override && cd response-override
    
  4. Создайте новый проект Node.js:
    npm init
    
    Нажмите Return несколько раз, чтобы принять значения по умолчанию.
  5. Используйте текстовый редактор, чтобы создать новый файл с именем index.js .
  6. Скопируйте следующий код в index.js и сохраните файл.
    'use strict';
    var debug = require('debug')
    
    module.exports.init = function(config, logger, stats) {
    
      return {
       
        ondata_response: function(req, res, data, next) {
          debug('***** plugin ondata_response');
          next(null, null);
        },
        
        onend_response: function(req, res, data, next) {
          debug('***** plugin onend_response');
          next(null, "Hello, World!\n\n");
        }
      };
    }
    
  7. Теперь вы создали плагин, и вам нужно добавить его в конфигурацию Edge Microgateway. Откройте файл $HOME/.edgemicro/[org]-[env]-config.yaml , где org и env — это имена вашей организации Edge и среды.
  8. Добавьте плагин response-override в элемент plugins:sequence , как показано ниже.
          ...
          
          plugins:
            dir: ../plugins
            sequence:
              - oauth
              - response-override
              
          ...
    
  9. Перезапустите Edge Microgateway.
  10. Вызовите API через Edge Microgateway. (Этот вызов API предполагает, что вы настроили ту же конфигурацию, что и в руководстве, с защитой ключа API, как описано в разделе «Установка и настройка Edge Microgateway» :
    curl -H 'x-api-key: uAM4gBSb6YoMvTHfx5lXJizYIpr5Jd' http://localhost:8000/hello/echo
    Hello, World!
    

Анатомия плагина

Следующий пример плагина Edge Microgateway иллюстрирует шаблон, которому следует следовать при разработке собственных плагинов. Исходный код примера плагина, обсуждаемого в этом разделе, находится в plugins/header-uppercase/index.js.

  • Плагины — это стандартные модули NPM с package.json и index.js в корневой папке.
  • Плагин должен экспортировать функцию init() .
  • Функция init() принимает три аргумента: config , logger и stats . Эти аргументы описаны в разделе «Аргументы функции init() плагина».
  • init() возвращает объект с именованными обработчиками функций, которые вызываются при возникновении определенных событий во время существования запроса.

Функции обработчика событий

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

Обработчики событий потока запросов

Эти функции вызываются по событиям запроса в Edge Microgateway.

  • onrequest
  • ondata_request
  • onend_request
  • onclose_request
  • onerror_request

функция onrequest

Вызывается в начале клиентского запроса. Эта функция срабатывает, когда Edge Microgateway получает первый байт запроса. Эта функция предоставляет вам доступ к заголовкам запроса, URL-адресу, параметрам запроса и методу HTTP. Если вы вызываете next с правдивым первым аргументом (например, экземпляром Error), обработка запроса останавливается и целевой запрос не инициируется.

Пример:

onrequest: function(req, res, next) {
      debug('plugin onrequest');
      req.headers['x-foo-request-start'] = Date.now();
      next();
    }

функция ondata_request

Вызывается, когда от клиента получен фрагмент данных. Передаёт данные запроса следующему плагину в последовательности плагинов. Возвращаемое значение из последнего плагина в последовательности отправляется в цель. Типичный вариант использования, показанный ниже, — преобразование данных запроса перед их отправкой в ​​цель.

Пример:

ondata_request: function(req, res, data, next) {
      debug('plugin ondata_request ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    }

функция onend_request

Вызывается, когда все данные запроса получены от клиента.

Пример:

onend_request: function(req, res, data, next) {
      debug('plugin onend_request');
      next(null, data);
    }

функция onclose_request

Указывает, что клиентское соединение закрыто. Вы можете использовать эту функцию в случаях, когда клиентское соединение ненадежно. Он вызывается, когда соединение сокета с клиентом закрывается.

Пример:

onclose_request: function(req, res, next) {
      debug('plugin onclose_request');
      next();
    }

функция onerror_request

Вызывается, если при получении клиентского запроса произошла ошибка.

Пример:

onerror_request: function(req, res, err, next) {
      debug('plugin onerror_request ' + err);
      next();
    }

Обработчики событий потока ответов

Эти функции вызываются при ответных событиях в Edge Microgateway.

  • onresponse
  • ondata_response
  • onend_response
  • onclose_response
  • onerror_response

функция onresponse

Вызывается в начале целевого ответа. Эта функция срабатывает, когда Edge Microgateway получает первый байт ответа. Эта функция дает вам доступ к заголовкам ответов и коду состояния.

Пример:

onresponse: function(req, res, next) {      
    debug('plugin onresponse');     
    res.setHeader('x-foo-response-time', Date.now() - req.headers['x-foo-request-start'])    
    next();    
}


функция ondata_response

Вызывается, когда от цели получен фрагмент данных.

Пример:

ondata_response: function(req, res, data, next) {
      debug('plugin ondata_response ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    }


функция onend_response

Вызывается, когда все данные ответа получены от цели.

Пример:

onend_response: function(req, res, data, next) {
      debug('plugin onend_response');
      next(null, data);
    }

функция onclose_response

Указывает, что целевое соединение закрыто. Вы можете использовать эту функцию в случаях, когда целевое соединение ненадежно. Он вызывается, когда соединение сокета с целью закрывается.

Пример:

onclose_response: function(req, res, next) {
      debug('plugin onclose_response');
      next();
    }


функция onerror_response

Вызывается, если при получении целевого ответа произошла ошибка.

Пример:

onerror_response: function(req, res, err, next) {
      debug('plugin onerror_response ' + err);
      next();
    }

Что нужно знать о функциях обработчика событий плагина

Функции обработчика событий плагина вызываются в ответ на определенные события, которые происходят, когда Edge Microgateway обрабатывает заданный запрос API.

  • Каждый из обработчиков функции init() ( ondata_request , ondata_response и т. д.) должен вызвать обратный вызов next() после завершения обработки. Если вы не вызовете next() , обработка остановится и запрос зависнет.
  • Первым аргументом функции next() может быть ошибка, которая приведет к прекращению обработки запроса.
  • Обработчики ondata_ и onend_ должны вызывать next() со вторым аргументом, содержащим данные, которые будут переданы цели или клиенту. Этот аргумент может иметь значение null, если плагин выполняет буферизацию и в данный момент не имеет достаточно данных для преобразования.
  • Обратите внимание, что для обслуживания всех запросов и ответов используется один экземпляр плагина. Если плагин желает сохранить состояние каждого запроса между вызовами, он может сохранить это состояние в свойстве, добавленном к предоставленному объекту запроса ( req ), время жизни которого равно продолжительности вызова API.
  • Будьте осторожны, чтобы отловить все ошибки и вызвать next() с ошибкой. Невыполнение вызова next() приведет к зависанию вызова API.
  • Будьте осторожны, чтобы не допускать утечек памяти, поскольку это может повлиять на общую производительность Edge Microgateway и привести к сбою в случае нехватки памяти.
  • Будьте осторожны и следуйте модели Node.js, не выполняя ресурсоемкие задачи в основном потоке, поскольку это может отрицательно повлиять на производительность Edge Microgateway.

О функции init() плагина

В этом разделе описаны аргументы, передаваемые в функцию init() : config , logger и stats .

конфигурация

Объект конфигурации, полученный после объединения файла конфигурации Edge Microgateway с информацией, загруженной из Apigee Edge, такой как продукты и квоты. Вы можете найти конфигурацию, специфичную для плагина, в этом объекте: config.<plugin-name> .

Чтобы добавить параметр конфигурации с именем param со значением foo в плагин с именем response-override , поместите его в файл default.yaml :

response-override:
    param: foo

Затем вы можете получить доступ к параметру в коде вашего плагина, например:

// Called when response data is received
    ondata_response: function(req, res, data, next) {
      debug('***** plugin ondata_response');
      debug('***** plugin ondata_response: config.param: ' + config.param);
      next(null, data);
    },

В этом случае вы увидите foo, напечатанное в выводе отладки плагина:

Sun, 13 Dec 2015 21:25:08 GMT plugin:response-override ***** plugin ondata_response: config.param: foo

лесоруб

Системный регистратор. Используемый в данный момент регистратор экспортирует эти функции, где объектом может быть строка, HTTP-запрос, HTTP-ответ или экземпляр ошибки.

  • info(object, message)
  • warn(object, message)
  • error(object, message)

статистика

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

  • treqErrors — количество целевых запросов с ошибками.
  • treqErrors — количество целевых ответов с ошибками.
  • statusCodes — объект, содержащий количество кодов ответа:
{
  1: number of target responses with 1xx response codes
  2: number of target responses with 2xx response codes
  3: number of target responses with 3xx response codes
  4: number of target responses with 4xx response codes
  5: number of target responses with 5xx response codes
  }
  
  • запросы — общее количество запросов.
  • ответы – общее количество ответов.
  • Connections — количество активных целевых соединений.

О функции next()

Все методы плагина должны вызывать next() , чтобы продолжить обработку следующего метода в серии (иначе процесс плагина зависнет). В жизненном цикле запроса первым вызывается метод onrequest(). Следующий вызываемый метод — метод ondata_request() ; однако ondata_request вызывается только в том случае, если запрос включает данные, как, например, в случае запроса POST. Следующим вызываемым методом будет onend_request() , который вызывается после завершения обработки запроса. Функции onerror_* вызываются только в случае ошибки и позволяют при желании обрабатывать ошибки с помощью специального кода.

Допустим, данные отправляются в запросе и вызывается ondata_request() . Обратите внимание, что функция вызывает next() с двумя параметрами:

next(null, data);

По соглашению первый параметр используется для передачи информации об ошибке, которую вы затем можете обработать в последующей функции в цепочке. Установив для него значение null (ложный аргумент), мы говорим, что ошибок нет и обработка запроса должна проходить нормально. Если этот аргумент правдив (например, объект Error), обработка запроса останавливается и запрос отправляется адресату.

Второй параметр передает данные запроса следующей функции в цепочке. Если вы не выполняете никакой дополнительной обработки, данные запроса передаются без изменений в целевой API. Однако у вас есть возможность изменить данные запроса внутри этого метода и передать измененный запрос цели. Например, если данные запроса представляют собой XML, а цель ожидает JSON, вы можете добавить код в метод ondata_request() , который (а) меняет Content-Type заголовка запроса на application/json и преобразует данные запроса в JSON любыми способами (например, вы можете использовать конвертер Node.js xml2json, полученный из NPM).

Давайте посмотрим, как это может выглядеть:

ondata_request: function(req, res, data, next) {
  debug('****** plugin ondata_request');
  var translated_data = parser.toJson(data);
  next(null, translated_data);
},

В этом случае данные запроса (предполагаемые в формате XML) преобразуются в JSON, а преобразованные данные передаются через next() следующей функции в цепочке запросов перед передачей в серверную цель.

Обратите внимание, что вы можете добавить еще один оператор отладки для печати преобразованных данных в целях отладки. Например:

ondata_request: function(req, res, data, next) {
  debug('****** plugin ondata_request');
  var translated_data = parser.toJson(data);
  debug('****** plugin ondata_response: translated_json: ' + translated_json);
  next(null, translated_data);
},

О порядке выполнения обработчика плагина

Если вы пишете плагины для Edge Microgateway, вам необходимо понимать порядок, в котором выполняются обработчики событий плагина.

Важно помнить, что когда вы указываете последовательность плагинов в файле конфигурации Edge Microgateway, обработчики запросов выполняются в порядке возрастания , а обработчики ответов выполняются в порядке убывания .

Следующий пример призван помочь вам понять эту последовательность выполнения.

1. Создайте три простых плагина.

Рассмотрим следующий плагин. Все, что он делает, это печатает вывод консоли при вызове его обработчиков событий:

плагины/плагин-1/index.js

module.exports.init = function(config, logger, stats) {

  return {

    onrequest: function(req, res, next) {
      console.log('plugin-1: onrequest');
      next();
    },

    onend_request: function(req, res, data, next) {
      console.log('plugin-1: onend_request');
      next(null, data);
    },

    ondata_response: function(req, res, data, next) {
      console.log('plugin-1: ondata_response ' + data.length);
      next(null, data);
    },

    onend_response: function(req, res, data, next) {
      console.log('plugin-1: onend_response');
      next(null, data);
    }
  };
}

Теперь рассмотрите возможность создания еще двух плагинов, plugin-2 и plugin-3 , с тем же кодом (за исключением того, что измените операторы console.log() на plugin-2 и plugin-3 соответственно).

2. Просмотрите код плагина.

Экспортированные функции плагина в <microgateway-root-dir>/plugins/plugin-1/index.js представляют собой обработчики событий, которые выполняются в определенное время во время обработки запросов и ответов. Например, onrequest выполняет получение первого байта заголовков запроса. В то время как onend_response выполняется после получения последнего байта данных ответа.

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

3. Добавьте плагины в последовательность плагинов.

Продолжая этот пример, мы добавим плагины в последовательность плагинов в файле конфигурации Edge Microgateway ( ~./edgemicro/config.yaml ) следующим образом. Последовательность важна. Он определяет порядок выполнения обработчиков плагинов.

  plugins:
    dir: ../plugins
    sequence:
      - plugin-1
      - plugin-2
      - plugin-3
  

4. Изучите выходные данные отладки.

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

  • Последовательность плагинов в файле конфигурации Edge Microgateway ( ~./edgemicro/config.yaml ) определяет порядок вызова обработчиков событий.
  • Обработчики запросов вызываются в порядке возрастания (порядок, в котором они появляются в последовательности плагина — 1, 2, 3).
  • Обработчики ответов вызываются в порядке убывания — 3, 2, 1.
  • Обработчик ondata_response вызывается один раз для каждого поступающего фрагмента данных. В этом примере (выходные данные показаны ниже) получены два фрагмента.

Вот пример вывода отладки, который создается, когда эти три плагина используются и запрос отправляется через Edge Microgateway. Просто обратите внимание на порядок вызова обработчиков:

  plugin-1: onrequest
  plugin-2: onrequest
  plugin-3: onrequest

  plugin-1: onend_request
  plugin-2: onend_request
  plugin-3: onend_request

  plugin-3: ondata_response 931
  plugin-2: ondata_response 931
  plugin-1: ondata_response 931

  plugin-3: ondata_response 1808
  plugin-3: onend_response

  plugin-2: ondata_response 1808
  plugin-2: onend_response

  plugin-1: ondata_response 1808
  plugin-1: onend_response

Краткое содержание

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

Просто помните, что обработчики запросов выполняются в том порядке, в котором плагины указаны в конфигурационном файле Edge Microgateway, а обработчики ответов выполняются в обратном порядке.

Об использовании глобальных переменных в плагинах

Каждый запрос к Edge Microgateway отправляется одному и тому же экземпляру плагина; следовательно, состояние второго запроса от другого клиента перезапишет первое. Единственное безопасное место для сохранения состояния плагина — это сохранение состояния в свойстве объекта запроса или ответа (время жизни которого ограничено временем запроса).

Перезапись целевых URL-адресов в плагинах

Добавлено: v2.3.3

Вы можете динамически переопределить целевой URL-адрес по умолчанию в плагине, изменив эти переменные в коде плагина: req.targetHostname и req.targetPath .

Добавлено: v2.4.x

Вы также можете переопределить порт целевой конечной точки и выбрать между HTTP и HTTPS. Измените эти переменные в коде вашего плагина: req.targetPort и req.targetSecure . Чтобы выбрать HTTPS, установите для req.targetSecure значение true ; для HTTP установите значение false . Если вы установили для req.targetSecure значение true, дополнительную информацию см. в этой теме обсуждения .

Пример плагина под названием eurekaclient был добавлен в Edge Microgateway. Этот плагин демонстрирует, как использовать переменные req.targetPort и req.targetSecure, а также показывает, как Edge Microgateway может выполнять динамический поиск конечных точек, используя Eureka в качестве каталога конечных точек службы.


Примеры плагинов

Эти плагины поставляются вместе с установкой Edge Microgateway. Вы можете найти их в установке Edge Microgateway здесь:

[prefix]/lib/node_modules/edgemicro/plugins

где [prefix] — это каталог префикса npm , как описано в разделе «Где установлен Edge Microgateway» в разделе «Установка Edge Microgateway ».

накапливать-запрос

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

module.exports.init = function(config, logger, stats) {

  function accumulate(req, data) {

    if (!req._chunks) req._chunks = [];
    req._chunks.push(data);

  }

  return {

    ondata_request: function(req, res, data, next) {

      if (data && data.length > 0) accumulate(req, data);

      next(null, null);

    },


    onend_request: function(req, res, data, next) {

      if (data && data.length > 0) accumulate(req, data);

      var content = null;

      if (req._chunks && req._chunks.length) {

        content = Buffer.concat(req._chunks);

      }

      delete req._chunks;

      next(null, content);

    }

  };

}

аккумулировать-ответ

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

module.exports.init = function(config, logger, stats) {

  function accumulate(res, data) {
    if (!res._chunks) res._chunks = [];
    res._chunks.push(data);
  }

  return {

    ondata_response: function(req, res, data, next) {
      if (data && data.length > 0) accumulate(res, data);
      next(null, null);
    },

    onend_response: function(req, res, data, next) {
      if (data && data.length > 0) accumulate(res, data);
      var content = Buffer.concat(res._chunks);
      delete res._chunks;
      next(null, content);
    }

  };

}

плагин заголовка-прописных букв

Дистрибутивы Edge Microgateway включают пример плагина под названием <microgateway-root-dir>/plugins/header-uppercase . Образец включает комментарии, описывающие каждый из обработчиков функций. В этом примере выполняется простое преобразование данных целевого ответа и добавляются пользовательские заголовки к клиентскому запросу и целевому ответу.

Вот исходный код <microgateway-root-dir>/plugins/header-uppercase/index.js :

'use strict';

var debug = require('debug')('plugin:header-uppercase');

// required
module.exports.init = function(config, logger, stats) {

  var counter = 0;

  return {

    // indicates start of client request
    // request headers, url, query params, method should be available at this time
    // request processing stops (and a target request is not initiated) if
    // next is called with a truthy first argument (an instance of Error, for example)
    onrequest: function(req, res, next) {
      debug('plugin onrequest');
      req.headers['x-foo-request-id'] = counter++;
      req.headers['x-foo-request-start'] = Date.now();
      next();
    },

    // indicates start of target response
    // response headers and status code should be available at this time
    onresponse: function(req, res, next) {
      debug('plugin onresponse');
      res.setHeader('x-foo-response-id', req.headers['x-foo-request-id']);
      res.setHeader('x-foo-response-time', Date.now() - req.headers['x-foo-request-start']);
      next();
    },

    // chunk of request body data received from client
    // should return (potentially) transformed data for next plugin in chain
    // the returned value from the last plugin in the chain is written to the target
    ondata_request: function(req, res, data, next) {
      debug('plugin ondata_request ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    },

    // chunk of response body data received from target
    // should return (potentially) transformed data for next plugin in chain
    // the returned value from the last plugin in the chain is written to the client
    ondata_response: function(req, res, data, next) {
      debug('plugin ondata_response ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    },

    // indicates end of client request
    onend_request: function(req, res, data, next) {
      debug('plugin onend_request');
      next(null, data);
    },

    // indicates end of target response
    onend_response: function(req, res, data, next) {
      debug('plugin onend_response');
      next(null, data);
    },

    // error receiving client request
    onerror_request: function(req, res, err, next) {
      debug('plugin onerror_request ' + err);
      next();
    },

    // error receiving target response
    onerror_response: function(req, res, err, next) {
      debug('plugin onerror_response ' + err);
      next();
    },

    // indicates client connection closed
    onclose_request: function(req, res, next) {
      debug('plugin onclose_request');
      next();
    },

    // indicates target connection closed
    onclose_response: function(req, res, next) {
      debug('plugin onclose_response');
      next();
    }

  };

}


преобразование в верхний регистр

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

 */
module.exports.init = function(config, logger, stats) {

  // perform content transformation here
  // the result of the transformation must be another Buffer
  function transform(data) {
    return new Buffer(data.toString().toUpperCase());
  }

  return {

    ondata_response: function(req, res, data, next) {
      // transform each chunk as it is received
      next(null, data ? transform(data) : null);
    },

    onend_response: function(req, res, data, next) {
      // transform accumulated data, if any
      next(null, data ? transform(data) : null);
    },

    ondata_request: function(req, res, data, next) {
      // transform each chunk as it is received
      next(null, data ? transform(data) : null);
    },

    onend_request: function(req, res, data, next) {
      // transform accumulated data, if any
      next(null, data ? transform(data) : null);
    }

  };

}