π[Spring] APIμμ μμΈ λμ§κΈ°.
Java λ°±μλ μ ν리μΌμ΄μ μμ API νΈμΆ μ€ μμΈλ₯Ό λμ§λ©΄, μμΈκ° μ μ νκ² μ²λ¦¬λμ§ μλ ν ν΄λΌμ΄μΈνΈμ μ€λ₯ μλ΅μ΄ λ°νλ©λλ€.
κΈ°λ³Έμ μΌλ‘ μμΈκ° λ°μνλ©΄ μ ν리μΌμ΄μ μ μμΈκ° λ°μν μμ μμ μ€νμ μ€λ¨νκ³ , μμΈμ λν μ²λ¦¬λ₯Ό νμ§ μμΌλ©΄ λ΄λΆ μλ² μ€λ₯(HTTP 500)λ₯Ό ν΄λΌμ΄μΈνΈμ λ°ννκ² λ©λλ€.
1οΈβ£ μμΈ μ²λ¦¬ νλ¦.
1. μμΈ λ°μ.
- APIμ 컨νΈλ‘€λ¬λ μλΉμ€ λ μ΄μ΄μμ νΉμ λ‘μ§μ μννλ λμ€ μμΈκ° λ°μν μ μμ΅λλ€.
- μμΈκ° λ°μνλ©΄ μ€ν νλ¦μ΄ μμΈ μ²λ¦¬ λΈλ‘μΌλ‘ λμ΄κ°κ±°λ, μμΈκ° νΈμΆλ λ©μλλ₯Ό ν΅ν΄ μμλ‘ μ νλ©λλ€.
2. μμΈ μ ν.
- λ§μ½ ν΄λΉ μμΈλ₯Ό
try-catch
λΈλ‘ λ΄μμ μ²λ¦¬νμ§ μμΌλ©΄ μμΈλ νΈμΆλ λ©μλλ₯Ό λ°λΌ μμλ‘ μ νλ©λλ€. - μ΄ κ³Όμ μμ μ΅μ’ μ μΌλ‘ 컨νΈλ‘€λ¬ λ 벨μ΄λ κ·Έ μ΄μμμ μμΈλ₯Ό μ‘μ§ μμΌλ©΄, Spring Frameworkμ κ°μ λ°±μλ νλ μμν¬κ° μμΈλ₯Ό λ°μ μ²λ¦¬νκ² λ©λλ€.
3. Springμ κΈ°λ³Έ λμ.
- Spring MVCμμλ μμΈκ° μ νλμ΄ μ»¨νΈλ‘€λ¬κΉμ§ λλ¬νκ³ λ μ²λ¦¬λμ§ μμΌλ©΄, Springμ΄
DefaultHandlerExceptionResolver
λ₯Ό ν΅ν΄ κΈ°λ³Έμ μΈ μμΈ μ²λ¦¬λ₯Ό μνν©λλ€. - μ²λ¦¬λμ§ μμ μμΈλ κΈ°λ³Έμ μΌλ‘ HTTP μν μ½λ 500(λ΄λΆ μλ² μ€λ₯)λ‘ λ§€νλμ΄ ν΄λΌμ΄μΈνΈμ λ°νλ©λλ€.
- ν΄λΌμ΄μΈνΈλ μ΄ μν μ½λλ₯Ό ν΅ν΄ μλ²μμ μ€λ₯κ° λ°μνμμ μΈμνκ² λ©λλ€.
2οΈβ£ μμΈ μ²λ¦¬λ₯Ό μν λ°©λ².
1. @ExceptionHandler
μ¬μ©.
- Spring MVCμμλ 컨νΈλ‘€λ¬ λ 벨μμ μμΈλ₯Ό μ²λ¦¬νκΈ° μν΄
@ExceptionHandler
μ΄λ Έν μ΄μ μ μ¬μ©ν μ μμ΅λλ€. - νΉμ μμΈκ° λ°μνμ λ ν΄λΉ λ©μλκ° νΈμΆλμ΄ μμΈλ₯Ό μ²λ¦¬νκ³ , μ μ ν μλ΅μ ν΄λΌμ΄μΈνΈμκ² λ°νν μ μμ΅λλ€.
@RestController
public class MyController {
@GetMapping("/example")
public String example() {
if (someConditionFails()) {
throw new MyCustomException("Something went wrong!");
}
return "success";
}
@ExceptionHandler(MyCustomException.class)
public ResponseEntity<String> handleMyCustomException(MyCustomException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
}
μ΄ κ²½μ° MyCustomException
μ΄ λ°μνλ©΄ HTTP μν μ½λ 400κ³Ό ν¨κ» μμΈ λ©μμ§κ° λ°νλ©λλ€.
2. @ControllerAdvice
μ¬μ©.
-
@ControllerAdvice
λ μ μ μμΈ μ²λ¦¬κΈ°λ₯Ό μ μνλ λ° μ¬μ©λ©λλ€. - μ΄λ₯Ό ν΅ν΄ μ ν리μΌμ΄μ μ λ°μ λ°μνλ μμΈλ₯Ό μ€μμμ μ²λ¦¬ν μ μμ΅λλ€.
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MyCustomException.class)
public ResponseEntity<String> handleMyCustomException(MyCustomException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGeneralException(Exception ex) {
return new ResponseEntity<>("An unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
μ΄ κ²½μ° νΉμ μμΈλΏλ§ μλλΌ λͺ¨λ μΌλ°μ μΈ μμΈλ μ²λ¦¬ν μ μμ΅λλ€.
3. ResponseEntityμ ν¨κ» μμΈλ₯Ό λ°ν.
-
ResponseEntity
λ₯Ό μ¬μ©νμ¬ μ§μ μμΈ λ°μ μ HTTP μλ΅κ³Ό μν μ½λλ₯Ό λ°νν μλ μμ΅λλ€.
@GetMapping("/example")
public ResponseEntity<String> example() {
if (someConditionFails()) {
return new ResponseEntity<>("Custom error message", HttpStatus.BAD_REQUEST);
}
return new ResponseEntiry<>("success", HttpStatus.OK);
}
3οΈβ£ μ€μ μ½λ μ¬λ‘.
// UserUpdateRequest - DTO
public class UserUpdateRequest {
private long id;
private String name;
public long getId() {
return id;
}
public String getName() {
return name;
}
}
// UserController - Controller
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request) {
String sql = "UPDATE user SET name = ? WHERE id = ?";
jdbcTemplate.update(sql, request.getName(), request.getId());
}
@DeleteMapping("/user")
public void deleteUser(@RequestParam String name) {
String sql = "DELETE FROM user WHERE name = ?";
jdbcTemplate.update(sql, name);
}
1. λ¬Έμ μν©.
- μ μ½λμμμ λ¬Έμ μν©μ μλ μ μ λ₯Ό μ λ°μ΄νΈ νκ±°λ μμ νλ € ν΄λ 200 OKκ° λμ¨λ€λ μ μ λλ€.
2. ν΄κ²° λ°©μ.
- APIμμ μμΈλ₯Ό λμ 500 Internal Server Errorμ΄ λμ€κ² νλ©΄λ©λλ€.
@GetMapping("/user/error-test")
public void errorTest() {
throw new IllegalArgumentException();
}
- POSTMANμ νμ©νμ¬
http://localhost:8080/user/error-test
λ‘ GET νΈμΆμ 보λ΄λ©΄ 500 Internal Server Errorμ΄ λ°μν©λλ€.
4οΈβ£ νμ© μμ.
// UserUpdateRequest - DTO
public class UserUpdateRequest {
private long id;
private String name;
public long getId() {
return id;
}
public String getName() {
return name;
}
}
// UserController - Controller
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request) {
String readSql = "SELECT * FROM user WHERE id = ?";
boolean isUserExist = jdbcTemplate.query(readSql, (rs, rowNum) -> 0 request.getId()).isEmpty();
if (isUserNotExist) {
throw new IllegalArgumentException();
}
String sql = "UPDATE user SET name = ? WHERE id = ?";
jdbcTemplate.update(sql, request.getName(), request.getId());
}
@DeleteMapping("/user")
public void deleteUser(@RequestParam String name) {
String readSql = "SELECT * FROM user WHERE name = ?";
boolean isUserExist = jdbcTemplate.query(readSql (rs, rowNum) -> 0, name).isEmpty();
if (isUserNotExist) {
throw new IllegalArgumentException();
}
String sql = "DELETE FROM user WHERE name = ?";
jdbcTemplate.update(sql, name);
}
- μμ κ°μ΄ APIμμ λ°μ΄ν° μ‘΄μ¬ μ¬λΆλ₯Ό νμΈν΄ μμΈλ₯Ό λμ§λ©΄ λ©λλ€.
String readSql = "SELECT * FROM user WHERE id = ?";
- idλ₯Ό κΈ°μ€μΌλ‘ μ μ κ° μ‘΄μ¬νλμ§ νμΈνκΈ° μν΄ SELECT 쿼리λ₯Ό μμ±νμ΅λλ€.
boolean isUserExist = jdbcTemplate.query(readSql, (rs, rowNum) -> 0 request.getId()).isEmpty();
- SQLμ λ λ € DBμ λ°μ΄ν°κ° μλμ§ νμΈν©λλ€.
- SELECT SQLμ κ²°κ³Όκ° μμΌλ©΄ 0μΌλ‘ λ³νλ©λλ€.
- μ΅μ’
μ μΌλ‘ Listλ‘ λ°νλ©λλ€.
- μ¦, ν΄λΉ idλ₯Ό κ°μ§ μ μ κ° μμΌλ©΄ 0μ΄ λ΄κΈ΄ Listκ° λμ€κ³ , μλ€λ©΄ λΉ Listκ° λμ€κ² λ©λλ€.
- jdbcTemplate.query()μ κ²°κ³ΌμΈ Listκ° λΉμ΄μλ€λ©΄, μ μ κ° μλ€λ λ»μ λλ€.
if (isUserNotExist) {
throw new IllegalArgumentException();
}
- λ§μ½ μ μ κ° μ‘΄μ¬νμ§ μλλ€λ©΄ IllegalArgumentExceptionμ λμ§λλ€.