6.1.2 Отправка данных на сервер
Сейчас приложение может вернуть дюжину самых последних созданных тако. Но как эти тако были созданы изначально?
Вы еще не удалили ни один код из главы 2, поэтому у вас все еще есть оригинальный DesignTacoController, который отображает форму дизайна Taco и обрабатывает отправку формы. Это отличный способ получить некоторые тестовые данные для тестирования созданного вами API. Но если вы собираетесь преобразовать Taco Cloud в одностраничное приложение, вам нужно будет создать компоненты Angular и соответствующие endpoint-ы, чтобы заменить форму дизайна Taco из главы 2.
Я уже переработал клиентский код для формы дизайна taco, создав новый Angular компонент с именем DesignComponent (в файле с именем design.component.ts). Поскольку в нем должен присутствовать функционал отправки данных формы, DesignComponent имеет метод onSubmit (), который выглядит следующим образом:
onSubmit() {
this.httpClient.post(
'http://localhost:8080/design',
this.model, {
headers: new HttpHeaders().set('Content-type', 'application/json'),
}).subscribe(taco => this.cart.addToCart(taco));
this.router.navigate(['/cart']);
}
В методе onSubmit() вместо get() вызывается метод post(). Это означает, что вместо извлечения данных из API, вы отправляете данные в API. В частности, вы отправляете дизайн тако, который хранится в переменной model, в API endpoint /design с request-ом HTTP POST.
Это означает, что вам нужно будет написать метод в DesignTacoController для обработки этого запроса и сохранения дизайна. Добавив следующий метод postTaco() в DesignTacoController, вы реализуете функционал в контроллере для этой цели:
@PostMapping(consumes="application/json")
@ResponseStatus(HttpStatus.CREATED)
public Taco postTaco(@RequestBody Taco taco) {
return tacoRepo.save(taco);
}
Поскольку postTaco() будет обрабатывать HTTP POST request , он аннотируется @PostMapping вместо @GetMapping. Вы не указываете здесь атрибут path, поэтому метод postTaco() будет обрабатывать запросы для /design, как указано в классе @RequestMapping у DesignTacoController.
Вы устанавливаете атрибут consumes. Здесь вы используете consumes, чтобы сказать, что метод будет обрабатывать только запросы, Content-type которых соответствует application/json.
Параметр Taco для метода помечается @RequestBody, чтобы указать, что тело запроса должно быть преобразовано в объект Taco и привязано к параметру. Эта аннотация важна, без нее Spring MVC предполагает, что вы хотите, чтобы параметры запроса (либо параметры запроса, либо параметры формы) были связаны с объектом Taco. Но аннотация @RequestBody гарантирует, что вместо этого JSON в теле запроса будет связан с объектом Taco.
Как только postTaco() получает объект Taco, он передает его методу save() в TacoRepository.
Возможно, вы также заметили, что я аннотировал метод postTaco() с помощью @ResponseStatus (HttpStatus.CREATED). При нормальных обстоятельствах (когда не генерируются исключения) все ответы будут иметь код состояния HTTP 200 (ОК), что указывает на успешность запроса. Хотя ответ HTTP 200 всегда приветствуется, он не всегда достаточно описательный. В случае запроса POST HTTP-статус 201 (CREATED) является более информативным. Он сообщает клиенту, что запрос был не только успешным, но в результате был создан ресурс. Всегда целесообразно использовать @ResponseStatus, где это уместно, для передачи клиенту наиболее описательного и точного кода состояния HTTP.
Хотя вы использовали @PostMapping для создания нового ресурса Taco, POST-запросы также можно использовать для обновления ресурсов. Тем не менее, запросы POST обычно используются для создания ресурсов, а запросы PUT и PATCH используются для обновления ресурсов. Давайте посмотрим, как вы можете обновить данные, используя @PutMapping и @PatchMapping.
6.1.3 Обновление данных на сервере
Прежде чем написать какой-либо код контроллера для обработки команд HTTP PUT или PATCH, вам следует уделить время рассмотрению слона в комнате: почему существуют два разных метода HTTP для обновления ресурсов?
Хотя это правда, что PUT часто используется для обновления данных ресурсов, на самом деле это семантическая противоположность GET. В то время как запросы GET предназначены для передачи данных с сервера на клиент, запросы PUT предназначены для отправки данных с клиента на сервер.
В этом смысле PUT действительно предназначен для выполнения операции оптовой замены, а не операции обновления. Напротив, целью HTTP PATCH является выполнение исправления или частичное обновление данных ресурса.
Например, предположим, что вы хотите изменить адрес заказа. Один из способов добиться этого с помощью REST API - обработать запрос PUT следующим образом:
@PutMapping("/{orderId}")
public Order putOrder(@RequestBody Order order) {
return repo.save(order);
}
Это может сработать, но для этого потребуется, чтобы клиент передал полные данные заказа в запросе PUT. Семантически PUT означает «передать эти данные по этому URL», по сути, заменяя любые данные, которые уже есть. Если какое-либо из свойств заказа будет опущено, значение этого свойства будет заменено на ноль. Даже тако в заказе необходимо будет передать вместе с данными заказа, иначе они будут удалены из заказа.