Перевод (подробности здесь) статьи REST 101: Part 5 – Respond!, автором которой является Jeff Cohen.

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

С 1-ой по 4-ую статьи мы знакомились с основами концепции REST и к текущему моменту все точки расставлены. Осталось соединить их линиями, чтобы увидеть картину целиком. Это моя любимая часть, в том числе потому, что в ней рассмотрена реализация REST в Rails, являющаяся еще одним примером того, насколько прекрасен Ruby.

Коротко, но так… мило

Для того чтобы наше REST приложение заработало, нужно заставить контроллер правильно отвечать на запросы в зависимости от того, кто находится на другом конце провода и отправляет их. В качестве простого примера можно рассмотреть получение списка аэропортов. Если Вы воспользовались генератором scaffold_resource, то у Вас должен был получиться примерно такой код:

class AirportsController < ApplicationController def index @airports = Airport.find :all respond_to do |format| format.html # do nothing, allow Rails to render index.rhtml format.js # do nothing, allow Rails to render index.rjs format.xml { render :xml => @airports.to_xml } end end end

Первая строка метода понятна – получаем все аэропорты. Но остальной код выглядит несколько необычно. Все что он делает – это отображает список аэропортов в HTML, XML и даже с использованием AJAX, если это потребуется. Для того, чтобы понять, как это работает нужно познакомиться с respond_to.

HTTP клиенты могут добавить различную мета-информацию к своему запросу в виде HTTP заголовков. Заголовок – это просто необязательная пара ключ-значение. Существует несколько определенных стандартом заголовков, которые могут быть использованы. например заголовок “Accept-Type”. В качестве значения этого заголовка клиент может передать формат, в котором он способен прочитать ответ. В качестве значения может выступать любой из MIME types, но если значение этого заголовка не указано, то сервер считает что клиент способен адекватно воспринять HTML. Таким образом, если клиент посылает заголовок “Accept-Type: text/xml”, то предполагается что сервер вернет ответ в виде XML документа.

Именно заголовок Accept-Type вызывает магические действия внутри блока resond_to. Вот плохой пример того, как можно было бы реализовать поддержку различных форматов (предположим что Rails передает значение заголовка Accept-Type в наш метод):

class AirportsController < ApplicationController # Pretend that Rails will call our index action, # and will pass in the value of the Accept-Type header def index(client_format) @airports = Airport.find :all if client_format == "text/html" # TO DO: render the default template elsif client_format == "application/javascript" # TO DO: return some javascript elsif client_format == "application/xml" || client_format == "text/xml" # TO DO: return some XML back the client # ... more elsif statements here for each MIME type you want to support end end end

Но это некрасиво

Если закрыть глаза на уродство, то будет видно что сам по себе алгоритм очень прост – в зависимости от запрашиваемого формата отображаем список аэропортов тем или иным образом. Я легко могу себе представить, как команда разработчиков Rails стартовала с подобного кода (хотя бы в голове), но быстро решила просто добавить хэлпер respond_to, чтобы избежать безобразия:

respond_to do |format| format.html # do nothing, allow Rails to render index.rhtml format.js # do nothing, allow Rails to render index.rjs format.xml { render :xml => @airports.to_xml } end

Мы можем не знать, как устроен метод respond_to, но мы точно знаем, что он принимает Ruby блок. (Если Вы не знакомы с блоками в Ruby, попробуйте немного погуглить и возвращайтесь обратно). Внутри блока Вы получаете в свое распоряжение объект, который я назвал format и вызываете три метода этого объекта.

Идея состоит в том, что Rails не может догадаться, какие типы клиентов Вы хотите поддерживать, но может сделать 80% черной работы за Вас. Необходимо только указать типы клиентов, которые Вас интересуют, и отобразить ресурс в виде, понятном клиенту. Вместо того, чтобы говорить Вам какой формат ответа запрашивается, Rails просит Вас указать, какие форматы Вы готовы поддерживать. И для каждого формата (если захотите) можно указать блок кода, который непосредственно отобразит ресурс.

В приведенном выше примере мы говорим Rails, что для клиентов, запрашивающих HTML и Javascript можно выполнить действие по умолчанию – отобразить шаблон в соответствующем формате, но если клиент хочет получить XML, необходимо выполнить указанный нами блок кода.

Помните, как когда-то очень давно мы говорили о разнице между ресурсом и множеством различных его представлений? О том, что HTML – это на самом деле всего лишь одно из возможных представлений (Ваше приложение это не WEB страница и т.д.)? Теперь это видно даже в коде – HTML всего лишь один из вариантов.

Что дальше?

Понятно, что невозможно охватить все, что связано с REST в нескольких статьях. Именно поэтому серия и называется “ликбез”. Но мы поговорили о многом, в том числе и о том, как проектировать приложения согласно REST, о концепции ресурсов и о том, как это отличается от традиционного ООП подхода.

Думаете о том, что же делать дальше? Просто попробуйте! Создайте REST приложение с нуля, воспользуйтесь генератором scaffold_resource, изучите сгенерированный код, попробуйте подредактировать views и контроллеры. Это легче чем Вы думаете.

Вот некотрые источники, которые я могу порекомендовать для более подробного изучения (обратите внимание, PeepCode поддерживает блог автора)

Можете посоветовать что-то еще? Оставляйте ссылки в комментариях.

Leave a Reply