스프링MVC기반 RESTFul API 구현하기
REST 란?
도대체 REST가 뭐지? RESTful은 다른 건가? 소스를 보면 알겠는데, 개념을 정의한 내용을 보면 당췌 이해가 안간다.
그런데, 위키의 한줄 정의를 보는 순간 개념이 명확해진 느낌 이랄까?
"REST(Representational State Transfer)는 월드 와이드 웹과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식이다."(위키피디아 발췌)
REST는 특정 기술이라기 보다는 소프트웨어 아키텍처인 것이다.
그럼, 아키텍처는 또 뭐지? 일단 간단히 스펙, 명세, 요구사항이라고 이해하고 넘어가자.
어쨌든 좀더 쉽게 풀어 말하면 REST는 WWW상에서 다른 시스템과 연동을 위한 스펙을 나타내며, 그 스펙을 만족시킬수 있도록 구현되어 있다면 RESTful 하다고 말할수 있는것 같다.
REST 설계
그럼 REST 의 상세 스펙은 어떻게 될까? 여기서는 아주 심플하게 이해하자.
RESTFul 한 설계란 HTTP URI와 HTTP Method를 통해 자원을 관리할 수 있도록 하는것이다.
예를들어, 여기 인사정보 시스템이 있고, 우리는 그 시스템을 담당하고 있다고 가정해보자.
그런데 어느날 외부 시스템에서 인사정보에 접근 가능하도록 인터페이스 개발요구가 들어왔다.
정말 다양한 방법이 존재할것이다. DBtoDB, SOAP웹서비스 등등
하지만, 우리는 REST를 선택했고, 이제 RESTFul 하게 설계하고 스프링을 셋팅하고 샘플소스를 작성해 보도록 한다.
URI 설계
URI와 HTTP Method를 보면 어떤 작업을 할 수 있는 인터페이스 인지 감이온다. 뭔가 심플하고 직관적인 느낌이랄까? 보더라도 어떤 작업을 할수 있는 인터페이스인지 감이온다. 거기에 더해 HTTP Method를 보면 이 작업의 성격이 CRUD인지 명확해 진다.
Action | HTTP Method | URI |
사용자등록 | POST | http://0.0.0.0/emp |
사용자보기 | GET | http://0.0.0.0/emp/{1} |
사용자전체보기 | GET | http://0.0.0.0/emp |
사용자 수정 | PUT | http://0.0.0.0/emp/{1} |
사용자삭제 | DELETE | http://0.0.0.0/emp/{1} |
환경설정
- spring MVC 프로젝트 생성
- JSON 데이터 호출, 응답 가능하도록 pom.xml 에 jackson 라이브러리 추가
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
- servlet-context.xml 설정
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</beans:bean>
소스구현
URI 설계에 맞추어 컨트롤러내 메소드를 구현해 준다.
스프링 3.x 일때는 각 메소드마다 @ResponseBody 어노테이션을 붙여줘야 했으나,
스프링 4.x 부터는 컨트롤러 클래스에 @Controller 대신 @RestController만 붙여주면 된다.
사용자등록
@RequestMapping(value = "/rest/emp", method = RequestMethod.POST)
//스프링 3.x 방식
public @ResponseBody Employee createEmployee(@RequestBody Employee emp) {
//스프링 4.x 이전 방식
// public Employee createEmployee(@RequestBody Employee emp) {
empData.put(emp.getId(), emp);
return emp;
}
사용자보기
@RequestMapping(value = "/rest/emp/{id}", method = RequestMethod.GET)
//스프링 3.x 방식
public @ResponseBody Employee getEmployee(@PathVariable("id") int empId) {
//스프링 4.x 이전 방식
// public Employee getEmployee(@PathVariable("id") int empId) {
return empData.get(empId);
}
사용자목록
@RequestMapping(value = "/rest/emp", method = RequestMethod.GET)
//스프링 3.x 방식
public @ResponseBody List<Employee> getAllEmployees() {
//스프링 4.x 이전 방식
// public List<Employee> getAllEmployees() {
List<Employee> emps = new ArrayList<Employee>();
Set<Integer> empIdKeys = empData.keySet();
for(Integer i : empIdKeys){
emps.add(empData.get(i));
}
return emps;
}
사용자수정
@RequestMapping(value = "/rest/emp/{id}", method = RequestMethod.PUT)
//스프링 3.x 방식
public @ResponseBody Employee updateEmployee(@RequestBody Employee emp) {
//스프링 4.x 이전 방식
// public Employee updateEmployee(@RequestBody Employee emp) {
empData.replace(emp.getId(), emp);
return emp;
}
사용자삭제
@RequestMapping(value = "/rest/emp/{id}", method = RequestMethod.DELETE)
//스프링 4.x 방식
// public @ResponseBody Employee deleteEmployee(@PathVariable("id") int empId) {
//스프링 3.x 이전 방식
public Employee deleteEmployee(@PathVariable("id") int empId) {
Employee emp = empData.get(empId);
empData.remove(empId);
return emp;
}