[Перевод] Как мы сделали из JSON язык программирования

Спустя месяцы напряжённой работы мы наконец выпустили приложение для iOS Relevant. С ним мы ломаем существующие устои взаимодействия с сервисами и контентом в сети, благодаря чему пользователь тратит куда меньше времени на привычные вещи. Достигается это путём представления приложений и веб-сервисов в виде карточек (подробнее здесь).

Карточки, как независимые интерактивные единицы, показывают, каким будет будущее мобильных интерфейсов.imageКогда мы только начали работать над Relevant, нам были ясны лишь две вещи: карточки должны быть красивыми, и они должны быть универсальными. То есть их содержание может формироваться из любого источника информации в сети с минимальными ограничениями. Что до красивости, так она заслуживает отдельной статьи, и здесь мы её касаться не будем, а поговорим именно об универсальности.

Так как карточки Relevant должны быть лёгкими и скачиваемыми, мы решили представлять их в виде JSON-файлов, содержащих инструкции о том, как получить доступ к различным источникам информации и API в сети и как преобразовать полученные данные в содержимое карточек.imageТребовалась необычайно гибкая структура карточек, которая бы не усложняла процесс их создания. Должна быть возможность, например, получения от API массива с товарами, а затем и получение подробной информации о каждом из них. Причём получение данных может происходить посредством разных API с последующим сбором всего этого воедино.

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

Веб-сервисы и API представлены в виде самых разных форм. Некоторые API, когда требуется вернуть список, возвращают просто массив, в то время как другие засовывают его куда-то в недра возвращаемого объекта. Одни используют разбиение на страницы, другие принимают явный параметр страницы. [Не совсем ясно, в чем заключается подразумевающаяся разница] Добавьте к этому сотни стандартов формата даты и времени, пару стандартов URL и случайное оборачивание целых и дробных чисел в кавычки. Большинство разработчиков, пытающихся создать систему агрегации многочисленных API, быстро погружаются в многоуровневый ад из блоков if-else.

Нам хотелось чего-то более мощного. Требовалось сделать нашу платформу независимой от качества дизайна API и его данных. После долгих проб и ошибок Relevant Card«s JSON стал выглядеть примерно так: image

Большая часть нашей инфраструктуры агрегации API лежит на сложных серверных и клиентских системах. Тем не менее, придуманный нами JSON-ориентированный язык REL заслуживает отдельного упоминания.

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

Типы и переменные

Типы в REL — это стандартные типы JSON: числа, строки, объекты и массивы. В большинстве случаев они парсятся непосредственно. Однако некоторые объекты имеют особое значение. Пары ключ-значение объекта, имеющего ключ »_RETURN», парсятся как пары переменная-значение. Обращение к переменным осуществляется посредством фигурных скобок:»{variable_name}».

Например, следующий объект

{
    "foo":1,
    "var":2,
    "_RETURN":{"_MATH":"{foo}+{var}"}
}

REL представляет как число 3.

Функции

Мы часто добавляем новые встроенные функции в REL. Эти функции выглядят как объекты с определёнными специальными ключами, которые начинаются с символа подчёркивания. Функция »_MATH» из примера выше разбирает строку как математическое выражение и возвращает его результат.

Среди других встроенных функций можно выделить »_URL», которая загружает JSON по заданному адресу, и »_PATH», которая ищет значение в объекте JSON или массиве. Эти две функции являются основными, использующимися для агрегации API в REL Engine.

Можно даже создавать пользовательские функции. Больше информации об этом в документации.

Управление порядком выполнения

Встроенные функции, такие как {»_IF»:,»_THEN»:,»_ELSE»:} и {»_LOOP»: {»_ARRAY»:,»_EACH»:}} используются для управления порядком выполнения, но, в отличие от нефункциональных языков (таких как C или Java), они всегда возвращают значение.

Больше информации о текущей версии REL всегда можно найти в документации.

Также доступна развивающаяся библиотека карточек с примерами и описаниями на REL.

От переводчика

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

© Habrahabr.ru