В этом посте я хотел бы познакомить вас с Grape — веб-фреймворком, написанным на ruby, предназначенным для быстрой и удобной разработки API, а также немного порассуждать о судьбе Rails в свете последних тенденций в веб-разработке.
Ruby = Ruby On Rails
Как-то так сложилось, что при упоминании ruby в качестве средства веб-разработки (да и просто в качестве скриптового ЯП) передо многими людьми, имеющими некоторое отношение к этой самой веб-разработке, в голове возникает если не логотип с пресловутыми белыми рельсами на красном фоне, то магическое словосочетание Ruby On Rails уж точно.
Я не берусь спорить, хорошо это или плохо — эта статья не для спора. Одно могу сказать с уверенностью — RoR оказал огромное влияние на развитие веб-фреймворков в целом, а этот вклад переоценить крайне трудно.
НО
Но жизнь не стоит на месте.
Веб становится динамичным, все большее и большее значение приобретают мобильные приложения, пользователю нужно потреблять контент «не отходя от кассы», то есть с экрана своего айфона, гугл нексуса, хуайвэя, впиши_название_своего_телефона.
Да и сами сайты нуждаются в качественно новых подходах к организации пользовательских взаимодействий и подаче контента.
AngularJS, Ember, Meteor.js, Derby.js — технологии, предвосхищающие очередной прорыв в сайтостроении, который можно сравнить с «изобретением» AJAX в старые добрые времена.
Ruby-разработчикам нужно мощное и в то же время легкое для освоения средство для разработки API, которым когда-то стали RoR для обычных сайтов.
Давайте уже к делу!
Действительно, хватит рассуждений. Встречайте — Grape
Это фреймворк, заточенный под разработку API, никаких швейцарских ножей.
Но надо отдать должное, он умеет делать API очень неплохо.
Попробую перечислить основные его достоинства:
- DSL, заточенный под описание API
- версионирование API из коробки
- параметризация методов со встроенной валидацией
- автоматическая генерация OPTIONS (кто встречался с CORS — оценит)
- прозрачная работа с форматами API
- встроенный DSL для документирования
вот далеко не полный перечень инструментов, которые облегчают жизнь разработчика API, когда он использует Grape.
Code time
Для начала приведу пример простого приложения, которое по адресу /hello/world.json вернет нам {hello: 'world'}
Gemfile
source 'https://rubygems.org'
gem 'grape', github: 'intridea/grape'
gem 'rack', '~> 1.5.2'
gem 'thin', '~> 1.6.2'
hello_world.rb
require 'grape'
class HelloWorld < Grape::API
format :json
namespace :hello do
get :world do
{hello: 'world'}
end
end
end
config.ru
require_relative 'hello_world'
run HelloWorld
На моем i5 c 16 Гб памяти и HDD это приложение стартует где-то за 400-700 мс. Вот список используемых гемов:
Using i18n 0.6.11
Using json 1.8.1
Using minitest 5.4.1
Using thread_safe 0.3.4
Using tzinfo 1.2.2
Using activesupport 4.1.6
Using descendants_tracker 0.0.4
Using ice_nine 0.11.0
Using axiom-types 0.1.1
Using builder 3.2.2
Using coercible 1.0.0
Using daemons 1.1.9
Using equalizer 0.0.9
Using eventmachine 1.0.3
Using hashie 3.3.1
Using multi_json 1.10.1
Using multi_xml 0.5.5
Using rack 1.5.2
Using rack-accept 0.4.5
Using rack-mount 0.8.3
Using virtus 1.0.3
Using grape 0.9.1 from git://github.com/intridea/grape.git (at master)
Using thin 1.6.2
Как вы могли заметить, в Grape есть чудесная штука, которая называется namespace. Она же group, resource, resources, segment — все для удобства чтения кода.
При этом она может использоваться без параметров. Казалось бы, зачем? А вот вам пример:
namespace :authorized do
before { authorize! }
get :some_secret_data ...
end
group do
before { authorize! }
get :some_secret_data ...
end
Это как в фильме — «все что случилось в Лас-Вегасе — остается в Лас-Вегасе».
Внутри групп, равно как нэймспейсов, вы можете определять before и after блоки, которые будут выполняться только для роутов, указанных в данных группах (и глубже).
Вот пример, демонстрирующий использование параметров:
params do
requires :first_name, type: String
requires :last_name, type: String
optional :birth_date, type: DateTime
end
post :register do
...
end
Как по мне, так понятно без слов. Управление в роут даже не попадет, если с запросом не будут переданы параметры, которые удовлетворяют описанным условиям. Самое чудесное, что это все с минимальными модификациями можно использовать для документирования API. Например:
desc 'User signup'
params do
requires :first_name, type: String, desc: 'First name'
requires :last_name, type: String, desc: 'Last name'
optional :birth_date, type: DateTime, desc: 'Date of birth'
end
post :register do
...
end
Убиваем сразу целую охапку зайцев — код документирован на месте, подключив grape-swagger получаем swagger-совместимую документацию. Изменили код — изменилась документация.
Одной из многих чудесных штук, которые меня покорили в Grape, является mount. Позволяет примонтировать ранее описанный API в новое место:
mount.rb
class Mount < Grape::API
get :mounted do
{mounted: true}
end
end
mount.rb
require 'grape'
require_relative 'mount'
class HelloWorld < Grape::API
format :json
namespace :hello do
mount Mount
get :world do
{hello: 'world'}
end
end
end
Как мы все уже поняли, наш роут из класса Mount станет доступен по адресу /hello/mounted.json
«Меня терзают смутные сомнения...»
Само собой, объема среднестатистической статьи, которая не вызовет у хабражителя стойкого зевотного рефлекса, вряд ли хватит, чтобы рассказать о всех плюсах и минусах фреймворка. Моей задачей в первую очередь было вызвать в вас интерес — документация у проекта неплохая, трудностей с дальнейшим изучением возникнуть не должно.
Также на гитхаб-страничке можно найти перечень гемов, которые можно использовать совместно с grape.
Эпилог
До недавнего времени у проекта была небольшая проблема, связанная с автоматической перезагрузкой измененного кода в dev-режиме. Все Rails-разработчики к этому привыкли и на мой взгляд это must have feature. В issues на гитхабе эта проблема была озвучена несколько раз и вроде предлагались какие-то решения на Rack::Reloader и для случаев использования совместно с Rails.
Я позволю себе упомянуть свое собственное решение, которое увидело свет буквально пару недель назад, а именно гем grape-reload, предназначенный для использования в plain-rack стеках.
Для grape версии 0.9.0 и ранее можно использовать версию гема 0.0.3, для более поздних и master-ветки фреймворка используйте master-ветку репозитория гема.
Если вам будут интересны дальнейшие статьи, посвященные данному фреймворку — не забудьте упомянуть об этом в комемнтариях. Всем ruby, посоны!
Автор: AMar4enko