Главное Авторские колонки Вакансии Образование
Выбор редакции:
11 755 18 В избр. Сохранено
Авторизуйтесь
Вход с паролем

Так ли нужен REST для веб-приложений?

Многие из вас слышали о таком популярном понятии, как RESTful. Но думаю что не все знают что это такое и в чем преимущества этого подхода. Давайте попробуем разобраться на примере.
Мнение автора может не совпадать с мнением редакции

Что такое REST?

Термин REST был введен в 2000 году Роем Филдингом. Системы которые базируются на REST принято называть RESTful. Сам по себе REST это не какой-то стандарт, или применяемая технология, это архитектурный стиль. Он лишь дает вам методологию, а реализацию оставляет на ваше усмотрение.

REST предлагает брать в качестве уникального идентификатора для единицы ресурса (к примеру товар или пользователь) url адрес, а определять действие с этой единицей - по типу запроса.

b_54743484087a1.jpg

Обычное среднестатистическое веб-приложение обходится двумя типами запросов: GET и POST, для получения и соответственно отправки данных. Но RESTful архитектура подразумевает использовать весь спектр запросов: GET - получить данные, POST - отправить новые данные, PUT - отправить отредактированные данные, DELETE - удалить данные. Есть ещё PATCH, который по своей идеи повторяет PUT, различия лишь в том, что PUT предполагает заменить полностью запись, а PATCH только частично обновить данные. Что интересно, мнения об использовании POST и PUT расходятся. Англоязычные разработчики предпочитают использовать именно PUT для добавления новых данных, а POST для редактирования.

Использование REST на примере GML

Для начала нам нужно определиться с ресурсами, с которыми может взаимодействовать пользователь. На GML у меня получилось: линки (ссылки на веб-ресурсы), сборники (контейнеры для линков), пользователи и теги. Это четыре основных единицы, с которыми происходит работа.

Обозначим корневой домен как gml.link/

b_5474336525e23.jpg

У нас получаются следующие запросы на получение данных:

  • GET gml.link/links/ - получить весь список линков
  • GET gml.link/links/125 - получить сто двадцать пятый линк
  • GET gml.link/collections/ - получить список всех сборников
  • GET gml.link/collection/34 - получить список линков тридцать четвертого сборника
  • GET gml.link/tags/ - получить список всех тегов
  • GET gml.link/tags/animal - получить список линков с тегом 'animal' (для тегов в качестве идентификатора выступает его название, а не номер.)

Запросы на добавление данных (в круглых скобках указаны данные передаваемые в теле запроса)

  • POST gml.link/users/ (username: 'Alex', password: 'sdf7665$6', email: 'alex@mail.ru') - добавить нового пользователя
  • POST gml.link/users/23 (username: 'Alex', password: 'sdf7665$6', email: 'alex@mail.ru') - в данном случае вернется ошибка, так как мы указали в запросе идентификатор конкретного пользователя
  • POST gml.link/collections/ (title: 'Новая коллекция', 'type': 'private') - создаст новый приватный сборник

Запросы на редактирование

  • PUT gml.link/collections/ (title: 'Измененное название сборника') - вернет ошибку, так как не указан идентификатор сборника
  • PUT gml.link/collections/12 (title: 'Измененное название сборника') - изменит название у двенадцатого сборника
  • PUT gml.link/links/117 (title: 'Другое название линка') - изменит название у сто семнадцатого линка

Запросы на удаление

  • DELETE gml.link/collection/32 - удалит тридцать второй сборник
  • DELETE gml.link/links/43 - удалит сорок третий линк

Как мы видим запросы для пользователя получаются совершенно прозрачными, без тайных знаков и выражений. К примеру в предыдущей версии сервиса GML получение списка линков выглядело следующим образом: POST http://gml.link/action.php с кучей параметров в теле запроса типа action=get_links, start=0, finish=30 и так далее, причем в адресной строке был адрес http://gml.link/index.php?target=category&id=l4. В принципе адрес можно было и не менять, так как запрос происходит через Ajax, но он был нужен для сохранения состояния, чтоб при обновлении страницы (F5) не сбрасывалась открытая категория. И это было ужасно.

Подозреваю что многие уже задались вопросом, как же правильно передавать дополнительные параметры запроса для получения данных. REST архитектура не запрещает в GET запросах передавать дополнительные данные. Это даже необходимо в некоторых случаях. К примеру на сервисе GML реализована так называемая "ленивая загрузка" (lazy load), когда данные подгружаются по мере надобности (в моем случае при скролле страницы). Поэтому на запрос линков нужно передавать ещё и страницу (если быть точнее с какого линка и сколько выбрать), поэтому запрос на получение данных с дополнительными параметрами выглядит так: GET gml.link/links/?page=3. Так же дополнительные данные нам понадобятся для поиска: GET gml.link/links/?search=javascript

