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

Какие использовали методы в @RestController

1.6 Junior🔥 251 комментариев
#REST API и микросервисы#Spring Framework

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

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

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

HTTP методы в @RestController

@RestController в Spring Framework позволяет создавать REST API с использованием различных HTTP методов. Каждый метод имеет свою семантику и применяется в определённых сценариях.

REST контроллер

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    // HTTP методы будут рассмотрены ниже
}

1. GET - Получение ресурсов

GET — безопасный и идемпотентный метод для получения данных БЕЗ изменения состояния сервера.

// Получение всех пользователей
@GetMapping
public ResponseEntity<List<UserDTO>> getAllUsers(
    @RequestParam(defaultValue = "0") int page,
    @RequestParam(defaultValue = "10") int size) {
    return ResponseEntity.ok(userService.getUsers(page, size));
}

// Получение по ID
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
    return userService.findById(id)
        .map(ResponseEntity::ok)
        .orElse(ResponseEntity.notFound().build());
}

// С query параметрами
@GetMapping("/search")
public ResponseEntity<List<UserDTO>> searchUsers(
    @RequestParam String email,
    @RequestParam(required = false) String name) {
    return ResponseEntity.ok(userService.search(email, name));
}

// Несколько path параметров
@GetMapping("/organizations/{orgId}/users/{userId}")
public ResponseEntity<UserDTO> getUserFromOrganization(
    @PathVariable Long orgId,
    @PathVariable Long userId) {
    return ResponseEntity.ok(userService.getByIdInOrg(orgId, userId));
}

Характеристики GET:

  • Безопасен: не изменяет состояние
  • Идемпотентен: несколько запросов = один запрос
  • Кешируется: браузеры и прокси кешируют GET запросы
  • HTTP коды: 200 OK, 404 Not Found, 400 Bad Request
  • Нет body: параметры в URL

2. POST - Создание ресурсов

POST — создаёт новый ресурс на сервере. НЕ идемпотентен (каждый запрос создаёт новый ресурс).

// Создание пользователя
@PostMapping
public ResponseEntity<UserDTO> createUser(@RequestBody CreateUserRequest request) {
    UserDTO user = userService.create(request);
    return ResponseEntity.status(HttpStatus.CREATED).body(user);
}

// Или с URI нового ресурса
@PostMapping
public ResponseEntity<UserDTO> createUserWithLocation(@RequestBody CreateUserRequest request) {
    UserDTO user = userService.create(request);
    return ResponseEntity
        .created(URI.create("/api/v1/users/" + user.getId()))
        .body(user);
}

// С валидацией
@PostMapping
public ResponseEntity<UserDTO> createValidatedUser(
    @Valid @RequestBody CreateUserRequest request) {
    UserDTO user = userService.create(request);
    return ResponseEntity.status(HttpStatus.CREATED).body(user);
}

// Batch операция
@PostMapping("/batch")
public ResponseEntity<List<UserDTO>> createUsers(
    @RequestBody List<CreateUserRequest> requests) {
    List<UserDTO> users = userService.createBatch(requests);
    return ResponseEntity.status(HttpStatus.CREATED).body(users);
}

Характеристики POST:

  • Не идемпотентен: каждый запрос может создать новый ресурс
  • Имеет body: данные в теле запроса (JSON, XML, etc.)
  • HTTP коды: 201 Created, 400 Bad Request, 409 Conflict
  • Может иметь Location header: указывает URI нового ресурса
  • Используется для: создание, отправка форм, запуск операций

3. PUT - Полное обновление ресурса

PUT — полностью заменяет ресурс. Идемпотентен (несколько запросов = один запрос).

// Полное обновление пользователя
@PutMapping("/{id}")
public ResponseEntity<UserDTO> updateUser(
    @PathVariable Long id,
    @RequestBody UpdateUserRequest request) {
    UserDTO updated = userService.updateFully(id, request);
    return ResponseEntity.ok(updated);
}

