Spring boot로 ResponseEntity 적용하기

in #kr-dev7 years ago

지난시간 Swagger를 셋팅하고 난 뒤 이제 Controller를 개발하는데 집중을 하려고 생각을 하니 HTTP 스펙에 맞춰서 메시지 응답하는 환경이 필요해졌다. 왜 필요하냐고 질문하는 분들을 위해 잠깐 설명하는 시간 가져보자.

우리는 왜 Restful APIs를 만드는 것일까?

Ajax 통신을 통해 데이터를 주고 받기 위해서 만든다고 하면 80점 짜리 답변이다. Restful APIs를 만드는 가장 큰 이유는 Client Side를 정형화된 플랫폼이 아닌 모바일, PC, 어플리케이션 등 플렛폼에 제약을 두지 않는 것을 목표로 했기 때문이다.

이게 무슨 소리인지 조금 더 쉽게 설명하자면

2010년 이전만 해도 Server Side에서 데이터를 전달해주는 Client 프로그램의 대상이 명확했다. PC 브라우저가 그 대상이었다. 그렇다보니 그냥 JSP나 ASP, PHP 등을 이용한 웹페이지를 구성하고 작업을 진행하면 됐다. 하지만 스마트 기기들이 등장하면서 TV, 스마트 폰, 테블릿 등 Client 프로그램이 다양화 되고 그에 맞춰서 Server Side를 일일이 만드는 것이 꽤 비효율적인 일이 되었다.

이런 과정에서 개발자들은 Client Side를 전혀 고려하지 않고 메시지 기반, XML, JSON과 같은 Client에서 바로 객체로 치환 가능한 형태의 데이터 통신을 지향하게 되면서 Server와 Client의 역할을 분리하게 되었다.

이런 변화를 겪으면서 필요해진 것은 HTTP의 표준 규약을 지켜서 API를 만드는 것이다.

이 Restful APIs를 개발하다보면 HTTP의 Response 규약을 지키지 않고 본인들이 만들어넨 JSON 컨벤션으로 응답하는 경우를 많이 확인할 수 있는데 그것은 옳지 않은 개발 방향이다. 왜냐하면 아까도 이야기 했듯 Client Side가 정형화되어있지 않은 환경에서 개발속도를 저하하는 가장 큰 이유는 표준을 지키지 않아서다. 그 표준을 지키지 않게 되었을 때 발생하는 가장 큰 이슈는 HTTPStatus 코드를 제대로 응답하지 않게되는 것이고 이런 경우 클라이언트에서는 별도의 방어코드를 짜 넣는 수고가 발생하고 이런 수고들이 모여 프로젝트의 속도를 저하시키는 요소로 동작하게 된다. 그렇기 때문에 표준을 준수하는 것이 중요하다.

그래서 오늘은 위와 같은 장황한 이유 때문에 Spring에서 제공하는 ResponseEntity 객체를 이용해 규약에 맞는 HTTP Response를 개발해 보겠다.

지난번에 만든 HelloWorld 메서드를 확인해보자.

다운로드 (21).png

중간에 String 으로 반환한다고 하는 저 빨간 사각형은 HTTPStatus Code를 그저 200("Success"를 의미하는 코드)으로 응답해주고 ResponseBody(응답 본문)에는 그저 문자로 채워서 내보내는 역할만 할 뿐이다. 하지만 실제 서비스에서는 200뿐 아니라 401(권한없음)이나 500대 에러(Server Side에서 발생하는 오류들은 500번대 에러들이다)들도 반환할 수 있어야한다.

자, 패키지와 클래스를 한번 만들어보도록 하자.

이미 몇 번 만들어봤으니까 따로 만드는 법은 패스. 패키지 명은 "com.example.sample.model" 이고 클래스 명은 "ApiResponseMessage"라고 하겠다.

아참, 클래스를 만들기 전에 우리는 STS에 lombok 플러그인을 설치했다고 가정하고 아래의 코드를 진행한다. pom.xml에 아래의 라이브러리를 Dependency로 추가하도록 하자.

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

이렇게 라이브러리를 준비했다면 이제 ApiResponseMessage 클래스를 아래와 같이 작성해보도록 하자.

