Какой выбрать фреймворк для API на Ruby

Illustration of anthropomorphic mobile apps on chairs in a waiting room: a sleeping music app, a social media app, a messaging app with a hat, and a gaming app being kicked out by a security app. Illustration of anthropomorphic mobile apps on chairs in a waiting room: a sleeping music app, a social media app, a messaging app with a hat, and a gaming app being kicked out by a security app.

Не так давно на берлинском Ruby митапе я рассказывал про свой опыт с Ruby веб-фреймворком Grape. В этой статье я вам расскажу, о чем же я там говорил.

Я работаю в команде, которая занимается разработкой продукта с Single-Page Application архитектурой. Это значит, что мухи с фронтендом у нас отдельно, а котлеты с бэкендом тоже отдельно. Таким образом, от бэкенда остается только API, никакой логики отображения там не подразумевается. Кроме того, у нашего процесса есть своя специфика, мы работаем в очень быстром темпе. Дизайнеры создают концепт, проводят user test’ы, отправляют это на разработку, мы это создаем, выкатываем на открытую бету, если фидбэк позитивный - оставляем, если нет - выпиливаем или изменяем. Поэтому, как можно понять, нам очень важно, чтобы фреймворк не вставлял нам палки в колеса, а, напротив, имел в себе достаточное количество базовых фич, и при этом не ограничивал нас в наших, порой не шаблонных, желаниях.

Язык для разработки был выбран Ruby, потому что он хорошо известен команде. Кроме того что бы ни говорили популисты, это до сих пор самый лучший язык для быстрого прототипирования и выхода на рынок. Например, на днях с другом golang-разработчиком на спор создавали простенький API с интеграцией с бд, чтобы выяснить, кто быстрее. Не в смысле, я или он, а Ruby или Golang, в плане скорости разработки веб-приложения. Понятное дело, что на Ruby это оказалось сделать быстрее, иначе я бы не стал приводить этого примера :) Ни в коем случае не умаляю достоинств Go, они просто совершенно другие.

Не знаешь, что такое API? Тогда сначала прочитай нашу статью Что такое API в веб-приложениях и зачем он нужен.

Выбор фреймворков

Итак, после выбора языка мы должны были выбрать фреймворк. Какие у нас варианты? Ruby on Rails! Хмм… Спасибо, DHH, мы тебе искренне благодарны за твой труд, но давайте посмотрим по сторонам, вдруг что еще найдем.

Если вы, как и я, разрабатываете на Ruby уже достаточно много времени, вы уже давно устали быть Rails-разработчиками. Это то самое чувство, когда вы берете фреймворк с конкретным взглядом на архитектуру, разработчика с конкретным взглядом на архитектуру, и оказывается, что они совершенно не совпадают, так еще и получается, что фреймворк не дает вам следовать принципам, которые вы считаете ключевыми в построении надежной и гибкой системы. Опять-таки, не хочу сказать, что Rails - плохой фреймворк. Приложения на нем начинают подгнивать, если вы не знаете, как их готовить, поэтому все в руках разработчиков, которые, к сожалению, часто не заботятся об архитектуре. Мы готовить и заботиться умеем, но, тем не менее, решили рассмотреть другие варианты. И вот он, не полный, но список:

  • Grape
  • Hanami
  • Roda
  • Rails API
  • Sinatra

А вот какие требования мы предъявляли к фреймворку:

  • Достаточное количество фич из коробки;
  • Поддержка версий;
  • Время на рынке;
  • Производительность;
  • Личное предпочтение. Куда без него.

Фичи из коробки

Есть какой-то набор ключевых фич, без которых API не имеет смысла. Например валидация параметров, поддержка Cross Origin Resource Sharing (CORS), обработка и форматирование ошибок и т. д.

Нет никаких сомнений, что у Rails API это все есть, потому что это все та же Rails экосистема.

Sinatra находится на противоположном конце, в ней нет практически ничего %) Само собой, вы можете построить с ней любую желаемую архитектуру и добавить любые гемы, но, для меня это скорее недостаток. Сервисы на синатре в продакшне у меня были, и не раз, но все же для продукта, который мы создаем, нам хотелось иметь что-то более богатое на фичи. Остальные перечисленные фреймворки находятся где-то между этими двумя и имеют как достаточное количество плюшек из коробки, так и экосистему из дополнительных гемов, поэтому на них отдельно останавливаться не будем.

Поддержка версий

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

Sinatra, Hanami, Rails API:

namespace '/api/v1' do
  # routes goes here
end

Roda:

r.on "api" do
  r.on "v1" do
    r.is "users" do
      r.get do end
      r.post do end
    end
    r.get "comments" do end
  end
