BackEnd 개발자라면 게다가 웹 개발자거나 Spring 개발자라면 적어도 한 번 이상,
아니 너무나 익숙하게 많이 들었을 것이다.
RESTful 하다는 게 대체 뭘까?
RESTful : REST API 의 설계 의도를 명확하게 지킴으로써, 각 구성 요소들의 역할이 확실하게 분리 되어 있어서, URI만 보더라도 리소스를 명확하게 인식 할 수 있도록 표현 한 설계 방식을 의미. 또한, 각 리소스에 대한 기능을 HTTP 메소드 (POST, GET, PUT, DELETE 등)를 이용하여 일관되게 정의할 수 있어야 한다.
음... 🤔 어렵다. 그쵸?
개발자는 코드를 보면서 이해하는 것이 가장 빠르다.
실무에서 첫 API를 설계할 때, 아래와 같이 URI를 작성한 적이 있었다.
그리고 팀장님은 그런 나를 보시며 "RESTful 하다는거 글로 배웠죠 허허허 😊 " 라고 웃으며 말씀하셨다.
우리 팀장님 너무 좋으신 분이다. 안 혼내시고 인자하게 웃으시면서 말씀하신다. 하지만 팩트로 뼈를 퍽퍽
어떤 부분이 잘못되었을지 한번 봐보시라.
아, 예제 코드는 👉🏻 JPA를 사용한 카테고리 구현 시리즈에서 사용한 것을 가지고 왔다.
@PostMapping ("/category/save") @ResponseBody public Long saveCategory (CategoryDTO categoryDTO) { return categoryService.saveCategory(categoryDTO); } @GetMapping ("/category/get/{branch}") @ResponseBody public CategoryReturnDto getCategoryByBranch (@PathVariable String branch) { return categoryService.getCategoryByBranch(branch); } @PutMapping ("/category/update/{branch}/{code}") @ResponseBody public Long updateCategory (@PathVariable (name = "branch") @NotBlank String branch, @PathVariable (name = "code") @NotBlank String code, CategoryDTO categoryDTO) { return categoryService.updateCategory(branch, code,categoryDTO); } @DeleteMapping ("/category/delete/{branch}/{code}") @ResponseBody public void deleteCategory (@PathVariable (name = "branch") @NotBlank String branch, @PathVariable (name = "code") @NotBlank String code) { categoryService.deleteCategory(branch, code); }
주목해서 봐야할 부분은 각각의 매핑 어노테이션에서 URI부분이다.
뭐가 잘못되었을까? 크게는 두가지다.
HTTP 메소드에서 정의 되어 있다.위의 메소드들은 각각의 기능들이 이미 HTTP 메소드를 통해 정의 되어있다.
저장하는 기능이면 POST, 정보를 얻어 오는 것이면 GET, 정보를 수정하는 것이면 PUT, 삭제하는거면 DELETE.
그러므로 굳이 URI에 각각의 기능을 중복해서 적어줄 필요가 없다.
즉, 위의 RESTful의 정의에서 "각 리소스에 대한 기능을 HTTP 메소드 (POST, GET, PUT, DELETE 등)를 이용하여 일관되게 정의할 수 있어야 한다." 의 의미가 이런 의미다.
Category 객체를 URI에 명시하여 이 API를 통해서 Category라는 객체를 관리할 것이라는 것을 알려줬다.
그러면, 관례적으로 객체명을 복수로 써 주는 것이 좋다.
@PostMapping ("/categories") @ResponseBody public Long saveCategory (CategoryDTO categoryDTO) { return categoryService.saveCategory(categoryDTO); } @GetMapping ("/categories/{branch}") @ResponseBody public CategoryReturnDto getCategoryByBranch (@PathVariable String branch) { return categoryService.getCategoryByBranch(branch); } @PutMapping ("/categories/{branch}/{code}") @ResponseBody public Long updateCategory (@PathVariable (name = "branch") @NotBlank String branch, @PathVariable (name = "code") @NotBlank String code, CategoryDTO categoryDTO) { return categoryService.updateCategory(branch, code,categoryDTO); } @DeleteMapping ("/categories/{branch}/{code}") @ResponseBody public void deleteCategory (@PathVariable (name = "branch") @NotBlank String branch, @PathVariable (name = "code") @NotBlank String code) { categoryService.deleteCategory(branch, code); }
RESTful한 API로 변경했다. 예제에는 적용되지 않았지만 사실 RESTful하다는 의미를 충족시키기 위해서 여러가지 기준들이 있다.
팀장님 말씀에 의하면, 사실 기준이 다 다르고 누군가 확실하게 정의해 놓은 것이 없기 때문에 이걸 제대로 안한다고 해서 코드가 안돌아가는 것도 아니라고 하셨다. 욕은 먹을 수 있다.
RESTful의 가장 중요한 건, URI의 명확한 정의를 통해 실무에서 API사용에 있어서 원할한 소통이 가능해야 한다는 것이다.
그 밖의 규칙들은 다음과 같다.
URI를 표시할 때 계층들의 관계는 '/' 를 통해서 구분 해야한다.RESTful한 API는 가독성이 좋아야 하며, 보기만해도 어떤 의미인지 직관적으로 알 수 있어야 한다. 동사, 즉 메소드를 통한 어떠한 행위는 HTTP METHOD를 통해서 충분히 어필이 되기 때문에 굳이 URI에 써줄 필요가 없다. hwp는 우리나라에서만 사용하는 확장자다. 나는 한글파일이 무척 싫다. 싫어 너무
가령 URI에 minjae.com/board/zzang.hwp로 되어 있다고 생각해보자. 우리나라 사람은 이게 뭔지 알겠지만, 외국인들은 하고 지나갈 것이다. shit
다시 강조하지만, RESTful 하다는 것은, URI만 보고도 어떤 의미인지 직관적으로 알 수 있는 것이다.
사실, 더 깊게 들어가면 더 할 이야기가 많다.
이번 포스팅을 통해서 강조하고 싶은 것은 이거다.
RESTful 하다는 것은, 결국 소통이 원할한 API를 구성하는 것.
개발자들에게는 코딩실력만큼 중요한건 소통이다. 💬
이 글을 읽는 모든 개발자가 소통도 짱짱 잘하는 좋은 개발자가 되시길 진심으로 빈다. 나도..