В этом руководстве вы узнаете
Обычно, когда говорят, что Rails используется как "API", имеется в виду предоставление программно доступного API вместе с веб-приложением. Например, GitHub предоставляет API, который можно использовать в собственном клиенте.
С приходом клиентских фреймворков многие разработчики используют Rails для создания бэкенда, общего для их веб-приложений и других нативных приложений.
Например, Twitter использует свой публичный API в своем веб-приложении, который создан как статичный сайт, потребляющий ресурсы JSON.
Вместо использования Rails для генерации HTML, взаимодействующего с сервером с помощью форм и ссылок, многие разработчики трактуют их веб-приложения как всего лишь клиент API, созданный из HTML с помощью JavaScript, обращающегося к JSON API.
Это руководство раскрывает создание приложения Rails, отдающего JSON-ресурсы клиентам API, включая клиентский фреймворк.
Первый вопрос, который многие задают, когда думают о создании JSON API с помощью Rails, это: "Не будет ли использование Rails для отдачи некоторого JSON избыточным? Не должен ли я использовать что-то вроде Sinatra?".
Для очень простых API это может быть истиной. Однако, даже в самых навороченных HTML приложениях, большинство логики приложения находится вне уровня представления.
Причиной, по которой многие используют Rails, является то, что он предоставляет набор, позволяющий разработчикам взять и начать работать без осуществления множества тривиальных решений.
Давайте посмотрим на некоторые вещи, которые Rails предоставляет из коробки и которые применимы к API-приложениям.
На уровне промежуточных программ:
params
. Хотите использовать вложенные URL-кодированные параметры? Это тоже работает.
GET
(ETag
и Last-Modified
), обрабатывая заголовки запроса и возвращая правильный отклик и код статуса. Все, что нужно, это использовать проверку stale?
в вашем контроллере, и Rails позаботится обо всех деталях HTTP.
HEAD
в GET
, и возвращает только заголовки тем же образом. Это позволяет HEAD
надежно работать во всех API Rails.
Очевидно, что хотя вы и можете это создать сами в терминах существующих промежуточных программ Rack, этот список демонстрирует стек промежуточных программ Rails по умолчанию, представляющий большую ценность, даже если вы "просто генерируете JSON".
На уровне Action Pack:
head :no_content
и redirect_to user_url(current_user)
очень удобны. Конечно, заголовки отклика можно добавить руками, но зачем?
Конечно, процесс загрузки Rails также соединяет воедино все зарегистрированные компоненты. Например, процесс загрузки Rails это то, что использует файл config/database.yml
при конфигурации Active Record.
Краткая версия: можно не задумываться, какие части Rails все еще применимы, даже если вы уберете уровень представления, ответом будет - большая часть из них.
Если вы создаете приложение Rails, которое будет в первую очередь сервером API, можно начать с более ограниченного подмножества Rails и добавлять особенности по необходимости.
Можно сгенерировать новое приложение api Rails:
$ rails new my_api --api
Это сделает три основных вещи:
ApplicationController
от ActionController::API
вместо ActionController::Base
. Как и в случае с промежуточными программами, это выкинет все модули Action Controller, предоставляющие функциональность, в основном используемую браузерными приложениями.
Если хотите взять существующее приложение и сделать его API-приложением, следуйте этим шагам.
В config/application.rb
добавьте следующую строчку в самый верх определения класса Application
:
config.api_only = true
В config/environments/development.rb
установите config.debug_exception_response_format
, чтобы настроить формат, используемый в откликах, когда происходит ошибка в режиме development.
Чтобы отрендерить страницу HTML с отладочной информацией, используйте значение :default
.
config.debug_exception_response_format = :default
Чтобы отрендерить отладочную информацию, сохранив формат отклика, используйте значение :api
.
config.debug_exception_response_format = :api
По умолчанию config.debug_exception_response_format
установлен :api
, когда config.api_only
установлен true.
Наконец, в app/controllers/application_controller.rb
вместо:
class ApplicationController < ActionController::Base
end
сделайте:
class ApplicationController < ActionController::API
end
API-приложение поставляется со следующими промежуточными программами по умолчанию:
ActionDispatch::HostAuthorization
Rack::Sendfile
ActionDispatch::Static
ActionDispatch::Executor
ActionDispatch::ServerTiming
ActiveSupport::Cache::Strategy::LocalCache::Middleware
Rack::Runtime
ActionDispatch::RequestId
ActionDispatch::RemoteIp
Rails::Rack::Logger
ActionDispatch::ShowExceptions
ActionDispatch::DebugExceptions
ActionDispatch::ActionableExceptions
ActionDispatch::Reloader
ActionDispatch::Callbacks
ActiveRecord::Migration::CheckPending
Rack::Head
Rack::ConditionalGet
Rack::ETag
Смотрите раздел по внутренним промежуточным программам руководства по Rack, чтобы узнать подробности о них.
Другие плагины, включая Active Record, могут добавлять дополнительные промежуточные программы. В основном, эти промежуточные программы безразличны к типу создаваемого приложения, и имеют смысл в API-приложении Rails.
Можно получить список всех промежуточных программ вашего приложения с помощью:
$ bin/rails middleware
По умолчанию Rails добавит промежуточную программу, предоставляющую хранилище кэша, основанного на конфигурации вашего приложения (по умолчанию memcache). Это означает, что встроенный кэш HTTP будет полагаться на нее.
Например, используя метод stale?
:
def show
@post = Post.find(params[:id])
if stale?(last_modified: @post.updated_at)
render json: @post
end
end
Вызов stale?
сравнит заголовок If-Modified-Since
в запросе с @post.updated_at
. Если заголовок новее, чем время последнего модифицирования, этот экшн вернет отклик "304 Not Modified". В противном случае, он отрендерит отклик и включит в него заголовок Last-Modified
.
Обычно этот механизм используется отдельно для каждого клиента. Кэширующая промежуточная программа позволяет распределять этот кэширующий механизм между клиентами. Можно включить межклиентское кэширование в вызове stale?
:
def show
@post = Post.find(params[:id])
if stale?(last_modified: @post.updated_at, public: true)
render json: @post
end
end
Это означает, что кэширующая промежуточная программа сохранит значение Last-Modified
для URL в кэше Rails, и добавит заголовок If-Modified-Since
в любой последующий входящий запрос к этому URL.
Воспринимайте это как кэширование страниц в семантике HTTP.
При использовании метода send_file
в контроллере Rails, он устанавливает заголовок X-Sendfile
. Rack::Sendfile
ответственен за фактическую отсылку файла.
Если ваш фронтенд сервер поддерживает ускоренную отсылку файла, Rack::Sendfile
переложит работу по фактической отсылке файла на фронтенд сервер.
Можно настроить имя заголовка, которое использует ваш фронтенд сервер для этой цели, с помощью config.action_dispatch.x_sendfile_header
в соответствующем среде конфигурационном файле.
Подробнее узнать о том, как использовать Rack::Sendfile
с популярными фронтендами можно в документации Rack::Sendfile.
Вот несколько значений этого заголовка для некоторых популярных серверов, которые, как только эти серверы будут настроены, добавят поддержку для ускоренной отсылки файла:
# Apache и lighttpd
config.action_dispatch.x_sendfile_header = "X-Sendfile"
# Nginx
config.action_dispatch.x_sendfile_header = "X-Accel-Redirect"
Убедитесь, что сконфигурировали на своем сервере поддержку этих опций в соответствии с инструкциями в документации Rack::Sendfile
.
ActionDispatch::Request#params
примет параметры от клиента в формате JSON и сделает их доступными в контроллере внутри params
.
Для его использования клиенту нужно сделать запрос с кодированными в JSON параметрами и указать Content-Type
как application/json
.
Вот пример на jQuery:
jQuery.ajax({
type: 'POST',
url: '/people',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({ person: { firstName: "Yehuda", lastName: "Katz" } }),
success: function(json) { }
});
ActionDispatch::Request
увидит Content-Type
и вашими параметрами будут:
{ :person => { :firstName => "Yehuda", :lastName => "Katz" } }
Следующие промежуточные программы, используемые для управления сессией, исключены из приложений API, так как им обычно не нужны сессии. Если один из ваших клиентов API это браузер, возможно, вы захотите вернуть одну из:
ActionDispatch::Session::CacheStore
ActionDispatch::Session::CookieStore
ActionDispatch::Session::MemCacheStore
Трудность в их возврате в том, что по умолчанию при добавлении они передают session_options
(включая ключ сессии), поэтому нельзя просто добавить инициализатор session_store.rb
, добавить use ActionDispatch::Session::CookieStore
и получить функционирующие сессии. (Проясним: сессии может и будут работать, но опции сессии будут игнорироваться - т.е. будет ключ сессии по умолчанию _session_id
)
Вместо этого инициализатора нужно установить нужные опции где-то до создания стека промежуточных программ (наподобие config/application.rb
) и передать их в предпочитаемую промежуточную программу, наподобие:
# Это также сконфигурирует session_options для использования ниже
config.session_store :cookie_store, key: '_interslice_session'
# Требуется для всех управлений сессиями (независимо от session_store)
config.middleware.use ActionDispatch::Cookies
config.middleware.use config.session_store, config.session_options
Rails поставляется с рядом других промежуточных программ, которые вы, возможно, захотите использовать в API-приложении, особенно если одним из клиентов вашего API является браузер:
Rack::MethodOverride
ActionDispatch::Cookies
ActionDispatch::Flash
Любые из этих промежуточных программ могут быть добавлены с помощью:
config.middleware.use Rack::MethodOverride
Если вы не хотите использовать промежуточную программу, которая включена по умолчанию в набор промежуточных программ для API, ее можно убрать с помощью:
config.middleware.delete ::Rack::Sendfile
Учтите, что удаление этих промежуточных программ удалит поддержку для определенных особенностей в Action Controller.
API-приложение (использующее ActionController::API
) по умолчанию поставляется со следующими модулями:
ActionController::UrlFor
: Делает доступными url_for
и подобные хелперы.
ActionController::Redirecting
: Поддержка для redirect_to
.
AbstractController::Rendering
и ActionController::ApiRendering
: Базовая поддержка для рендеринга.
ActionController::Renderers::All
: Поддержка для render :json
и сотоварищей.
ActionController::ConditionalGet
: Поддержка для stale?
.
ActionController::BasicImplicitRender
: Убеждается, что возвращен пустой отклик, если нет явного.
ActionController::StrongParameters
: Поддержка для фильтрации параметров в сочетании с массовым назначением Active Model.
ActionController::DataStreaming
: Поддержка для send_file
и send_data
.
AbstractController::Callbacks
: Поддержка для before_action
и подобных хелперов.
ActionController::Rescue
: Поддержка для rescue_from
.
ActionController::Instrumentation
: Поддержка для инструментальных хуков, определенных Action Controller (подробности относительно этого смотрите в руководстве Инструментарий Active Support).
ActionController::ParamsWrapper
: Оборачивает хэш параметров во вложенный хэш, таким образом, к примеру, не нужно указывать корневые элементы при посылка запросов POST.
ActionController::Head
: Поддержка возврата отклика без тела сообщения, только заголовки.
Другие плагины могут добавлять дополнительные модули. Список всех модулей, включенных в ActionController::API
можно получить в консоли rails:
irb> ActionController::API.ancestors - ActionController::Metal.ancestors
=> [ActionController::API,
ActiveRecord::Railties::ControllerRuntime,
ActionDispatch::Routing::RouteSet::MountedHelpers,
ActionController::ParamsWrapper,
... ,
AbstractController::Rendering,
ActionView::ViewPaths]
Все модули Action Controller знают о зависимых модулях, поэтому можно свободно включать любые модули в контроллеры, и будут включены и настроены все зависимости.
Некоторые распространенные модули, которые вы, возможно, захотите добавить:
AbstractController::Translation
: Поддержка для методов локализации l
и перевода t
.
ActionController::HttpAuthentication::Basic::ControllerMethods
ActionController::HttpAuthentication::Digest::ControllerMethods
ActionController::HttpAuthentication::Token::ControllerMethods
ActionView::Layouts
: Поддержка для макетов при рендеринге.
ActionController::MimeResponds
: Поддержка для respond_to
.
ActionController::Cookies
: Поддержка для cookies
, что включает поддержку для подписанных и зашифрованных куки. Он требует промежуточную программу для куки.
ActionController::Caching
: Поддержка кэширования вью для контроллера API. Отметьте, что нужно вручную указать хранилище кэша внутри контроллера подобно следующему:
class ApplicationController < ActionController::API
include ::ActionController::Caching
self.cache_store = :mem_cache_store
end
Rails не передает эту конфигурацию автоматически.
Лучшим местом для добавления модулей является ApplicationController
, но вы также можете добавить модули в отдельные контроллеры.