// С проверкой существования
@PutMapping("/{id}")
public ResponseEntity<UserDTO> updateUserIfExists(
    @PathVariable Long id,
    @RequestBody UpdateUserRequest request) {
    try {
        UserDTO updated = userService.updateFully(id, request);
        return ResponseEntity.ok(updated);
    } catch (UserNotFoundException e) {
        // PUT может также создать ресурс, если его нет
        UserDTO created = userService.createWithId(id, request);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
}

// Обновление с предусловием (ETag)
@PutMapping("/{id}")
public ResponseEntity<UserDTO> updateUserWithETag(
    @PathVariable Long id,
    @RequestBody UpdateUserRequest request,
    @RequestHeader("If-Match") String etag) {
    UserDTO updated = userService.updateIfMatch(id, request, etag);
    return ResponseEntity.ok(updated);
}

Характеристики PUT:

  • Идемпотентен: несколько запросов = один запрос
  • Полное обновление: заменяет весь ресурс
  • Имеет body: полные данные ресурса
  • HTTP коды: 200 OK, 201 Created, 204 No Content, 400 Bad Request
  • Может создать: если ресурс не существует

4. PATCH - Частичное обновление ресурса

PATCH — частично обновляет ресурс. Обновляет только переданные поля.

// Частичное обновление
@PatchMapping("/{id}")
public ResponseEntity<UserDTO> partialUpdate(
    @PathVariable Long id,
    @RequestBody Map<String, Object> updates) {
    UserDTO updated = userService.updatePartially(id, updates);
    return ResponseEntity.ok(updated);
}

// С DTO для частичного обновления
@PatchMapping("/{id}")
public ResponseEntity<UserDTO> partialUpdateWithDTO(
    @PathVariable Long id,
    @RequestBody PatchUserRequest request) {
    UserDTO updated = userService.patchUser(id, request);
    return ResponseEntity.ok(updated);
}

// Пример DTO с Optional полями
public class PatchUserRequest {
    private Optional<String> name;
    private Optional<String> email;
    private Optional<String> phone;
    
    // getters, setters, constructors
}

// Использование
public UserDTO patchUser(Long id, PatchUserRequest request) {
    User user = userRepository.findById(id)
        .orElseThrow(() -> new UserNotFoundException("User not found"));
    
    request.getName().ifPresent(user::setName);
    request.getEmail().ifPresent(user::setEmail);
    request.getPhone().ifPresent(user::setPhone);
    
    return userRepository.save(user);
}

Характеристики PATCH:

  • Частичное обновление: только переданные поля
  • Менее строгий чем PUT: можно обновить один field
  • Имеет body: только измененные данные
  • HTTP коды: 200 OK, 204 No Content, 400 Bad Request
  • JSON Patch стандарт: RFC 6902 для стандартизации

5. DELETE - Удаление ресурса

DELETE — удаляет ресурс. Идемпотентен.

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

// С проверкой существования
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteUserIfExists(@PathVariable Long id) {
    try {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    } catch (UserNotFoundException e) {
        return ResponseEntity.notFound().build();
    }
}

// Мягкое удаление (soft delete)
@DeleteMapping("/{id}")
public ResponseEntity<Void> softDeleteUser(@PathVariable Long id) {
    userService.softDelete(id);  // Отмечает как удалённый
    return ResponseEntity.noContent().build();
}

// Batch удаление
@DeleteMapping
public ResponseEntity<Void> deleteUsers(@RequestBody List<Long> ids) {
    userService.deleteAll(ids);
    return ResponseEntity.noContent().build();
}

Характеристики DELETE:

  • Идемпотентен: несколько удалений = одно удаление
  • Может вернуть 404: если ресурс уже удалён
  • HTTP коды: 200 OK, 204 No Content, 404 Not Found
  • Нет гарантий: сервер может не удалить физически
  • Обычно возвращает: 204 No Content

6. HEAD - Как GET, но без тела

HEAD — как GET, но возвращает только заголовки БЕЗ тела ответа.

// Проверка существования ресурса
@HeadMapping("/{id}")
public ResponseEntity<Void> userExists(@PathVariable Long id) {
    return userService.exists(id)
        ? ResponseEntity.ok().build()
        : ResponseEntity.notFound().build();
}

// Проверка последнего изменения
@HeadMapping("/{id}")
public ResponseEntity<Void> getUserHeaders(@PathVariable Long id) {
    UserDTO user = userService.findById(id)
        .orElseThrow(() -> new UserNotFoundException("User not found"));
    
    return ResponseEntity.ok()
        .lastModified(user.getLastModified())
        .eTag(calculateETag(user))
        .build();
}

Характеристики HEAD:

  • Как GET: но без тела ответа
  • Быстрее: меньше передачи данных
  • Проверка: существует ли ресурс
  • Заголовки: возвращаются полностью (Content-Length, ETag, etc.)

7. OPTIONS - Информация о методах

OPTIONS — возвращает информацию о допустимых методах для ресурса.

// Spring обычно генерирует автоматически
@OptionsMapping("/")
public ResponseEntity<Void> describeOptions() {
    return ResponseEntity.ok()
        .allow(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, 
               HttpMethod.PATCH, HttpMethod.DELETE, HttpMethod.OPTIONS)
        .build();
}

// CORS preflight запросы
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("*")
            .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
            .allowedHeaders("*")
            .maxAge(3600);
    }
}

Сравнительная таблица

МетодБезопасенИдемпотентенBodyКешИспользуется для
GETДаДаНетДаПолучение данных
POSTНетНетДаНетСоздание ресурса
PUTНетДаДаНетПолное обновление
PATCHНетНет*ДаНетЧастичное обновление
DELETEНетДаНетНетУдаление ресурса
HEADДаДаНетДаПроверка метаданных
OPTIONSДаДаНетНетОписание методов

*PATCH может быть идемпотентен в зависимости от реализации

HTTP коды ответов

@GetMapping("/{id}")
public ResponseEntity<?> handleRequest(@PathVariable Long id) {
    // 2xx Success
    return ResponseEntity.ok(data);                    // 200 OK
    return ResponseEntity.status(HttpStatus.CREATED)  // 201 Created
        .body(data);
    return ResponseEntity.noContent().build();         // 204 No Content
    
    // 3xx Redirection
    return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY) // 301
        .location(URI.create("/new-url"))
        .build();
    
    // 4xx Client Error
    return ResponseEntity.badRequest().body(error);              // 400
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();// 401
    return ResponseEntity.status(HttpStatus.FORBIDDEN).build();  // 403
    return ResponseEntity.notFound().build();                    // 404
    
    // 5xx Server Error
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) // 500
        .body(error);
}

Лучшие практики

  • Используй правильный метод: GET для чтения, POST для создания, PUT/PATCH для обновления, DELETE для удаления
  • Возвращай правильные коды: 201 при создании, 204 при удалении, 400 при ошибке
  • Идемпотентность: PUT и DELETE должны быть идемпотентны
  • URL как существительные: /users, не /getUsers или /deleteUser
  • Версионирование API: /api/v1/users
  • Валидация: используй @Valid для DTO
  • Обработка ошибок: ControllerAdvice для глобальной обработки
  • CORS: настрой правильно для cross-origin запросов

Правильное использование HTTP методов — это основа хорошего REST API дизайна.

Какие использовали методы в @RestController | PrepBro