b_5474334ee7e70.jpg

Совсем немного о технической реализации

(внимание, прочитав данный параграф, ваша жизнь может навсегда измениться)

Так как мы не на хабрахабре, поэтому техническую реализацию я затрону условно.

Для многих, кто только начал знакомиться с архитектурой RESTful, возникает вопрос, кто обработает запрос вида GET gml.link/collections/45, ведь по старой школе запрос идет по пути public_html/collections/45/index.html (public_html - корень сайта). Но у нас нет такой структуры папок, и вообще только один index файл. На первый взгляд может показаться что это очередные проделки лукавого, но нет, во всем виноваты хитрые люди, которые придумали RewriteEngine (механизм преобразований, управляется сервером Apache, конфигурируется в файле .htaccess), чтоб дурить нашего брата. На самом же деле наш запрос идет по адресу gml.link/index.php?target=collection&id=45, просто RewriteEngine незаметно для пользователя подменяет все запросы и перенаправляет в нужное русло. Составив нужные нам правила для замены адресов, мы держим строку адреса в чистоте и здравом смысле. А в остальном (PUT, DELETE запросы) все по честному.

Так как приложение у нас одностраничное, и все запросы передаются посредством ajax, то для смены url адреса в адресной строке, нужно вручную запоминать состояние страницы через HTML5 History API, которое мы не будем рассматривать в этом посте.

Весь процесс обработки запроса делится на несколько этапов:

  1. Определение ресурса, к которому направлен запрос (links, collections, users и tags, и id ресурса)
  2. Определение действия из типа запроса (получение, добавление, редактирование и удаление)
  3. Сбор дополнительных параметров из запроса (для добавления\редактирования - это непосредственно данные ресурса, для получения - это разные фильтры)

В чем преимущества данного архитектурного подхода?

Применив REST на своем проекте, для себя я отметил следующее:

  1. Понятные url адреса для пользователя
  2. Сохранение состояния страницы через HTML5 History API (как бонус)
  3. Нет путаницы с дополнительной передачей параметров в запросах и обработкой их на сервере
  4. Прозрачная логика клиентской части приложения
  5. В случае надобности легко предоставить RESTful API для сторонних приложений

Что дальше? (в общем)

Как я уже говорил, статьи буду писать по мере реализации той или иной части сервиса. На данный момент уже готова регистрация/аутентификация, полностью поддержана REST архитектура, реализована "lazy load" подгрузка линков, добавление/создание сборника.

Вы можете предложить тему для следующей статьи в рамках сервиса GML. Если же предложений не будет, то следующая статья будет о сборниках, их типах, для чего они нужны и как реализовано добавление/создание сборника.

+8
В избр. Сохранено
Авторизуйтесь
Вход с паролем
Комментарии
ADZY
Ассистент для ведения рекламных компаний
Дмитрий Кубитский
мне вот интересно, когда же пхпистам надоест костылить и они все таки задумаются над сменой используемого стека технологий, начиная с языка программирования.
Ответить
GML
Сервис организации ваших интернет линков
GM2mars 10790
Я думаю тогда, когда php, mysql и стек используемых технологий будет проигрывать в производительности, удобстве и популярности.
Ну к примеру давайте возьмем другой серверный язык, на ваш выбор, что изменится?
Ответить
ADZY
Ассистент для ведения рекламных компаний
Дмитрий Кубитский
Будет???
Он никогда и не выигрывал!!1111
Что измениться? Ну для начала не будет такого головняка с роутингом.
Ответить
GML
Сервис организации ваших интернет линков
GM2mars 10790
Да, возможно php и уступит в скорости С языкам и Java. Но какой головняк с роутингом? Чем отличается RESTful, если у приложения сервер будет на java или на python? Совершенно ни чем, от того, что описано в статье.
Ответить
Макалей Цукерман
> Англоязычные разработчики предпочитают использовать именно PUT для добавления новых данных, а POST для редактирования.

