Exception handling - Spring Boot’da xatolarni tartibli ushlash va clientga tushunarli response qaytarish usuli.
Bu bo‘lim ichida quyidagilar bor: @ControllerAdvice / @RestControllerAdvice, @ExceptionHandler, custom exception classes, ProblemDetail, consistent error response format.
1. Exception handling nima?
API ishlaganda har xil xatolar bo‘ladi:
User topilmadi
Email allaqachon mavjud
Validation xato
Database xato
Token noto‘g‘ri
Ruxsat yo‘qAgar bu xatolarni tartibli ushlamasak, clientga noaniq response qaytadi:
{
"timestamp": "2026-05-21T10:00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/api/users/99"
}Bu frontend yoki mobile developer uchun yetarli emas.
Yaxshi API xatosi shunday bo‘lishi kerak:
{
"code": "USER_NOT_FOUND",
"message": "User topilmadi",
"status": 404,
"path": "/api/users/99"
}2. Exception nima?
Java’da exception - dastur ishlayotgan paytda yuz beradigan xato.
Masalan:
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));Agar user topilmasa, exception tashlanadi.
throw new RuntimeException(...)ya’ni: "bu holatda normal davom etib bo‘lmaydi".
3. Spring Boot’da default xato response
Agar siz exceptionni o‘zingiz ushlamasangiz, Spring Boot default error qaytaradi.
Masalan:
@GetMapping("/{id}")
public UserResponse getById(@PathVariable Long id) {
throw new RuntimeException("User not found");
}Response odatda shunga o‘xshash bo‘ladi:
{
"timestamp": "2026-05-21T10:00:00.000+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/api/users/1"
}Muammo:
status noto‘g‘ri: 500 emas, 404 bo‘lishi kerak
message aniq emas
frontend uchun code yo‘q
hamma xato bir xil formatda emasShuning uchun global exception handler yoziladi.
4. @RestControllerAdvice nima?
@RestControllerAdvice - butun project bo‘yicha exceptionlarni ushlaydigan global class.
@RestControllerAdvice
public class GlobalExceptionHandler {
}Bu class ichida har xil exceptionlar uchun handler methodlar yoziladi.
5. @ExceptionHandler nima?
@ExceptionHandler - qaysi exceptionni ushlash kerakligini bildiradi.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ex.getMessage());
}
}Agar projectda RuntimeException chiqsa, Spring shu methodni chaqiradi.
6. Lekin hamma joyda RuntimeException ishlatish yomon
Yomonroq:
throw new RuntimeException("User not found");Nega?
Chunki RuntimeException juda umumiy. U orqali xato turi aniq bilinmaydi.
Yaxshiroq:
throw new NotFoundException("User topilmadi");Yoki:
throw new BadRequestException("Email allaqachon mavjud");7. Custom exception classlar
Real loyihada o‘z exception classlaringiz bo‘lgani yaxshi.
NotFoundException
public class NotFoundException extends RuntimeException {
public NotFoundException(String message) {
super(message);
}
}BadRequestException
public class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}ForbiddenException
public class ForbiddenException extends RuntimeException {
public ForbiddenException(String message) {
super(message);
}
}8. Service’da custom exception ishlatish
Masalan UserService:
@Service
public class UserService {
private final UserRepository userRepository;
private final UserMapper userMapper;
public UserService(UserRepository userRepository,
UserMapper userMapper) {
this.userRepository = userRepository;
this.userMapper = userMapper;
}
public UserResponse getById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new NotFoundException("User topilmadi"));
return userMapper.toResponse(user);
}
@Transactional
public UserResponse create(UserCreateRequest request) {
if (userRepository.existsByEmail(request.email())) {
throw new BadRequestException("Email allaqachon mavjud");
}
User user = userMapper.toEntity(request);
User savedUser = userRepository.save(user);
return userMapper.toResponse(savedUser);
}
}Bu yerda:
User topilmasa → NotFoundException
Email mavjud bo‘lsa → BadRequestException9. Error response DTO
Clientga bir xil formatda xato qaytarish uchun DTO yozamiz.
import java.time.LocalDateTime;
import java.util.Map;
public record ErrorResponse(
String code,
String message,
int status,
String path,
LocalDateTime timestamp,
Map<String, String> fields
) {
}Bu yerda:
code → xato kodi
message → odam tushunadigan xabar
status → HTTP status
path → qaysi endpointda xato bo‘ldi
timestamp → qachon xato bo‘ldi
fields → validation xatolari uchun10. GlobalExceptionHandler to‘liq misol
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.time.LocalDateTime;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(
NotFoundException ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"NOT_FOUND",
ex.getMessage(),
HttpStatus.NOT_FOUND.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
}
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<ErrorResponse> handleBadRequest(
BadRequestException ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"BAD_REQUEST",
ex.getMessage(),
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.badRequest().body(response);
}
}11. Natija qanday bo‘ladi?
Request:
GET /api/users/99Agar user topilmasa:
{
"code": "NOT_FOUND",
"message": "User topilmadi",
"status": 404,
"path": "/api/users/99",
"timestamp": "2026-05-21T15:30:12",
"fields": null
}Request:
POST /api/usersAgar email mavjud bo‘lsa:
{
"code": "BAD_REQUEST",
"message": "Email allaqachon mavjud",
"status": 400,
"path": "/api/users",
"timestamp": "2026-05-21T15:32:44",
"fields": null
}12. Validation exception handling
Oldingi darsda @Valid ishlatdik.
Masalan request xato:
{
"fullName": "",
"email": "wrong-email",
"age": -5
}DTO:
public record UserCreateRequest(
@NotBlank(message = "Full name majburiy")
String fullName,
@NotBlank(message = "Email majburiy")
@Email(message = "Email formati noto‘g‘ri")
String email,
@NotNull(message = "Age majburiy")
@Min(value = 18, message = "Yosh kamida 18 bo‘lishi kerak")
Integer age
) {
}Validation xatosi uchun Spring MethodArgumentNotValidException tashlaydi.
Uni ushlaymiz:
import org.springframework.web.bind.MethodArgumentNotValidException;
import java.util.HashMap;
import java.util.Map;
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(
MethodArgumentNotValidException ex,
HttpServletRequest request
) {
Map<String, String> fields = new HashMap<>();
ex.getBindingResult()
.getFieldErrors()
.forEach(error ->
fields.put(error.getField(), error.getDefaultMessage())
);
ErrorResponse response = new ErrorResponse(
"VALIDATION_ERROR",
"Request data noto‘g‘ri",
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
fields
);
return ResponseEntity.badRequest().body(response);
}Response:
{
"code": "VALIDATION_ERROR",
"message": "Request data noto‘g‘ri",
"status": 400,
"path": "/api/users",
"timestamp": "2026-05-21T15:35:01",
"fields": {
"fullName": "Full name majburiy",
"email": "Email formati noto‘g‘ri",
"age": "Yosh kamida 18 bo‘lishi kerak"
}
}13. RequestParam va PathVariable validation xatosi
Agar controller’da shunday yozgan bo‘lsak:
@RestController
@RequestMapping("/api/products")
@Validated
public class ProductController {
@GetMapping
public Page<ProductResponse> getAll(
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size
) {
return productService.getAll(page, size);
}
}Request:
GET /api/products?page=-1&size=500Bunda odatda ConstraintViolationException chiqadi.
Handler:
import jakarta.validation.ConstraintViolationException;
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleConstraintViolation(
ConstraintViolationException ex,
HttpServletRequest request
) {
Map<String, String> fields = new HashMap<>();
ex.getConstraintViolations()
.forEach(error -> {
String field = error.getPropertyPath().toString();
String message = error.getMessage();
fields.put(field, message);
});
ErrorResponse response = new ErrorResponse(
"VALIDATION_ERROR",
"Request parameter noto‘g‘ri",
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
fields
);
return ResponseEntity.badRequest().body(response);
}Response taxminan:
{
"code": "VALIDATION_ERROR",
"message": "Request parameter noto‘g‘ri",
"status": 400,
"path": "/api/products",
"timestamp": "2026-05-21T15:40:20",
"fields": {
"getAll.page": "must be greater than or equal to 0",
"getAll.size": "must be less than or equal to 100"
}
}14. Type mismatch xatolari
Masalan endpoint:
@GetMapping("/{id}")
public UserResponse getById(@PathVariable Long id) {
return userService.getById(id);
}Client noto‘g‘ri yubordi:
GET /api/users/abcabc ni Long ga aylantirib bo‘lmaydi.
Bunda Spring odatda MethodArgumentTypeMismatchException tashlaydi.
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<ErrorResponse> handleTypeMismatch(
MethodArgumentTypeMismatchException ex,
HttpServletRequest request
) {
String message = "Parameter formati noto‘g‘ri: " + ex.getName();
ErrorResponse response = new ErrorResponse(
"TYPE_MISMATCH",
message,
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.badRequest().body(response);
}Response:
{
"code": "TYPE_MISMATCH",
"message": "Parameter formati noto‘g‘ri: id",
"status": 400,
"path": "/api/users/abc",
"timestamp": "2026-05-21T15:42:10",
"fields": null
}15. JSON noto‘g‘ri bo‘lsa
Client noto‘g‘ri JSON yuborishi mumkin:
{
"name": "Laptop",
"price":
}Bu JSON invalid.
Bunda Spring HttpMessageNotReadableException tashlaydi.
import org.springframework.http.converter.HttpMessageNotReadableException;
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ErrorResponse> handleNotReadable(
HttpMessageNotReadableException ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"INVALID_JSON",
"Request body noto‘g‘ri yoki JSON format xato",
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.badRequest().body(response);
}Response:
{
"code": "INVALID_JSON",
"message": "Request body noto‘g‘ri yoki JSON format xato",
"status": 400,
"path": "/api/products",
"timestamp": "2026-05-21T15:45:00",
"fields": null
}16. Exception.class fallback handler
Har doim eng oxirida umumiy exception handler bo‘lgani yaxshi.
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(
Exception ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"INTERNAL_SERVER_ERROR",
"Serverda kutilmagan xato yuz berdi",
HttpStatus.INTERNAL_SERVER_ERROR.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(response);
}Muhim: production’da clientga ex.getMessage()ni doim qaytarish xavfli bo‘lishi mumkin.
Yomon:
"message": ex.getMessage()Chunki unda database, table, stack trace yoki ichki texnik ma’lumot chiqib ketishi mumkin.
Yaxshiroq:
"Serverda kutilmagan xato yuz berdi"Lekin logga exceptionni yozish kerak.
17. Logging qo‘shish
Global handler ichida xatoni log qilish foydali.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log =
LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(
Exception ex,
HttpServletRequest request
) {
log.error("Unexpected error. path={}", request.getRequestURI(), ex);
ErrorResponse response = new ErrorResponse(
"INTERNAL_SERVER_ERROR",
"Serverda kutilmagan xato yuz berdi",
HttpStatus.INTERNAL_SERVER_ERROR.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(response);
}
}Clientga umumiy xabar qaytadi, lekin backend logda to‘liq stack trace qoladi.
18. To‘liq GlobalExceptionHandler
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log =
LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(
NotFoundException ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"NOT_FOUND",
ex.getMessage(),
HttpStatus.NOT_FOUND.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
}
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<ErrorResponse> handleBadRequest(
BadRequestException ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"BAD_REQUEST",
ex.getMessage(),
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(
MethodArgumentNotValidException ex,
HttpServletRequest request
) {
Map<String, String> fields = new HashMap<>();
ex.getBindingResult()
.getFieldErrors()
.forEach(error ->
fields.put(error.getField(), error.getDefaultMessage())
);
ErrorResponse response = new ErrorResponse(
"VALIDATION_ERROR",
"Request data noto‘g‘ri",
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
fields
);
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleConstraintViolation(
ConstraintViolationException ex,
HttpServletRequest request
) {
Map<String, String> fields = new HashMap<>();
ex.getConstraintViolations()
.forEach(error ->
fields.put(
error.getPropertyPath().toString(),
error.getMessage()
)
);
ErrorResponse response = new ErrorResponse(
"VALIDATION_ERROR",
"Request parameter noto‘g‘ri",
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
fields
);
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<ErrorResponse> handleTypeMismatch(
MethodArgumentTypeMismatchException ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"TYPE_MISMATCH",
"Parameter formati noto‘g‘ri: " + ex.getName(),
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ErrorResponse> handleNotReadable(
HttpMessageNotReadableException ex,
HttpServletRequest request
) {
ErrorResponse response = new ErrorResponse(
"INVALID_JSON",
"Request body noto‘g‘ri yoki JSON format xato",
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(
Exception ex,
HttpServletRequest request
) {
log.error("Unexpected error. path={}", request.getRequestURI(), ex);
ErrorResponse response = new ErrorResponse(
"INTERNAL_SERVER_ERROR",
"Serverda kutilmagan xato yuz berdi",
HttpStatus.INTERNAL_SERVER_ERROR.value(),
request.getRequestURI(),
LocalDateTime.now(),
null
);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(response);
}
}19. ProblemDetail nima?
Spring 6'da ProblemDetail degan tayyor error response modeli bor.
U RFC 7807 uslubiga yaqin.
Oddiy misol:
import org.springframework.http.ProblemDetail;
@ExceptionHandler(NotFoundException.class)
public ProblemDetail handleNotFound(NotFoundException ex) {
ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.NOT_FOUND);
problem.setTitle("Resource not found");
problem.setDetail(ex.getMessage());
return problem;
}Response taxminan:
{
"type": "about:blank",
"title": "Resource not found",
"status": 404,
"detail": "User topilmadi",
"instance": "/api/users/99"
}ProblemDetail foydali, chunki u standartga yaqin. Lekin boshlang'ich bosqichda avval o‘zingizning ErrorResponse formatini tushunib olish yaxshiroq.
20. @ResponseStatus bilan exception
Yana bir usul bor:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {
public NotFoundException(String message) {
super(message);
}
}Bu usulda NotFoundException tashlansa, status 404 bo‘ladi.
Lekin kamchiligi:
Response formatni to‘liq nazorat qilish qiyinroq
Har xil xatolarni bir xil JSON formatda qaytarish noqulayroqShuning uchun real REST API’da @RestControllerAdvice ko‘proq ishlatiladi.
21. HTTP statuslarni to‘g‘ri tanlash
Holat | Status | Misol |
|---|---|---|
Validation xato |
|
|
Noto‘g‘ri request |
| email allaqachon mavjud |
Login kerak |
| token yo‘q |
Ruxsat yo‘q |
| user admin emas |
Resource topilmadi |
| product id mavjud emas |
Conflict |
| duplicate unique value |
Server xatosi |
| kutilmagan exception |
Javachilar uchun eng ko‘p ishlatiladiganlari:
400
401
403
404
409
50022. 400 va 404 farqi
400 Bad Request
Client noto‘g‘ri ma’lumot yubordi.
Misollar:
email format xato
age -5
price 0 dan kichik
JSON invalid404 Not Found
Client so‘ragan narsa topilmadi.
Misollar:
/api/users/99 → bunday user yo‘q
/api/products/123 → bunday product yo‘q23. 403 va 401 farqi
401 Unauthorized
User hali authentication qilmagan.
Masalan:
Token yo‘q
Token noto‘g‘ri
Token muddati tugagan403 Forbidden
User login qilgan, lekin ruxsati yo‘q.
Masalan:
Oddiy user admin endpointga kirmoqchi24. Product API’da exception handling misoli
ProductService
@Service
public class ProductService {
private final ProductRepository productRepository;
private final CategoryRepository categoryRepository;
private final ProductMapper productMapper;
public ProductService(ProductRepository productRepository,
CategoryRepository categoryRepository,
ProductMapper productMapper) {
this.productRepository = productRepository;
this.categoryRepository = categoryRepository;
this.productMapper = productMapper;
}
@Transactional(readOnly = true)
public ProductResponse getById(Long id) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new NotFoundException("Product topilmadi"));
return productMapper.toResponse(product);
}
@Transactional
public ProductResponse create(ProductCreateRequest request) {
if (productRepository.existsByName(request.name())) {
throw new BadRequestException("Product name allaqachon mavjud");
}
Category category = categoryRepository.findById(request.categoryId())
.orElseThrow(() -> new NotFoundException("Category topilmadi"));
Product product = productMapper.toEntity(request, category);
Product saved = productRepository.save(product);
return productMapper.toResponse(saved);
}
@Transactional
public ProductResponse update(Long id, ProductUpdateRequest request) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new NotFoundException("Product topilmadi"));
if (request.name() != null && productRepository.existsByName(request.name())) {
throw new BadRequestException("Product name allaqachon mavjud");
}
if (request.categoryId() != null) {
Category category = categoryRepository.findById(request.categoryId())
.orElseThrow(() -> new NotFoundException("Category topilmadi"));
product.setCategory(category);
}
productMapper.updateEntity(product, request);
return productMapper.toResponse(product);
}
@Transactional
public void delete(Long id) {
if (!productRepository.existsById(id)) {
throw new NotFoundException("Product topilmadi");
}
productRepository.deleteById(id);
}
}25. Exceptionlarni package qilish
Package-by-feature bo‘lsa:
src/main/java/com/example/demo
├── product
│ ├── ProductController.java
│ ├── ProductService.java
│ └── ...
├── category
│ └── ...
└── common
├── exception
│ ├── BadRequestException.java
│ ├── NotFoundException.java
│ └── GlobalExceptionHandler.java
└── response
└── ErrorResponse.javacommon ichida butun projectga umumiy classlar turadi.
26. Eng ko‘p qilinadigan xatolar
Xato 1: Controller’da try-catch yozish
Yomon:
@GetMapping("/{id}")
public ResponseEntity<?> getById(@PathVariable Long id) {
try {
return ResponseEntity.ok(productService.getById(id));
} catch (Exception ex) {
return ResponseEntity.badRequest().body(ex.getMessage());
}
}Bu yomon, chunki har bir controller’da bir xil try-catch ko‘payib ketadi.
Yaxshi:
@GetMapping("/{id}")
public ProductResponse getById(@PathVariable Long id) {
return productService.getById(id);
}Exceptionni GlobalExceptionHandler ushlaydi.
Xato 2: Har joyda RuntimeException
Yomon:
throw new RuntimeException("Product not found");Yaxshi:
throw new NotFoundException("Product topilmadi");Xato 3: Hamma xatoga 500 qaytarish
Yomon:
{
"status": 500,
"message": "User not found"
}User not found - server xatosi emas. To‘g‘ri status:
404 Not FoundXato 4: Clientga stack trace qaytarish
Yomon:
{
"message": "could not execute statement; SQL [insert into users...]"
}Bu xavfli. Ichki texnik ma’lumot chiqib ketadi.
Yaxshi:
{
"code": "INTERNAL_SERVER_ERROR",
"message": "Serverda kutilmagan xato yuz berdi"
}Xato 5: Error response format har xil bo‘lishi
Yomon:
"User not found"Boshqa endpointda:
{
"error": "Email exists"
}Yana boshqasida:
{
"message": "Validation failed",
"errors": [...]
}Yaxshi: hammasi bir xil formatda:
{
"code": "...",
"message": "...",
"status": 400,
"path": "...",
"timestamp": "...",
"fields": {}
}27. Javachi uchun qisqa qoida
Service exception tashlaydi.
Controller try-catch qilmaydi.
GlobalExceptionHandler exceptionni ushlaydi.
Clientga bir xil ErrorResponse qaytadi.
Logga texnik xato yoziladi.
Clientga xavfsiz xabar qaytariladi.28. Amaliy vazifa
Oldingi Product CRUD API loyihasiga exception handling qo‘shing.
Classlar
common.exception.NotFoundException
common.exception.BadRequestException
common.exception.GlobalExceptionHandler
common.response.ErrorResponseErrorResponse
public record ErrorResponse(
String code,
String message,
int status,
String path,
LocalDateTime timestamp,
Map<String, String> fields
) {
}Handlerlar
Quyidagilarni ushlang:
NotFoundException → 404
BadRequestException → 400
MethodArgumentNotValidException → 400
ConstraintViolationException → 400
MethodArgumentTypeMismatchException → 400
HttpMessageNotReadableException → 400
Exception → 500ProductService’da ishlating
Product topilmasa → NotFoundException
Category topilmasa → NotFoundException
Product name duplicate bo‘lsa → BadRequestExceptionKutilgan response
{
"code": "NOT_FOUND",
"message": "Product topilmadi",
"status": 404,
"path": "/api/products/99",
"timestamp": "2026-05-21T15:55:00",
"fields": null
}Xulosa
Exception handling - professional REST API yozishning majburiy qismi.
Eng muhimlari:
@RestControllerAdvice → global error handler
@ExceptionHandler → exception turini ushlaydi
Custom exception → xato turini aniq qiladi
ErrorResponse → clientga bir xil format
MethodArgumentNotValidException → @Valid xatolari
ConstraintViolationException → @RequestParam / @PathVariable validation
ProblemDetail → Spring 6 standart error modeliEng asosiy flow:
Service’da xato yuz berdi
↓
Custom exception tashlandi
↓
GlobalExceptionHandler ushladi
↓
ErrorResponse qaytdi
↓
Client tushunarli xato oldi