بالدرس اليوم رح نضل بالـ Controller ونركز على شيئين مهمين: كيف نبعث الـ Status Code الصحيح للـ Client، وكيف نعمل Validation للبيانات الجاية بالـ Request.
| Status Code | الاسم | المعنى |
|---|---|---|
200 | OK | كل شي تمام |
201 | Created | تم الإنشاء بنجاح |
204 | No Content | نجح الطلب بس ما في بيانات راجعة |
400 | Bad Request | مشكلة من الـ Client (بيانات ناقصة أو غلط) |
401 | Unauthorized | ما عمل Login |
403 | Forbidden | عامل Login بس ما عنده الـ Permissions الكافية |
404 | Not Found | عبيحاول يوصل لـ Resource مش موجود |
409 | Conflict | تعارض، مثلاً بيانات مكررة |
بدل ما نرجع البيانات مباشرة، بنلفها بـ ResponseEntity لنتحكم بالـ Status Code:
@GetMapping
public ResponseEntity<ArrayList<Employee>> findAll() {
return new ResponseEntity<>(employees, HttpStatus.OK);
}
ResponseEntity بياخذ:
HttpStatus المناسبلازم نتعامل مع حالة أن الموظف مش موجود:
اشترك في النشرة البريدية
دروس جديدة، مقالات، وأدوات مباشرة لبريدك.
@GetMapping("/{employeeId}")
public ResponseEntity<Employee> findOne(@PathVariable UUID employeeId) {
Optional<Employee> employee = employees.stream()
.filter(emp -> emp.getId().equals(employeeId))
.findFirst();
if (employee.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(employee.get(), HttpStatus.OK);
}إذا الموظف ما انلقى بيرجع 404 Not Found، وإذا انلقى بيرجع 200 OK مع البيانات.
@PostMapping
public ResponseEntity<Employee> create(@RequestBody Employee employee) {
employee.setId(UUID.randomUUID());
employees.add(employee);
return new ResponseEntity<>(employee, HttpStatus.CREATED);
}بنرجع 201 Created بدل 200 OK لأنو أدق.
@PutMapping("/{employeeId}")
public ResponseEntity<Employee> update(@PathVariable UUID employeeId,
@RequestBody Employee updatedEmployee) {
Optional<Employee> existing = employees.stream()
.filter(emp -> emp.getId().equals(employeeId))
.findFirst();
if (existing.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Employee emp = existing.get();
emp.setFirstName(updatedEmployee.getFirstName());
emp.setLastName(updatedEmployee.getLastName());
emp.setEmail(updatedEmployee.getEmail());
emp.setPosition(updatedEmployee.getPosition());
return new ResponseEntity<>(emp, HttpStatus.OK);
}@DeleteMapping("/{employeeId}")
public ResponseEntity<Void> delete(@PathVariable UUID employeeId) {
employees.removeIf(emp -> emp.getId().equals(employeeId));
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}بنرجع 204 No Content لأننا ما برجع أي بيانات بعد الحذف. لاحظ إن الـ Generic Type صار Void.
لو الـ Client بعث Request بدون firstName مثلاً، لازم السيرفر يرفضها. بنستخدم Bean Validation Annotations على الـ Entity:
@Getter
@Setter
@AllArgsConstructor
public class Employee {
private UUID id;
@NotBlank(message = "First name is required")
private String firstName;
@NotBlank(message = "Last name is required")
private String lastName;
@NotBlank(message = "Email is required")
private String email;
@NotBlank(message = "Phone number is required")
private String phoneNumber;
@NotNull
private LocalDate hireDate;
@NotBlank(message = "Position is required")
private String position;
private UUID departmentId;
}@NotBlank - بتتأكد أن الـ String مش فاضي ومش Null@NotNull - بتتأكد أن القيمة مش Nullبعدين بالـ Controller، بنضيف @Valid قبل الـ @RequestBody لتفعيل الـ Validation:
@PostMapping
public ResponseEntity<Employee> create(@Valid @RequestBody Employee employee) {
employee.setId(UUID.randomUUID());
employees.add(employee);
return new ResponseEntity<>(employee, HttpStatus.CREATED);
}هيك إذا الـ Client نسي يبعث firstName، بيرجع له 400 Bad Request تلقائياً مع رسالة الخطأ:
{
"errors": [
{ "field": "firstName", "message": "First name is required" },
{ "field": "lastName", "message": "Last name is required" }
]
}الـ @Size Annotation بتسمح تحدد الحد الأدنى والأقصى لطول النص:
@Size(min = 2, max = 50, message = "First name must be between 2 and 50 characters")
private String firstName;فينا نطبق نفس الـ Validation على الـ PUT Endpoint برضو، لأننا بنطلب من الـ Client يبعث كل الـ Object كامل.
بالدرس الجاي رح نشوف كيف نتعامل مع الـ Errors بشكل أنظف عن طريق Global Exception Handler.