end

Grape:

version 'v1', using: :path

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

Время на рынке

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

Grape

Был выпущен в 2010-м году, имеет 4 merged pull requests за январь по данным github аналитики. Rails API. Был выпущен в 2012-м, имеет аж 85 merged pull requests за тот же месяц. Однако не забывайте, что в 2015-м году репозиторий Rails API был слит с основным Rails репозиторием. Таким образом это их совместные пулл реквесты. Это совершенно ожидаемо хотя бы потому, что, как вы знаете, на рынке Ruby-фреймворков царит почти что монополия рельсов.

Sinatra

Своего рода дедушка в этом списке. Был выпущен в 2008-м. При этом развитие у него не прекращается (хотя, что уж там развивать-то), за январь 3 пулл реквеста. С моей точки зрения, особых изменений там уже лет пять как не было, но я не копал глубоко, могу и заблуждаться.

Hanami

Яркий, новый, с интересной идеей разделения контекстов приложения, был выпущен в 2014-м. Однако в мое поле зрения попал только в прошлом году, когда они зарелизили версию 1.0. Насколько я знаю, фреймворк находится в активной разработке, но за январь был смержен только один pull request. На данный момент я знаю людей, кто использует Hanami в продакшне, но на тот момент он был для нас слишком молод.

Roda

Появился в 2014-м, и тогда же создатели выпустили первый стабильный релиз. За январь был смержен один pull request.

Должны ли эти числа значить для вас что-то при выборе фреймворка? Ваше решение. Как по мне, основным фактором это точно не должно быть, однако может быть полезно для отсечки некоторых вариантов.

Производительность

Ну, вы поняли. Производительность веб-фреймворка на Ruby - это явно последнее, на что вы будете обращать внимание, это ведь Ruby. Скорость точно не наш конек. Даже в серьезном проекте, который давно на рынке и который нужно оптимизировать по производительности, веб-фреймворк не будет тем самым bottle neck, который не позволит вам увеличивать производительность. Им будет скорее всего ваш код. Или ваши БД запросы. Или ваша неправильная архитектура.

Личное предпочтение

Как я уже писал, с рельсами и Rails API я работал предостаточно и без проблем поработаю еще, однако в этот раз мы решили сделать выбор не в пользу рельсов. Могу порекомендовать очень известную статью Петра Сольника. Но, не смотря на эту статью и плюсы других фреймворков, если мне сейчас нужно быстро накидать какой-то прототип, и он еще и не API-only, то я скорее всего выберу именно Rails.

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

Hanami, как я уже писал, предлагает интересную модель, когда ты можешь на уровне одного проекта и одной кодовой базы сделать разделение контекста, как если бы ты разрабатывал микросервисную архитектуру, но без всех связанных с этим заморочек (конечно, и без многих плюсов, но это, все-таки, не замена одно другому). В Hanami у тебя есть общая кодовая база в папке lib, но плюс к ней существует папка apps, которая уже может содержать несколько независимых веб-интерфейсов или приложений. На первый взгляд выглядит занятно, однако, как я уже сказал, нам нужно было быстро идти в продакшн, и делать это на фреймворке, в котором мы не уверены в плане отсутствия багов и безопасности, не хочется. Говоря о безопасности, в день, когда я это пишу, был выпущен NPM версии 5.7.0, и он включает в себя страшную дыру в безопасности, которая изменяет права на все ваши системные директории. Это я к тому, что даже проверенный временем софт может внезапно преподнести сюрприз.

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

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

Ложка дегтя

Как известно, идеала не бывает, в Grape тоже есть свои недостатки. И главный для меня - это то, что у Grape свой DSL (domain specific language), т.е. ты пишешь не просто классический руби код, а должен следовать стандартам вызовов и наименований, продиктованных тебе грейпом. И иногда это может приводить к такому отвратительному коду:

expose :some_attribute, if: ->(element, _) { element.final? } do |element|
  element.my_attribute
end

Вывод

Софт - он даже называется софт, потому что это постоянно изменяющаяся «субстанция». И так же как постоянно меняются требования к продукту, так постоянно меняются стандарты, мнения, фавориты и подходы. Кроме того, чаще всего один проект не похож на другой, и решения требуется принимать осознанно. Я надеюсь, что этой статьей я смог вам показать, что даже в мире Ruby фреймворки бывают разные, и их стоит смотреть, пробовать и примерять на свой новый проект. И, конечно же, посмотрите в сторону Grape, это прекрасный API фреймворк!

Хочешь узнать больше о Ruby и API? Читай нашу серию статей, в которой Кирилл Ширинкин создаёт с нуля гем для работы с внешним API Разработка гема GrooveHQ.