А ну-ка пруфы сюда! В концепции черным по белому написано когда использовать POST, а когда PUT. После такого дальше статью оценивать не хочется.
Ответить
GML
Сервис организации ваших интернет линков
GM2mars 10790
В какой концепции, RESTful? Скиньте ссылку на официальную концепцию REST'a )
Вот википедия http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods
Про PUT сказано, что если по текущему пути есть объект, он его изменит, а если нету, то создаст новый.
Вот почитайте англоязычную статью, автор пишет что в некоторых случаях для обновления используется PUT, а в некоторых POST, так же и с созданием. http://jcalcote.wordpress.com/2008/10/16/put-or-post-the-rest-of-the-story/
Разница между PUT и POST в том, что PUT идемпотентен. Нигде не сказано что PUT только для обновления, а POST только для создания.
Ответить
InstaDreams
Instagram for your dreams
Филатов Александр
ом, холиварчик )) надеюсь все разбираются достаточно хорошо во всём, чтобы делать заявления про производительность, скорость разработки и прочие ништяки
Ответить
GML
Сервис организации ваших интернет линков
GM2mars 10790
Бесконечный спор, каждый кулик свое болото хвалит ))
Ответить
ubercrm
уберизация и локальные справочники
Саша Noxon
REST однозначно годная технология, прошу выложить следующую статью с премером на пхп буду благодарен)
Ответить
ubercrm
уберизация и локальные справочники
Саша Noxon
примером
Ответить
Сергей Бородаенко
Не годная, и вообще не технология, это даже не стандарт.
OData - технология и годная.
Ответить
ubercrm
уберизация и локальные справочники
Саша Noxon
ок почитаю
Ответить
ubercrm
уберизация и локальные справочники
Саша Noxon
хотел бы еще добавить, что rest это такая штука которая делает более эффективной работу нескольких кодеров на разных платформах, чтоб не было перетягивание логики "на свое поле", как это пытаются делать разработчики СУБД продвигая транзакции. У всех есть понимание атомарных операций и вся философия лишь в том, что положив утюг в шкаф он там будет лежать
Ответить
GML
Сервис организации ваших интернет линков
GM2mars 10790
Хорошо, в следующей статье я опишу логику работы бекэнда на реальном примере.
Ответить
Dmitry 12516
-- Понятные url адреса для пользователя
Речь же про API, когда это пользователи начали лезьть в потроха сервиса.

-- Сохранение состояния страницы через HTML5 History API (как бонус)
Опять же, очень косвенное отношение к REST API

-- Нет путаницы с дополнительной передачей параметров в запросах и обработкой их на сервере
Как раз и начинается путаница. Что передаем через GET параметры, что-то через POST в один и тот же обработчик.

-- Прозрачная логика клиентской части приложения
-- В случае надобности легко предоставить RESTful API для сторонних приложений
А другие протоколы не предоставляют этой возможности?

У REST есть много неопределенностей и из-за этого у каждого появляются свои реализации, которые они считают эталонными.

Нет более менее четкой спецификации. Например ответ о ошибке:
1. HTTP код
2. Всегда 200, информация об ошибке в ответе
3. 1 и 2 вариант

Формат ответа. Допустим вызываем метод получения пользователей:
1. [{ login: '' }]
2. { data: [{ login: '' }] }
3. { data: [ 'users': { login: '' }] }
Кто-как любит, так и делает. Большой минус если приходится интегрироваться с несколькими сервисами.

Веселье начинается, когда потребности выходят за рамки простого добавления, получения списка, удаления (типичный CRUD), т.е выходим за рамки /:collection/:id

Вот есть какая-либо сущьность, у который есть свойства и методы. Как эти действия выполнить?
1. POST /:collection/:id/on
2. Передавать "действие" в теле POST
3. Или вообще использовать, PUT, PATCH

Небольшая проблема возникает, когда идет кроссбраузерный запрос (CORS) к нашему API. На каждый url (/:collection/:id) будет слать предварительный OPTIONS запрос, дополнительные задержки.

Добавили GET/PATCH/DELETE обработчик /:collection/:id. И хотим в браузерном приложении использвать JSONP, чтобы избавиться от политик CORS. Придется добавлять еще один обработчик (3-в-1), для поддержки JSONP (он ведь только GET).

Нет стандратых инструментов для описания сервиса, по типу WSDL. Точнее более-менее широкоиспользуемых.

При типичном REST API, документация и параметры описываются вручную. Документация будет постоянно отставать.
Ответить
GML
Сервис организации ваших интернет линков
GM2mars 10790
Не пользуйтесь REST архитектурой )
Ответить
MpaK 12595
Странно в конце 2014-ом года видеть такие статьи, когда REST к примеру в Ruby on Rails без коробки и устаревшего mod_rewrite monkey patch'а Apache.

C PUT все просто, нужно иметь соглашение, что например POST это на создание (когда еще нет id объекта), а PUT это синоним PATCH на обновление (когда есть id уже), а обновлять все или одно поле разницы я думаю не имеет.
Ответить
GML
Сервис организации ваших интернет линков
GM2mars 10790
Да, REST уже совсем не новая архитектура, но стала пользоваться популярностью относительно недавно. Часто REST путают с простыми ЧПУ, где урлы имеют иерархических понятный вид, но запросы ограничиваются GET и POST на все действия.
Не все используют с своих проектах фреймворки.
Ответить
Выбрать файл
Блог проекта
Расскажите историю о создании или развитии проекта, поиске команды, проблемах и решениях
Написать
Личный блог
Продвигайте свои услуги или личный бренд через интересные кейсы и статьи
Написать

Spark использует cookie-файлы. С их помощью мы улучшаем работу нашего сайта и ваше взаимодействие с ним.