Spring Rest API Server의 Response 데이터 포맷, 어떻게 하는게 좋을까요?

2015-03-19 11:18

Android, IOS 어플리케이션 서비스를 위해 Spring Framework를 이용한 REST API Server를 만들고 있습니다.

예전에 네이버에서 제공해주는 Open API의 JSON 형태를 보니, {code="404", result="Not Found", data=""}와 같았습니다.

저또한 혼자 사용하는 API 서버를 만들지만, 위와같은 형태에 대해 고민하게 되어 이렇게 질문을 올립니다.

(1) Http Response의 헤더에 code, result에 대한 데이터를 담을 수 있는데 굳이 이렇게 하는 이유는 무엇일까요?

  • 모든 서버응답에 대한 데이터포맷을 위와 같이 만들면, 확장이나 일관성 측면에서 어떤 이점이 생길까요?

  • 일반적으로 Spring과 같은 Framework를 사용할경우 내부적으로 지정된 기본값으로 처리할거라 생각되는데 이 과정에서 개발자가 예상하지 못한 형태로 전달될 수 있어서 그럴까요?
  • 위와 같은 데이터포맷을 만드는 이유가 code영역을 Http 응답코드에 기본적인 항목(200, 302, 404, 500)을 사용하는게 아닌 201, 202, 401 등으로 좀 더 세세하게 나누고자 하는 의도일까요?

(2) 만약, 위와같은 포맷형태를 Spring MVC Framework로 구현한다고 할 경우에 대한 질문입니다.

  • 만약 단순하게 (200, 302, 404, 500)과 같은 프레임워크가 기본적으로 사용하는 응답코드라면 AOP나 Interceptor를 이용해 모든 응답을 {code="401", result="Not Permitted", data=""} 형태의 JSON으로 변환해주게끔 구현할것 같습니다. 그렇게 된다면 프로그래머는 반환되는 data의 영역만 신경쓰면 될것 같은데, controller의 메서드 하나로 예를 든다면 아래의 코드가 클라이언트에게 전달될때는 {code="200", result="OK", data="aaa"} 와 같이 변환되겠지요.

    @RequestMapping("/test")
    public String test() {
       return "aaa";
    }
    

하지만 201, 202, 401과 같은형태의 좀 더 세부적인 응답코드를 반환해야 한다면, 각 컨트롤러 메서드마다 Http Header를 지정하기 위한 객체를 파라미터에 선언하고, 반환코드를 일일이 지정해주는 한가지 방법이 떠오르고, 두번째는 AOP 및 Interceptor에서 데이터포맷을 지정하는게 아닌 아래와 같은 형태로 매 Controller Return 객체를 만들어 주어야 할 것 같습니다.

@RequestMapping("/test")
public ReturnData test() {
   return  new ReturnData<String>("aaa");
}


class ReturnData<T> {
		int code = 200;
		String result = getResult(code);
		T data;
		
		public ReturnData(int code, String result, T data) {
			this.code = code;
			this.result = result;
			this.data = data;
		}
		
		public ReturnData(T data) {
			this.data = data;
		}
		
		private String getResult(int code) {
			switch (code) {
			case 200:
				return "OK";
			//	....
		}
	}

먼저 굳이 세세하게 응답코드를 나눠야 하는가? 는 저도 잘 모르겠습니다. 하지만 클라이언트와 통신을 할때 요청에 대한 새로운 데이터를 정상적으로 생성했는지, 요청은 잘 전달받았지만 생성에는 실패했는지 (물론 서버에서는 Exception을 강제로 발생시켜 500에러를 리턴할 수 있겠지요) 등 좀더 효율적으로 사용할 수 있을텐데, 그렇게 사용하기 위해 응답코드를 조금씩은 구분지었을텐데라고 생각이 들어서요.

여러분들은 어떻게 생각하시나요?

3개의 의견 from SLiPP

2015-03-24 11:56

계정이 Facebook과 연동이 안되있어서, 따로 의견추가합니다.

Facebook을 통해서 받은 답변내용은 다음과 같습니다.

  1. 개인적으로 안좋아하는 방식입니다. 굳이 똑같은 코드를 사용하는데 json에 그걸 포함할 이유가 없어보이네요. 에러를 표현하고 싶으면 Rest에 해당하는 status 코드는 헤더에 넣고, 어플리케이션에서 사용되는 에러코드와 메세지는 json에 넣는게 좋아보이네요. 더 세세하게 나누려면 차라리 HTTP status 코드 범위는 피하고 그 상위 코드를 사용하는게 더 좋아보입니다. 저렇게 하면 204를 표현할 방법이 없습니다..

-> 그렇다면 제가 본 JSON의 code라는건 Http 상태코드가 아니라 어플리케이션에서 사용하는 코드일 가능성도 있겠군요. 답변 감사드립니다.

  1. ResponseEntity를 찾아보세요... http://docs.spring.io/.../spring.../http/ResponseEntity.html -> 매 컨트롤러 메서드마다 선언해야 하기 때문에 제가 찾던 방식은 아니였습니다. Controller에 불필요한 코드가 추가됩니다. Controller와 View 표현의 객체간 커플링이 발생합니다.

구글링을 통해 원하는 가이드라인을 찾을 수 있었습니다.

https://stormpath.com/blog/spring-mvc-rest-exception-handling-best-practices-part-1/

-> 설명도 명료하고 예제소스를 통해 제가 궁금했던 내용이 해결됬습니다. 각각의 레이어에 영향을 주지 않으면서, RuntimeException의 객체종류를 통해서 원하는 형태로 Customizing이 가능하다는걸 알게되었습니다.

2015-03-24 12:08

@한석봉 나도 답변을 달까하다가 망설였다. 내 개인적으로도 코드를 포함하는 방식은 그리 좋아하지 않는다.

좋은 코드를 구현하려면 좋은 코드를 많이 읽어야 하듯이 좋은 api를 설계하려면 좋은 api를 읽어보면 많은 연습이 되더라. facebook, google에서 수 많은 api들 제공하고 있으니 이 쪽 api 참고해 보면 좋겠다.

의견 추가하기

연관태그

← 목록으로