Главная » Spring » Выполнение операций в стиле REST Spring

0

Как упоминалось выше, архитектура REST применяется для передачи информации о состоянии ресурса. Поэтому для описания операций над ресурсами достаточно лишь небольшого количества глаголов – глаголов, требующих передачи информации о состоянии ресурса. Наиболее типичными операциями над ресурсами являются создание, чтение, изменение и удаление ресурса.

Глаголы, интересующие нас в данном случае (послать (post), по-

лучить (get), вставить (put) и удалить (delete)), непосредственно соответствуют четырем методам протокола HTTP, перечисленным в табл. 12.11.

Таблица 12.1. Протокол HTTP поддерживает несколько методов управления ресурсами

Метод

Описание

Безопас- ный

Идемпо- тентный

GET

Извлекает ресурс с сервера. Ресурс иденти- фицируется адресом URL в запросе

Да

Да

POST

Посылает данные на сервер для обработки процессором, ожидающим поступления запросов по адресу URL в запросе

Нет

Нет

PUT

Помещает данные в ресурс на сервере, идентифицируемый адресом URL в запросе

Нет

Да

DELETE

Удаляет ресурс, идентифицируемый адресом URL в запросе

Нет

Да

OPTIONS

Запрашивает дополнительные параметры для взаимодействия с сервером

Да

Да

HEAD

Напоминает метод GET, за исключением того, что в ответ возвращаются только заголовки – содержимое не должно возвра- щаться в теле ответа

Да

Да

TRACE

В ответ на этот запрос сервер должен вернуть его тело обратно клиенту

Да

Да

1     Описание протокола HTTP определяет еще четыре метода: TRACE, OPTIONS, HEAD и CONNECT. Но мы сосредоточимся на четырех основных методах.

Каждый из HTTP-методов характеризуется двумя чертами: безопасность и идемпотентность. Метод считается безопасным, ес- ли он не изменяет состояние ресурса. Идемпотентный метод может изменять или не изменять состояние ресурса, но повторные запро- сы, следующие за первым, не должны оказывать влияния на со- стояние ресурса. По определению все безопасные методы являются также идемпотентными, но не все идемпотентные методы являются безопасными.

Важно отметить, что хотя фреймворк Spring поддерживает все методы протокола HTTP, это не освобождает разработчика от обя- занности следить, чтобы реализация методов контроллеров соответ- ствовала семантике HTTP-методов. Иными словами, метод, обраба- тывающий GET-запросы, должен только возвращать ресурс – он не должен изменять или удалять его.

Четыре первых HTTP-метода из перечисленных в табл. 12.1 часто отображаются в CRUD-операции (Create/Read/Update/Delete – соз- дать/прочитать/изменить/удалить). В частности, метод GET выпол- няет операцию чтения, а метод DELETE – операцию удаления. И даже при том, что методы PUT и POST могут использоваться для выполне- ния других операций, отличных от операций изменения и создания, обычно принято использовать их по прямому назначению.

Выше уже демонстрировался пример обработки GET-запросов. Ме- тод getSpittle() класса SpittleController снабжен аннотацией @Request- Mapping, в которой атрибуту method присвоено значение GET. Атрибут method определяет, какой HTTP-метод будет обрабатываться данным методом контроллера.

Изменение ресурса с помощью PUT-запросов

Что касается метода PUT, его семантика полностью противополож- на методу GET. В противоположность GET-запросу, требующему пере- дать информацию о состоянии ресурса клиенту, PUT-запрос передает информацию о состоянии ресурса на сервер.

Например, следующий метод putSpittle() предназначен для при- ема объекта Spittle в составе PUT-запроса:

@RequestMapping(value="/{id}", method=RequestMethod.PUT)

@ResponseStatus(HttpStatus.NO_CONTENT)

public void putSpittle(@PathVariable("id") long id,

@Valid  Spittle  spittle)  { spitterService.saveSpittle(spittle);

}

Метод putSpittle() отмечен аннотацией @RequestMapping как любой другой метод-обработчик. Фактически данная аннотация @Request- Mapping почти ничем не отличается от аннотации для метода getSpittle(). Единственное отличие заключается в том, что атрибуту method присвоено значение PUT.

Поскольку это единственное отличие, следовательно, метод put- Spittle() будет обрабатывать запросы с адресами URL вида /spittles/

{id}, аналогично методу getSpittle(). Напомню, что URL идентифи- цирует ресурс, а не операцию над ним. Поэтому URL, идентифици- рующий объект Spittle, будет тем же самым что для метода GET, что для метода PUT.

Кроме того, putSpittle() метод отмечен аннотацией, не встречав- шейся нам до сих пор. Аннотация @ResponseStatus определяет код состояния HTTP, который должен быть установлен в ответе, от- правляемом клиенту. В данном случае значение HttpStatus.NO_CONTENT указывает, что клиенту необходимо вернуть код состояния HTTP

