Spring Boot 3.0 ile Gelen Problem Details Kullanımı ve Uygulama Örneği
Spring Boot 3.0 ile gelen yeni gelen Problem Details sınıfından bahsedeceğim.
ProblemDetail Nedir?
Uygulamalarımızda Exception Handling yaparken bu hataları istemciye bildirmek için sınıflar kullanırız. Bu özellik gelmeden önce hata mesajını döndürdüğümüzde kendi sınıfımızı ve alanlarımızı kendimizin oluşturması gerekiyor. Bu sınıfların alanları ve içereceği değerler yazılımcının insifiyatine kalmaktadır.
Yeni gelen bu özellik sayesinde Hata mesajları için Spring Framework’ün ProblemDetail‘i kullanarak, birbiriyle iletişim servislerimizin yanıt biçimini standartlaştırabiliriz.
Problem Detail Sınıfı
Sınıfın içeriğinde kullanabileceğimiz alanlar aşağıdaki gibidir bu sınıfın alanları kullanarak kolay bir şekilde hata responslarımızı doldurarak cevap verebiliriz.
private URI type;
private String title;
private int status;
private String detail;
private URI instance;
private Map<String, Object> properties;
Code language: PHP (php)
Uygulama Örneği
Bir Student sınıfı içeren ve bir list içerisinde tutan basit bir rest api yapacağız.
Modelimiz aşağıdaki şekilde olacak.
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private String surName;
private String schoolNumber;
private String schoolName;
}
Code language: Java (java)
Controller sınfımızda bir kaydetme ve bir de okul numarasına göre arama işlemini yapacağız.
@RestController
public class StudentController {
@Autowired
StudentService studentService;
@PostMapping("/")
public Student save(@RequestBody Student student) {
return studentService.add(student);
}
@GetMapping("/{schoolNumber}")
public Student getStudent(@PathVariable String schoolNumber) throws StudentNotFoundException {
return studentService.getStudent(schoolNumber);
}
}
Code language: Java (java)
Servisimizi yazalım.
@Service
public class StudentService {
private List<Student> studentList = new ArrayList<>();
public Student add(Student student) {
studentList.add(student);
return student;
}
public Student getStudent(String schoolNumber) {
return studentList.stream()
.filter(student -> student.getSchoolNumber().equals(schoolNumber))
.findFirst().get();
}
}
Code language: Java (java)
Şimdi bir istek yollayalım.
{
"name": "John",
"surName": "Doe",
"schoolNumber": 1234567890,
"schoolName": "İstanbul Üniversitesi"
}
Code language: JSON / JSON with Comments (json)
Bu şimdi var olmayan bir okul numarasına göre istek attığımızda ki gelen hataya bakalım.
{
"timestamp": "2023-07-18T13:03:34.666+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/1234567890a"
}
Code language: JSON / JSON with Comments (json)
Hata mesajında varsayılan olarak Bad Request
işaretlenmiş olarak geldi. Bu çok açıklayıcı değil. Şimdi Exception Hanling
yapalım ve hata dönüş cevabımızı ProblemDetail
e göre doldurarak cevap verelim.
ExecptionHandling ve ProblemDetails Implementasyonu
Şimdi bir StudentNotFoundException
sınıfı oluşturalım.
public class StudentNotFoundException extends RuntimeException {
public StudentNotFoundException(String schoolNumber) {
super("Student Not Found! " + schoolNumber);
}
}
Code language: JavaScript (javascript)
Sonrasında servisimize bir hata fırlatacak kodu ekleyelim.
@Service
public class StudentService {
...
...
public Student getStudent(String schoolNumber) {
return studentList.stream()
.filter(student -> student.getSchoolNumber().equals(schoolNumber))
.findFirst()
.orElseThrow(() -> new StudentNotFoundException(schoolNumber));
}
}
Code language: Java (java)
Şimdi ise GlobalExceptionHandler
sınıfımızı kullanalım ve ProblemDetail
kullanarak vereceğimiz hata mesajımızı gerekli olan bilgileri dolduralım.
@RestControllerAdvice
public class GlobalExceptionHandler{
@ExceptionHandler(StudentNotFoundException.class)
public ProblemDetail studentNotFoundException(StudentNotFoundException e) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, e.getMessage());
problemDetail.setTitle("Student not found!");
problemDetail.setType(URI.create("https://http.cat/status/404"));
problemDetail.setProperty("errorCategory", "Generic");
problemDetail.setProperty("timestamp", Instant.now());
return problemDetail;
}
}
Code language: Java (java)
ProblemDetail
sınıfı sayesinde dönüş alanlarımızı belirli bir standarta getirmiş olduk. Tüm alanları kullanıp, kullanmamak bizim elimizde olup kullandığımızda ise alanlarımızın aynı olduğunu her zaman koruyoruz ve bizi fazladan bir sınıf yazma zahmetini de ortadan kalkıyor.
Şimdi yine geçersiz bir istek attıktan sonra çıkan sonuca bakalım.
{
"type": "https://http.cat/status/404",
"title": "Student not found!",
"status": 404,
"detail": "Student Not Found! 1234567890a",
"instance": "/1234567890a",
"errorCategory": "Generic",
"timestamp": "2023-07-18T13:19:48.619101Z"
}
Code language: JSON / JSON with Comments (json)
No Comment! Be the first one.