1. Обзор
В этом руководстве мы кратко рассмотрим два важных метода HTTP — PUT и POST — которые часто используются в архитектуре REST. Не секрет, что разработчики иногда пытаются выбрать между этими двумя методами при разработке веб-службы RESTful. Поэтому мы решим эту проблему с помощью простой реализации приложения RESTful в Spring Boot.
2. Дилемма PUT и POST
В типичной архитектуре REST клиент отправляет серверу запросы в виде методов HTTP для создания, извлечения, изменения или уничтожения ресурсов. Хотя и PUT, и POST могут использоваться для создания ресурсов, между ними есть существенные различия с точки зрения их предполагаемого применения.
В соответствии со стандартом RFC 2616 метод POST следует использовать для запроса на сервер принять вложенный объект в качестве подчиненного существующего ресурса, идентифицированного Request-URI. Это означает , что вызов метода POST создаст дочерний ресурс в наборе ресурсов.
С другой стороны, следует использовать метод PUT, чтобы запросить у сервера сохранение вложенного объекта под предоставленным Request-URI. Если Request-URI указывает на существующий ресурс на сервере, предоставленный объект будет считаться измененной версией существующего ресурса. Следовательно, вызов метода PUT либо создаст новый ресурс, либо обновит существующий .
Другое важное различие между методами заключается в том, что PUT является идемпотентным методом, а POST — нет . Например, многократный вызов метода PUT либо создаст, либо обновит один и тот же ресурс. Напротив, несколько запросов POST приведут к созданию одного и того же ресурса несколько раз.
3. Образец заявления
Чтобы продемонстрировать разницу между PUT и POST, мы собираемся создать простое веб-приложение RESTful с использованием Spring Boot . Приложение будет хранить имена и адреса людей.
3.1. Зависимости Maven
Для начала нам нужно включить зависимости для Spring Web, Spring Data JPA и базы данных H2 в памяти в наш файл pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
3.2. Интерфейс объекта домена и репозитория
Давайте начнем с создания объекта домена. Для адресной книги давайте определим класс Entity с именем
Address
, который мы будем использовать для хранения информации об адресах отдельных лиц. Для простоты мы будем использовать три поля — name
, city
и postalCode
— для нашей сущности Address
:
@Entity
public class Address {
private @Id @GeneratedValue Long id;
private String name;
private String city;
private String postalCode;
// constructors, getters, and setters
}
Следующим шагом является доступ к данным из базы данных. Для простоты мы будем использовать JpaRepository Spring Data JPA .
Это позволит нам выполнять функции CRUD для данных без написания дополнительного кода:
public interface AddressRepository extends JpaRepository<Address, Long> {
}
3.3. REST-контроллер
Наконец, нам нужно определить конечные точки API для нашего приложения. Мы создадим RestController
, который будет принимать HTTP-запросы от клиента и отправлять соответствующий ответ.
Здесь мы определим @ PostMapping
для создания новых адресов и их сохранения в базе данных и @PutMapping
для обновления содержимого адресной книги на основе URI запроса. Если URI не найден, он создаст новый адрес и сохранит его в базе данных:
@RestController
public class AddressController {
private final AddressRepository repository;
AddressController(AddressRepository repository) {
this.repository = repository;
}
@PostMapping("/addresses")
Address createNewAddress(@RequestBody Address newAddress) {
return repository.save(newAddress);
}
@PutMapping("/addresses/{id}")
Address replaceEmployee(@RequestBody Address newAddress, @PathVariable Long id) {
return repository.findById(id)
.map(address -> {
address.setCity(newAddress.getCity());
address.setPin(newAddress.getPostalCode());
return repository.save(address);
})
.orElseGet(() -> {
return repository.save(newAddress);
});
}
//additional methods omitted
}
3.4. cURL-запросы
Теперь мы можем протестировать наше разработанное приложение, используя cURL для отправки примеров HTTP-запросов на наш сервер.
Для создания нового адреса мы заключим данные в формате JSON и отправим их через POST-запрос:
curl -X POST --header 'Content-Type: application/json' \
-d '{ "name": "John Doe", "city": "Berlin", "postalCode": "10585" }' \
http://localhost:8080/addresses
Теперь давайте обновим содержимое созданного нами адреса. Мы отправим запрос PUT, используя идентификатор
этого адреса в URL-адресе. В этом примере мы обновим город
и раздел postalCode
адреса, который мы только что создали — предположим, что он был сохранен с id
= 1:
curl -X PUT --header 'Content-Type: application/json' \
-d '{ "name": "John Doe", "city": "Frankfurt", "postalCode": "60306" }' \
http://localhost:8080/addresses/1
4. Вывод
В этом руководстве мы узнали о концептуальных различиях между HTTP-методами PUT и POST. Кроме того, мы также узнали, как методы могут быть реализованы с использованием среды Spring Boot для разработки приложений RESTful.
В заключение, мы должны использовать метод POST для создания нового ресурса и метод PUT для обновления существующего ресурса. Как всегда, код для этого руководства доступен на GitHub .