204. Этот код означает, что запрос был успешно обработан, но тело ответа не содержит никакой дополнительной информации.

Обработка DELETE-запросов

Иногда бывает желательно не просто изменить ресурс, а вообще удалить его. В случае с приложением Spitter, например, можно дать клиентам возможность удалять сообщения, написанные в спешке, или когда пользователь находился в не совсем адекватном состоя- нии. Когда надобность в ресурсе отпадает, можно задействовать HTTP-метод DELETE.

Для демонстрации обработки DELETE-запросов в Spring MVC до- бавим в класс SpittleController новый метод-обработчик, который в ответ на DELETE-запросы будет удалять ресурсы Spittle:

@RequestMapping(value="/{id}",     method=RequestMethod.DELETE)

@ResponseStatus(HttpStatus.NO_CONTENT)

public void deleteSpittle(@PathVariable("id") long id) { spitterService.deleteSpittle(id);

}

И снова аннотация @RequestMapping оказалась очень похожей на аналогичные аннотации методов getSpittle() и putSpittle(). Она отличается только атрибутом method, который на этот раз получил значение DELETE. Шаблон URL, идентифицирующий ресурс, остался прежним.

Подобно методу putSpittle(), метод deleteSpittle() также отмечен аннотацией @ResponseStatus, чтобы известить клиента об успешной обработке запроса и об отсутствии дополнительной информации в теле ответа.

Создание ресурса с помощью POST-запроса

В каждой компании найдется свой человек, отличающийся сво- бодомыслием и несогласием с остальными. Среди HTTP-методов таким несогласием отличается метод POST. Он не подчиняется обще- принятым правилам. Он опасен и конечно же не идемпотентен. Этот HTTP-метод нарушает, кажется, все правила, но благодаря этому он выполняет работу, непосильную для других HTTP-методов.

Чтобы увидеть, как действует метод POST, посмотрим, как он вы- полняет работу, которую ему часто поручают, – создание нового ре- сурса. Метод createSpittle(), представленный в листинге 12.3, реа- лизует обработку POST-запросов и создает новые ресурсы Spittle.

Листинг 12.3. Создание новых сообщений методом POST

@RequestMapping(method=RequestMethod.POST)  // Обрабатывает POST-запросы

@ResponseStatus(HttpStatus.CREATED)                 // Возвращает  ответ  HTTP  201 public   @ResponseBody   Spittle   createSpittle(@Valid   Spittle   spittle,

BindingResult  result,  HttpServletResponse  response) throws BindException {

if(result.hasErrors())   {

throw    new    BindException(result);

}

spitterService.saveSpittle(spittle);

// Указать местоположение ресурса response.setHeader("Location", "/spittles/" + spittle.getId()); return spittle;                                       // Вернуть  ресурс

}

Первое, на что следует обратить внимание в этом методе, – ан- нотация @RequestMapping, отличающаяся от аналогичных аннотаций, встречавшихся до сих пор. В отличие от них, данная аннотация не имеет атрибута value. Это означает, что определение шаблона адре- сов URL, обрабатываемых методом createSpittle(), целиком и пол- ностью возлагается на аннотацию @RequestMapping на уровне класса.

Точнее, метод createSpittle() будет обрабатывать запросы, соответ- ствующие шаблону URL /spittles.

Обычно идентичность ресурса определяется сервером. Поскольку в данном случае создается новый ресурс, нет никакой возможности определить его идентификатор в URL. То есть запросы GET, PUT и DELETE воздействуют непосредственно на ресурс, идентифицируемый адресом URL, а запрос POST вынужден использовать URL, который не является ссылкой на создаваемый ресурс (нельзя определить адрес URL несуществующего ресурса).

И снова метод отмечен аннотацией @ResponseStatus, определяющей код состояния в ответе, отправляемом клиенту. На этот раз возвра- щается код состояния HTTP 201 (создано), свидетельствующий, что ресурс был успешно создан. При возврате кода состояния HTTP 201 вместе с ним необходимо вернуть клиенту и URL нового ресурса. Поэтому в конце метода createSpittle() определяется заголовок Location, содержащий URL ресурса.

Хотя это и не обязательно, но в теле ответа с кодом HTTP 201 можно вернуть полное представление ресурса. Поэтому, подобно методу getSpittle(), обрабатывающему GET-запросы, данный метод завершается, возвращая новый объект Spittle. Этот объект будет трансформирован в некоторое представление, которое сможет быть использовано клиентом.

Неясным пока остается сам процесс трансформации. Или как бу- дет выглядеть представление. Рассмотрим букву R в аббревиатуре REST: representation (представление).

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии