티스토리 뷰

2) RestController를 이용하여 web api작성하기

web api 작성 실습

  • 앞에서 작성했던 Guestbook 프로젝트에다가 웹 API를 추가하겠습니다.
  • RestController 사용하려면 반드시 jackson 라이브러리 추가해야합니다. pom.xml을 확인하여 없다면 추가합니다.
  • RestController를 사용해보기 위해서 일단은 controller 패키지에다가 RestController를 생성합니다. 클래스 이름은 GuestbookApiController.java으로 생성합니다. 생성하면 어노테이션을 @RestController라고 붙여줍니다.
  • 그리고 해당 API 클래스 안에는 같은 매핑으로 여러 개를 수행하므로 이 클래스에 RequestMapping을 선언하면 클래스 안에 있는 것들을 다 공통으로 사용할 수가 있습니다. 그래서 RequestMapping "/" path를 지정해줍니다.

 

  • 여기서도 서비스 인터페이스가 사용되니까 서비스를 선언하고 @Autowired를 붙여줍니다. GuestbookService 이용할 거니까 guestbookService, 이렇게 선언을 합니다.
  • 첫 번째 메서드를 보면 @GetMapping 되어있는데 path는 따로 없습니다. 그 이유는 클래스에 RequestMapping이 붙어있기 때문입니다. path /guestbooks라고 시작을 하면서 Get 방식으로 요청이 들어오면 이 메서드를 실행할 겁니다. RequestMapping의 path URL로 요청이 들어오면서 Content-Type application/json, 그리고 Get 방식으로 요청이 들어오면 이 메서드가 실행됩니다. 그리고 이 메서드의 결과 값으로 Map 객체를 반환하고 있습니다.

 

  • application/json 요청이기 때문에 DipatcherServlet jsonMessageConvert를 내부적으로 사용해서 리턴하는 해당 Map 객체를 json으로 변환해서 전송을 하게 됩니다.
  • Post 방식의 요청은 @PostMapping 어노테이션이 붙어있는 write라는 메서드가 호출이 될 겁니다. 해당 결과는 Guestbook 객체로 반환하는데 이것도 json 메서드로 변환돼서 클라이언트한테는 갈 겁니다. 클라이언트한테 응답이 갈 때는 json으로 바뀌어서 간다는 것을 기억해야 합니다.

 

  • 마지막으로 delete 메서드는 @DeleteMapping 어노테이션을 갖고 있습니다. @DeleteMapping path 정보가 있어요 /guestbooks/id 형식으로 URL이 올 때 메서드가 호출됩니다. 이런 id 정보를 PathVariable이라고 했던 거 기억하시죠? 메서드의 인자를 보면 @pathVaialbe이라는 어노테이션으로 값을 읽어들이고 있는 것을 볼 수 있습니다. 해당 메서드가 성공하면 Map 객체를 생성하는데 키값은 "success"로 주고 값은 true false가 리턴이 됩니다.

 

  • 이렇게 작성한 Rest API가 잘 작동하는지 확인하기 위해서는 Rest API를 테스트하기 위한 클라이언트가 필요합니다. 이런 클라이언트는 다양한데 여기서는 크롬 브라우저의 Restlet Client라는 확장 프로그램을 사용하겠습니다. 크롬 웹스토어에서 Restlet Client를 찾아서 설치하면 쓸 수 있습니다.
  • Restlet Client를 실행해서 보면 Add라는 버튼을 클릭해서 Request에다가 원하는 이름을 써주시면 됩니다. 테스트를 위해 name에 입력합니다. 예를 들면 "방명록 조회 api" 하고 넣어줍니다.

 

  • 그리고 이제 실제 테스트해보기 위해서 메서드를 선택합니다. 원하는 메서드를 선택해서 들어갔을 때 제대로 동작이 되는지 확인합니다.
  • 우선 GET 메서드를 선택할 거고요. 그다음에 HEADERS - add하고 name 부분에다가 Content-Type이라고 지정을 하고 value에는 application/json 이라고 지정합니다. 그리고 테스트할 URL을 넣어주는데 지금은 http://localhost:8080/guestbook/guestbooks 라고 넣습니다.

 

  • 이렇게 설정을 하고 Send를 눌러서 실행해보면 하단의 Respone에 결과가 나오는 걸 볼 수 있습니다. 여기서는 list를 요청했기 때문에 이렇게 list가 보여집니다.

 

  • 수행할 때 URL 뒤에 파라미터로 ?start=5 이렇게 설정하고 Send 하면 아까와 결과 값이 달라지는 것을 알 수 있습니다.

 

  • 지금 여기에 나오는 데이터는 실제 데이터베이스의 guestbook select 했을 때 나오는 데이터와 같을 겁니다.
  • GetMapping 하는 부분이 테스트가 되셨다면 다음은 PostMapping을 테스트해보겠습니다.
  • PostMapping 할 때는 실제 입력할 guestbook의 정보를 넘겨야 합니다. 우선 메서드는 POST로 하고 URL은 같으니까 그냥 두고 Content-Type도 똑같겠죠. json 타입으로 올 거니까. 그리고 바디에다가 실제 입력할 값을 json 형태로 추가합니다. 그래야 테스트가 이루어집니다. name "강경미", content는 "잘되고계신가요?" 로 추가해보겠습니다.

 

  • Send 해서 테스트를 해보니까 200이 나오면서 성공했다고 메시지가 나오고 있습니다. 실제 db에서 select 해보면 id 10번인 "강경미"라는 데이터가 잘 들어가고 있는 것을 확인할 수가 있습니다.

 

  • 이번에는 삭제를 테스트해보겠습니다. 4 id를 삭제해겠습니다. 삭제는 DeleteMapping이므로 메서드를 DELETE로 바꾸시고 URL 뒤에다가 /4 를 붙여줍니다.

 

  • Send 하면 success: "true"가 리턴되고 있는 것을 확인할 수 있습니다.

 

  • 아래 화면이 해당 코드입니다. 이 부분이 잘 수행되고 넘어왔으면 실제 삭제가 됐으니까 deleteCount 1이 넘어왔을 거고 0보다 크니까 true를 리턴해줬겠죠. 리턴한 true를 가지고 Map을 만들어서 응답을 하고 있으니까 응답 결과가 true로 나타난 겁니다.

 

  • 이렇게 잘 응답되고 있는 것을 확인할 수 있습니다. mysql에서도 다시 select 해보면 4번 데이터가 삭제된 것까지 확인할 수 있습니다.

 

  • 이렇게 Rest Controller를 이용해서 웹 API를 이용하는 실습까지 진행을 해보았습니다.

