← Назад к вопросам

Какой REST метод используешь для удаления сущности в CRUD-приложении?

1.3 Junior🔥 271 комментариев
#REST API и микросервисы#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

REST методы для удаления сущности

Краткий ответ

Для удаления сущности в CRUD-приложении используется HTTP метод DELETE. Стандартный формат: DELETE /api/v1/resources/{id}

Стандартный DELETE запрос

Вот классический пример CRUD операции удаления:

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteById(id);
        return ResponseEntity.noContent().build(); // 204 No Content
    }
}

Компоненты DELETE запроса:

  1. HTTP метод: DELETE
  2. URL: /api/v1/resources/{id}
  3. Status код: 204 No Content (успешно удалено)
  4. Body: обычно пуст (нет данных для отправки)

Статус коды для DELETE

КодЗначениеПрименение
204 No ContentУспешно удалено, нет тела ответаСтандартный случай
200 OKУспешно, возвращаем информациюКогда нужно вернуть удалённую сущность
202 AcceptedЗапрос принят, удаление асинхронноеДолгие операции
404 Not FoundРесурс не найденПытались удалить несуществующий ID
403 ForbiddenДоступ запрещенНет прав на удаление

Полный пример с обработкой ошибок

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    private final UserService userService;
    
    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteUser(@PathVariable Long id) {
        try {
            // Проверяем существование
            User user = userService.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException(
                    "User not found with id: " + id));
            
            // Проверяем права доступа
            if (!userService.canDelete(getCurrentUser(), user)) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(new ErrorResponse("No permission to delete"));
            }
            
            // Удаляем сущность
            userService.deleteById(id);
            
            // Возвращаем 204 No Content
            return ResponseEntity.noContent().build();
            
        } catch (ResourceNotFoundException e) {
            return ResponseEntity.notFound().build(); // 404
        }
    }
}

Альтернативные подходы

1. Мягкое удаление (Soft Delete)

Вместо полного удаления из БД помечаем запись как удалённую:

@Entity
@Table(name = "users")
public class User {
    @Id
    private Long id;
    
    private String name;
    
    @Column(name = "deleted_at")
    private LocalDateTime deletedAt; // null = не удалён
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    // Вместо удаления, устанавливаем deletedAt = now()
    userService.softDelete(id);
    return ResponseEntity.noContent().build();
}

Плюсы:

  • Можно восстановить данные
  • Сохраняется история
  • Внешние ключи не ломаются

Минусы:

  • Усложняет запросы (везде WHERE deleted_at IS NULL)
  • Занимает больше места в БД

2. Каскадное удаление

Удаление связанных сущностей:

@Entity
public class User {
    @OneToMany(mappedBy = "user", cascade = CascadeType.DELETE)
    private List<Post> posts; // Удалятся автоматически
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    // При удалении User удалятся и все его Posts
    userService.deleteById(id);
    return ResponseEntity.noContent().build();
}

Пакетное удаление

Если нужно удалить несколько сущностей:

@PostMapping("/batch-delete")
public ResponseEntity<Void> batchDelete(@RequestBody List<Long> ids) {
    userService.deleteByIds(ids);
    return ResponseEntity.noContent().build();
}

// Service
public void deleteByIds(List<Long> ids) {
    userRepository.deleteAllByIdInBatch(ids);
}

REST vs GraphQL

В GraphQL удаление выглядит по-другому:

mutation {
  deleteUser(id: "123") {
    success
    message
  }
}

Но это всё равно использует DELETE операцию на уровне логики.

Лучшие практики для DELETE

  1. Используй правильный HTTP статус:

    • 204 No Content — стандарт для DELETE
    • 200 OK — если возвращаешь данные удалённой сущности
  2. Проверяй права доступа:

    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN') or @securityService.isOwner(#id, principal)")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) { ... }
    
  3. Используй транзакции:

    @Transactional
    public void deleteUser(Long id) {
        // Откатится всё, если произойдёт ошибка
    }
    
  4. Логируй удаления:

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        logger.info("User deleted: {} by {}", id, getCurrentUser());
        userService.deleteById(id);
        return ResponseEntity.noContent().build();
    }
    
  5. Рассмотри асинхронное удаление для больших объёмов:

    @DeleteMapping("/batch")
    public ResponseEntity<Void> batchDeleteAsync(@RequestBody List<Long> ids) {
        asyncService.scheduleDelete(ids); // Асинхронно
        return ResponseEntity.accepted().build(); // 202 Accepted
    }
    

Выводы

  • DELETE — правильный HTTP метод для удаления
  • 204 No Content — стандартный ответ
  • Рассмотри мягкое удаление для критичных данных
  • Всегда проверяй права доступа перед удалением
  • Используй транзакции для целостности данных