LINUX.ORG.RU

Как правильно написать PATCH запрос?

 , ,


1

1

Приветствую всех. Как правильно написать PATCH запрос для REST контроллера в Spring Boot?

Под правильным запросом я понимаю следующее. Например, есть объект, у объекта есть поля: его id, некоторое число, строка и массив значений.

От клиента приходит запрос, в теле которого указано только новое значение для строки, остальные поля — null. Нужно обновить только строку, значение числа оставить без изменения, а массив, если он пропущен, можно затереть.

Помогите написать PATCH запрос, а то во 99% туториалах разбирают только POST и GET.


а то во 99% туториалах разбирают только POST и GET.

а какая разница?

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

Не понел в чем проблема.

takino ★★★★★ ()
Ответ на: комментарий от takino

Проблема в отсутствии примера кода, что для человека, который пишет это в первый раз есть серьезное препятствие.

pol01 ()
Ответ на: комментарий от pol01
 @PatchMapping(value = "/stuff/{id}",
            produces = {APPLICATION_JSON_VALUE},
            consumes = {APPLICATION_JSON_VALUE})
    public ResponseEntity<StuffResponse> patchStuff(@PathVariable("id") long id, @RequestBody StuffBody stuffBody) {
        StuffDto dto = doStuff(stuffBody);
        saveStuffToDatabase(dto);

}


рили, разницы жеж никакой, какой тип запроса. Или я чего-то не понимаю?

takino ★★★★★ ()
Последнее исправление: takino (всего исправлений: 3)
Ответ на: комментарий от takino

А можно полный пример кода? (Я изучаю туториал, в котором с базой на прямую работают. Я подсознательно понимаю, что это не правильно, поэтому хочу сразу на правильном примере посмотреть)

pol01 ()
Ответ на: комментарий от pol01

Полный пример кода зависит от архитектуры приложения, то, о чем ты спросил, полностью опримерено (патч-запрос). Не уверен, что именно ты хочешь увидеть в дальнейшем примере.

p.s. работа с базой через hibernate или mybatis, контроллер отдельно, сервис отдельно, конвертор между жсон-объектом и дто через selma

takino ★★★★★ ()
Последнее исправление: takino (всего исправлений: 1)
Ответ на: комментарий от takino

Вот для этого как будет выглядеть DTO и webUserDTO.update(WebUser user)?

@Entity
public class WebsiteUser {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
 
    private String name;
    private int age;
    private List<Address>;
 
    // standard getters and setters
}

.

pol01 ()
Ответ на: комментарий от deadNightTiger

DTO и update(), которые потом в контроллере использовать буду.

pol01 ()
Ответ на: комментарий от takino

Вот за ссылку на selma спасибо. Сейчас сижу изучаю.

pol01 ()
Ответ на: комментарий от pol01

почему апдейт будет в дто? дто это объект трансфера данных, с базой данных оно работать не будет и знать о том, что кроме дто существует еще какое-то представление этих данных, ему не нужно. тебе нужен jpa repository и сервис, который будет с ним работать. как ты напишешь логику сервиса вопрос к тебе.

takino ★★★★★ ()
Ответ на: комментарий от takino

Вот смотри. У меня есть Entity, Controller, Service и Repository.

Репозитарий связан с сервисом, сервис связан с контроллером. PATCH запрос приходит в контроллер, где вызывается соотв. метод.

Вот твой пример (в контроллере):

 @PatchMapping(value = "/stuff/{id}",
            produces = {APPLICATION_JSON_VALUE},
            consumes = {APPLICATION_JSON_VALUE})
    public ResponseEntity<StuffResponse> patchStuff(@PathVariable("id") long id, @RequestBody StuffBody stuffBody) {
        StuffDto dto = doStuff(stuffBody);
        saveStuffToDatabase(dto);
}
StuffBody — это Entity, он определяется параметрами реквеста как я понял.

DTO — это еще одни класс, c полями как у Entity?

Метод doStuff это метод какого класса?

pol01 ()
Ответ на: комментарий от pol01

doStuff это обработка твоей логики, которая переделает вебэнтиту в дто. Логично это делать через сельму.

Дто это класс с которым будет работать репозитарий/сервис.

СтаффБоди писать тоже будешь ты (ну или оно будет автогенеренное помощи openapi, не суть)

Разделение вебэнтиты и дто в принципе не обязательно, но я их обычно держу в разных модулях (ну и читаемость повышается, плюс возникает возможность отсылать не полный набор данных, получаемых из дб).

takino ★★★★★ ()
Последнее исправление: takino (всего исправлений: 1)

Я поначалу подумал, что у топикстартера вопрос о том, как более-менее универсально пропатчить только одно, заранее неопределённое, поле у объекта. Задача, как оказалось, в java нетривиальная. Тут можно либо принимать Map<Object,Object> как тело запроса, либо JsonNode, и дальше вытаскивать только присланные поля и как-то сопоставлять их полям объекта. Я в своё время реализовывал это так:

@Component
public class EntityPatcher {
    private final ObjectMapper mapper;

    @Autowired
    public EntityPatcher(ObjectMapper mapper) {
        this.mapper = mapper.copy();
        this.mapper.disable(MapperFeature.USE_ANNOTATIONS);
    }

    @SneakyThrows
    @SuppressWarnings("unchecked") 
    public <T> T patch(T originalObject, JsonNode updatedFields) {
        JsonNode original = mapper.valueToTree(originalObject);
        T result = mapper.treeToValue(patchNode(original, updatedFields), (Class<T>) originalObject.getClass());
        return result;
    }

    @SneakyThrows
    private JsonNode patchNode(JsonNode originalNode, JsonNode updatedFields) {
        JsonMergePatch patchJson = JsonMergePatch.fromJson(updatedFields);
        return patchJson.apply(originalNode);
    }
}
В завимостях потребуется com.github.fge:json-patch. Для использования просто берём @RequestBody JsonNode updatedFields, в самом методе вытаскиваем оригинальный объект и скармливаем в patch. Ещё остаётся не решённым вопрос о том, как установить значение null для какого-то поля.

Nirvandil ()
Ответ на: комментарий от pol01

Это из Lombok'a, помогает бороться с checked исключениями. По сути заворачивает метод в try-catch и пробрасывает исключения в виде unchecked.

Nirvandil ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.