실습코드

GuestbookApiController.java

package kr.or.connect.guestbook.controller;

 

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

 

import javax.servlet.http.HttpServletRequest;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.DeleteMapping;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

 

import kr.or.connect.guestbook.dto.Guestbook;

import kr.or.connect.guestbook.service.GuestbookService;

 

@RestController

@RequestMapping(path="/guestbooks")

public class GuestbookApiController {

           @Autowired

           GuestbookService guestbookService;

          

           @GetMapping

           public Map<String, Object> list(@RequestParam(name="start", required=false, defaultValue="0") int start) {

                     

                      List<Guestbook> list = guestbookService.getGuestbooks(start);

                     

                      int count = guestbookService.getCount();

                      int pageCount = count / GuestbookService.LIMIT;

                      if(count % GuestbookService.LIMIT > 0)

                                  pageCount++;

                     

                      List<Integer> pageStartList = new ArrayList<>();

                      for(int i = 0; i < pageCount; i++) {

                                  pageStartList.add(i * GuestbookService.LIMIT);

                      }

                     

                      Map<String, Object> map = new HashMap<>();

                      map.put("list", list);

                      map.put("count", count);

                      map.put("pageStartList", pageStartList);

                     

                      return map;

           }

          

           @PostMapping

           public Guestbook write(@RequestBody Guestbook guestbook,

                                                                   HttpServletRequest request) {

                      String clientIp = request.getRemoteAddr();

                      // id가 입력된 guestbook이 반환된다.

                      Guestbook resultGuestbook = guestbookService.addGuestbook(guestbook, clientIp);

                      return resultGuestbook;

           }

          

           @DeleteMapping("/{id}")

           public Map<String, String> delete(@PathVariable(name="id") Long id,

                                  HttpServletRequest request) {

                      String clientIp = request.getRemoteAddr();

                     

                      int deleteCount = guestbookService.deleteGuestbook(id, clientIp);

                      return Collections.singletonMap("success", deleteCount > 0 ? "true" : "false");

           }

}

 

생각해보기

  • Web API에게 POST방식으로 값을 전달할 때 JSON메시지를 보냈고, 결과도 JSON메시지를 출력하도록 하였습니다. JSON메시지를 자바객체로 변환하고, 자바객체를 반대로 JSON메시지로 변화하는 부분들이 모두 자동으로 이뤄지고 있는 것을 알 수 있었습니다. 만약 서블릿을 이용해 개발한다면, 이 부분들을 어떻게 구현해야 할까요?
  • 이를 통해 Spring MVC의 장점에 대해 생각해보세요.

참고 자료

[참고링크] Building a RESTful Web Service          https://spring.io/guides/gs/rest-service/

[참고링크] Building REST services with Spring           https://spring.io/guides/tutorials/bookmarks/

 

Comments