Спустя месяцы напряжённой работы мы наконец выпустили приложение для iOS Relevant. С ним мы ломаем существующие устои взаимодействия с сервисами и контентом в сети, благодаря чему пользователь тратит куда меньше времени на привычные вещи. Достигается это путём представления приложений и веб-сервисов в виде карточек (подробнее здесь).
Карточки, как независимые интерактивные единицы, показывают, каким будет будущее мобильных интерфейсов.
Когда мы только начали работать над Relevant, нам были ясны лишь две вещи: карточки должны быть красивыми, и они должны быть универсальными. То есть их содержание может формироваться из любого источника информации в сети с минимальными ограничениями. Что до красивости, так она заслуживает отдельной статьи, и здесь мы её касаться не будем, а поговорим именно об универсальности.
Карточки как объекты JSON
Так как карточки Relevant должны быть лёгкими и скачиваемыми, мы решили представлять их в виде JSON-файлов, содержащих инструкции о том, как получить доступ к различным источникам информации и API в сети и как преобразовать полученные данные в содержимое карточек.
Требовалась необычайно гибкая структура карточек, которая бы не усложняла процесс их создания. Должна быть возможность, например, получения от API массива с товарами, а затем и получение подробной информации о каждом из них. Причём получение данных может происходить посредством разных API с последующим сбором всего этого воедино.
Таким образом, стало ясно, что требуется создать универсальный API-агрегатор: гибкий, легко изменяемый и хранящийся во внешних файлах. Это позволит создать экосистему, где карточки смогут развиваться, в отличие от приложений, содержимое которых недоступно для пользователя, так как разработчики просто захардкодили его.
API нестандартны
Веб-сервисы и API представлены в виде самых разных форм. Некоторые API, когда требуется вернуть список, возвращают просто массив, в то время как другие засовывают его куда-то в недра возвращаемого объекта. Одни используют разбиение на страницы, другие принимают явный параметр страницы. [Не совсем ясно, в чем заключается подразумевающаяся разница] Добавьте к этому сотни стандартов формата даты и времени, пару стандартов URL и случайное оборачивание целых и дробных чисел в кавычки. Большинство разработчиков, пытающихся создать систему агрегации многочисленных API, быстро погружаются в многоуровневый ад из блоков if-else.
Нам хотелось чего-то более мощного. Требовалось сделать нашу платформу независимой от качества дизайна API и его данных. После долгих проб и ошибок Relevant Card’s JSON стал выглядеть примерно так:
Большая часть нашей инфраструктуры агрегации API лежит на сложных серверных и клиентских системах. Тем не менее, придуманный нами JSON-ориентированный язык REL заслуживает отдельного упоминания.
Быстрое введение в 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.
От переводчика
Перевод местами достаточно вольный, но не в ущерб смыслу или содержанию. Все, что не относится напрямую к оригиналу, вынесено в примечания. Автор публикации является по совместительству и автором приложения, так что исходный текст является несколько рекламным. Я постарался перенести акцент именно на разработанный язык. За большим количеством ссылок и разнообразных призывов обращайтесь к оригиналу.
С предложениями, пожеланиями и замечаниями, как обычно, в ЛС.
Автор: gwer