package com.example.sample.model;
 
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
 
@Setter
@Getter
@ToString
public class ApiResponseMessage {
     // HttpStatus
    private String status;
    // Http Default Message
    private String message;
    // Error Message to USER
    private String errorMessage;
    // Error Code
    private String errorCode;
 
    public ApiResponseMessage() {}
 
    public ApiResponseMessage(String status, String message, String errorCode, String errorMessage) {
        this.status = status;
        this.message = message;
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }
}

이렇게 작업했다면 일단 초벌작업은 마무리되었다. 아, 방금 추가한 lombok 프레임워크에 대해서 이야기를 추가하자면 클래스 상단에 @Setter, @Getter, @ToString 어노테이션을 붙이면 컴파일 단계에서 Setter와 Getter, ToString메서드를 자동으로 생성한다. 클래스 안에 코드를 작성하지 않았어도 lombok은 알아서 만들어 동작하게 한다. 이 lombok 프레임워크는 코드를 깔끔하게 만들어주고 유지보수를 간편하게 한다.(완전 좋다!)

이 작업까지 마무리 했다면 전에 작업했던 HelloWorld 메서드를 찾아서 아래의 코드로 바꿔보도록 하자.

package com.example.sample.controller;
 
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
 
import com.example.sample.model.ApiResponseMessage;
 
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
 
@RestController
@Api(value = "HelloController", description = "헬로 에이피아이")
public class HelloController {
 
    @RequestMapping(value="/hello", method= RequestMethod.GET)
    @ApiOperation(value="hello, World API", notes="hello, World를 반환하는 API, Ajax 통신 확인용.")
    public ResponseEntity<ApiResponseMessage> helloWorld() {
        ApiResponseMessage message = new ApiResponseMessage("Success", "Hello, World", "", "");
         
        return new ResponseEntity<ApiResponseMessage>(message, HttpStatus.OK);
    }
}

이 작업까지 했다면 서버를 띄워서 응답 메시지를 확인해보도록 하자.

다운로드 (6).jpg

다운로드 (7).jpg

이런 성공 메시지를 확인할 수 있다. 그렇다면 에러 코드를 발생시키면 어떻게 될까?

코드를 아래와 같이 수정해보자.

@RequestMapping(value="/hello", method= RequestMethod.GET)
@ApiOperation(value="hello, World API", notes="hello, World를 반환하는 API, Ajax 통신 확인용.")
public ResponseEntity<ApiResponseMessage> helloWorld() {
    ApiResponseMessage message = new ApiResponseMessage("Authentification Error", "Hello, World", "", "");
     
    return new ResponseEntity<ApiResponseMessage>(message, HttpStatus.UNAUTHORIZED);
}

이렇게 수정한 뒤에 서버를 재시작해보자. 그리고 다시 접속해보자.

다운로드 (8).jpg

다운로드 (9).jpg

이렇게 에러 코드를 뱉어내고 원하는 메시지를 확인할 수 있게 된다.

본격적인 작업을 하기에 앞서서 Controller 영역은 작업을 대충(?) 마무리 지었다. 이제 다음 시간부터 DB와 JPA에 대해서 배워보도록 하자.

오늘은 여기까지.

Sort:  

오늘 올린글들을 잘 읽어봤어요.
그런데 아쉬운점은 1일 1포스팅 하셨으면 더 나았을 것 같아요.
한번에 많은 내용을 포스팅 하면 오히려 관심을 갖고 보팅해줄려는 사람도 여러글중에 하나밖에 안해드려요.
보팅의 한계때문에 하나씩 포스팅하는게 글쓰는분도 아이템 고갈도 느리고 꾸준히 포스팅할 수 있고 보팅도 분산안되고 좋아요.
포스팅이 맘에 들어도 오늘 포스팅 글들을 전부다 보팅해줄 수 없으니깐요.
꾸준히 1일 1포스팅으로 아이템을 정했으면 그 방향으로 나아가는게 가장 이상적일거에요

조언 감사합니다!! 몰랐던 내용이네요!
다운로드 (10).jpg