Какие знаешь подходы проектирования REST API?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Подходы проектирования REST API
REST (Representational State Transfer) — архитектурный стиль для построения веб-сервисов, основанный на стандартах HTTP и принципах распределенных систем. Правильное проектирование REST API критично для масштабируемости и удобства интеграции клиентов.
1. Ресурсо-ориентированный подход
Основной принцип REST — все в системе представляется как ресурсы, а не действия. Каждый ресурс имеет уникальный URI:
// Правильно — ресурсы
GET /api/v1/users // Получить список пользователей
GET /api/v1/users/{id} // Получить конкретного пользователя
POST /api/v1/users // Создать нового пользователя
PUT /api/v1/users/{id} // Обновить пользователя
DELETE /api/v1/users/{id} // Удалить пользователя
// Неправильно — глаголы в URI
GET /api/v1/getUsers
POST /api/v1/createUser
POST /api/v1/deleteUser/{id}
Вложенные ресурсы для коллекций:
GET /api/v1/users/{userId}/posts // Посты конкретного пользователя
POST /api/v1/users/{userId}/posts // Создать пост
GET /api/v1/users/{userId}/posts/{postId} // Получить конкретный пост
2. HTTP методы и семантика
GET — безопасен (не изменяет состояние), идемпотентен (повторные вызовы возвращают одинаковый результат):
@GetMapping("/users/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
POST — создает новый ресурс, не идемпотентен (повторные вызовы создают разные ресурсы):
@PostMapping("/users")
public ResponseEntity<UserDto> createUser(@RequestBody CreateUserRequest request) {
UserDto created = userService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
PUT — полностью заменяет ресурс, идемпотентен:
@PutMapping("/users/{id}")
public ResponseEntity<UserDto> updateUser(@PathVariable Long id,
@RequestBody UpdateUserRequest request) {
UserDto updated = userService.update(id, request);
return ResponseEntity.ok(updated);
}
PATCH — частичное обновление ресурса:
@PatchMapping("/users/{id}")
public ResponseEntity<UserDto> partialUpdate(@PathVariable Long id,
@RequestBody JsonPatch patch) {
UserDto updated = userService.patch(id, patch);
return ResponseEntity.ok(updated);
}
DELETE — удаляет ресурс, идемпотентен:
@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
3. Коды ответов (HTTP Status Codes)
- 200 OK — успешный GET, PUT, PATCH
- 201 Created — успешный POST с созданием ресурса
- 204 No Content — успешный DELETE или обновление без тела ответа
- 400 Bad Request — ошибка валидации клиента
- 401 Unauthorized — требуется аутентификация
- 403 Forbidden — недостаточно прав доступа
- 404 Not Found — ресурс не найден
- 409 Conflict — конфликт состояния (например, дублирование)
- 500 Internal Server Error — ошибка сервера
4. Версионирование API
URL версионирование — простой способ управления версиями:
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 { }
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 { }
Header версионирование — более элегантный подход:
@GetMapping("/users/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id,
@RequestHeader("API-Version") String version) {
if ("2".equals(version)) {
return ResponseEntity.ok(userService.findByIdV2(id));
}
return ResponseEntity.ok(userService.findById(id));
}
5. Фильтрация, сортировка и пагинация
@GetMapping("/users")
public ResponseEntity<Page<UserDto>> listUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String sort,
@RequestParam(required = false) String filter) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sort));
Page<UserDto> users = userService.findAll(pageable, filter);
return ResponseEntity.ok(users);
}
6. Content Negotiation
@GetMapping(value = "/users/{id}", produces = {"application/json", "application/xml"})
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
7. Обработка ошибок
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"NOT_FOUND",
ex.getMessage(),
System.currentTimeMillis()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
8. Безопасность
- Используй HTTPS для всех запросов
- Реализуй аутентификацию (OAuth 2.0, JWT)
- Валидируй входные данные на сервере
- Используй CORS для контроля доступа
- Применяй rate limiting для защиты от DDoS
- Логируй важные события
Правильное проектирование REST API обеспечивает интуитивность, масштабируемость и безопасность системы.