[리팩토링] HTTP Form 횐경에서 RESTful 설계
[리팩토링] HTTP Form 횐경에서 RESTful 설계
계기
출퇴근하며 김영한 선생님의 HTTP 강의를 듣던 중, 좋은 URI 설계 개념을 배우게 되었고 개인 프로젝트에도 적용해보고자 리팩토링을 진행했습니다.
기존 코드의 문제점
상품 컨트롤러
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@GetMapping("/productMain")
public String productMain() { ... }
@GetMapping("/product/new")
public String newProduct(...) { ... }
@PostMapping("/product/new")
public String createProduct(...) { ... }
@PutMapping("/product/{id}")
public String updateProduct(...) { ... }
@DeleteMapping("/product/{id}")
public String deleteProduct(...) { ... }
문제점:
- URL이 리소스 중심이 아닌 기능 중심으로 설계됨
- 단수형/복수형이 혼재 (product vs productMain)
- HTML Form 에서 PUT, DELETE 메서드를 지원하지 않음 (처음 알게 되었다…)
사용자 컨트롤러
1
2
3
4
5
6
7
8
9
10
11
@GetMapping("/users/new")
public String register(...) { ... }
@PostMapping("/users")
public String registerUser(...) { ... }
@PutMapping("/users/{id}")
public String updateUser(...) { ... }
@DeleteMapping("/users/{id}")
public String deleteUser(...) { ... }
문제점:
- 대소문자 혼용으로 일관성 부족 (UserRegisterSuccess)
/users가 목록과 등록을 모두 처리- 리소스 중심이 아닌 기능 중심 URL 구조
리팩토링 원칙
- URL을 리소스(명사) 중심으로 설계:
/users,/products - HTML Form 제약 고려: POST로 PUT/DELETE 대체
- 행위를 명확히 분리:
new(등록),edit(수정),delete(삭제)
리팩토링 결과
상품 컨트롤러
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 목록 조회
@GetMapping("/products")
public String productList(Model model) {
model.addAttribute("products", productService.findAllWithImages());
return "products/productList";
}
// 등록 폼
@GetMapping("/products/new")
public String newProduct(@AuthenticationPrincipal AuthUser authUser, Model model) {
return "products/new";
}
// 등록 처리
@PostMapping("/products/new")
public String createProduct(ProductRegistrationRequest request, ...) {
return "redirect:/products/success";
}
// 수정 폼
@GetMapping("/products/{id}/edit")
public String editProduct(@PathVariable Long id, Model model) {
return "products/edit";
}
// 수정 처리
@PostMapping("/products/{id}/edit")
public String updateProduct(@PathVariable Long id, ...) {
return "redirect:/products/my";
}
// 삭제 처리
@PostMapping("/products/{id}/delete")
public String deleteProduct(@PathVariable Long id, ...) {
return "redirect:/products/my";
}
사용자 컨트롤러
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 사용자 목록
@GetMapping("/users")
public String userList(Model model) {
model.addAttribute("users", userService.findAllUsers());
return "users/userList";
}
// 등록 폼
@GetMapping("/users/new")
public String register(Model model) {
return "users/new";
}
// 등록 처리
@PostMapping("/users/new")
public String registerUser(@Valid @ModelAttribute("user") UserRegistrationRequest request, ...) {
userService.registerUser(request);
return "redirect:/userSuccess";
}
// 수정 폼
@GetMapping("/users/{id}/edit")
public String userUpdate(@PathVariable Long id, Model model) {
return "users/edit";
}
// 수정 처리
@PostMapping("/users/{id}/edit")
public String userUpdateProc(@PathVariable Long id, ...) {
userService.updateUser(id, request);
return "redirect:/users";
}
// 삭제 처리
@PostMapping("/users/{id}/delete")
public String userDelete(@PathVariable Long id, ...) {
userService.deleteUser(id);
return "redirect:/";
}
주요 개선 사항
1. URL 복수형 통일
/product/...→/products/...- RESTful 설계 원칙에 따라 리소스는 복수형으로 표현
2. HTML Form 제약 대응
- HTML Form은 GET/POST만 지원
/edit,/delete경로로 구분하여 POST 요청 처리
3. 뷰 경로 구조 정리
- URL과 템플릿 폴더 구조 일치
/products/new→templates/products/new.html
4. 의미 중심 URL 설계
/products- 전체 상품 목록/products/my- 내 상품 목록/products/new- 새 상품 등록/products/{id}/edit- 상품 수정
배운 점
- HTML Form 환경에서도 RESTful 설계 가능
- 리소스 중심 사고의 중요성: 기능이 아닌 리소스를 중심으로 URL 설계
- 일관성의 가치: 모두가 이해하기 쉬운 일관된 규칙 적용
- 리팩토링의 어려움: 처음부터 잘 설계하는 것보다 기존 코드를 수정하는 것이 더 어렵다는 것을 체감..
작은 개선이지만 프로젝트의 유지보수성과 가독성이 크게 향상되었습니다. 좋은 설계 원칙을 배우고 적용해보는 것의 중요성을 다시 한번 느꼈습니다.
참고
This post is licensed under
CC BY 4.0
by the author.