Проблема
Всего пару недель назад я попробовал поток для новой серверной службы и обнаружил, что это довольно крутой инструмент (если его можно так назвать) для обеспечения безопасности кода. Несколько слов о сервисе: он доступен через REST и MQ для других сервисов, этот сервис генерирует некоторые текстовые сообщения типа переданного в зависимости от переданных параметров. Например:
// Request body { type: ‘SpectatorsMessage’, parameters: { eventId: 12345 } }
Предположим, что у вас есть много классов сообщений с разными типами, требуемыми в конструкторе.
// @flow // messages.js type Params = { eventId: number }; export class SpectatorsMessage { constructor(params: Params) {…} } // many other messages
И когда я реализовывал логику в генерации сообщений, отображении данных и т. д., я был очень доволен потоком, но когда я добавил простой маршрут для генерации этих сообщений, я застрял.
import * as messages from ‘my-messages’; router.post(‘/message’, ctx => { const { type, parameters } = ctx.request.body; const Message = messages[type]; if (Message) { // and here I would like to do some validation // of parameters for this type of message
Я надеюсь, вы понимаете, что поток является статическим средством проверки типов и не обеспечивает никаких проверок во время выполнения. Для этого есть модуль flow-runtime, но он медленный для продакшена, и я не хотел проверять весь код.
Хотя я не хотел копировать потоковые типы и преобразовывать их в какие-то функции валидатора, json-схему или другое. Я пытался найти что-то приемлемое для этой цели (модуль npm, конечно), но ничего.
Решение:
Я решил сделать свой собственный бабелевский плагин (наверное, лучше сделать скрипт codemod), который преобразует потоковые типы в JSON-схему. Теперь этот класс сообщений будет выглядеть так:
// IN: type Params = { eventId: number }; export class SpectatorsMessage { // $flow-to-json static propTypes: Params; constructor(params: Params) {…} } // OUT: export class SpectatorsMessage { // $flow-to-json static propTypes = { type: 'object', properties: { eventId: { type: 'number' } }, required: ['eventId'] }; constructor(params: Params) {…} }
Комментарий $flow-to-json используется, чтобы показать подключаемому модулю Babel, что вы хотите преобразовать это свойство в json-схему переданного типа (он обрабатывает любые статические свойства в классах).
Итак, теперь у меня есть действующая схема JSON (черновик 6), и я могу легко проверять свойства, которые я хочу проверить во время выполнения. Он охватывает множество вариантов использования (все мои, например), теперь осталось не так много нереализованных вещей. Вы можете проверить репозиторий, посмотреть, что реализовано, а что нет в ридми. Я буду рад отзывам, если вы протестируете его, создадите проблему, PR или просто поставите ему звезду.
P.S. Извините, если пример в этой статье не был ясен или странен, но в ридми репозитория вы можете найти, вероятно, более очевидный пример.