[ 기본 개념 ]

@RestController

Spring MVC 에서 특정 클래스에 @RestController 를 추가하면 해당 클래스가 REST API 리소스를 처리하기 위한 API 엔드포인트로 동작함을 정의합니다.

그리고 해당 애노테이션이 추가된 클래스는 애플리케이션 로딩 시, Spring Bean 으로 등록해줍니다.

 

 

 

@RequestMapping

클라이언트의 요청과 그 요청을 처리하는 핸들러 메서드를 매핑해주는 역할을 합니다.

예를 들어, RequsetMapping("v1/member") 을 하게 된다면 괄호 안에 있는 코드는 Controller 클래스 레벨에 추가하여 클래스 전체에 사용되는 공통 URL 설정을 하게 됩니다. 이러한 메서드를 핸들러 메서드라고 부릅니다.

 

 

 

@RequestMapping(value, produces)

[produces]
해당 속성은 응답 데이터를 어떤 미디어 타입으로 클라이언트에게 전송할 지를 설정합니다.
JSON 형식의 데이터를 응답 데이터로 전송하겠다는 의미로는
MediaType.APPLICATION_JSON_VALUE 로 값을 설정할 수 있습니다.
이 설정을 하지않는다면 JSON 형식이 아닌, 문자열 자체를 전송하게 됩니다.

 

 

 

@PostMapping

클라이언트 요청 데이터를 서버에 생성할 때 사용하는 애너테이션입니다.

주로 회원 정보를 등록해주는 역할을 해줍니다.



 

@RequsetParam

핸들러 메서드의 피라미터 종류 중 하나입니다.

주로 클라이언트쪽에서 전송하는 요청 데이터를 [ 쿼리 피라미터, 폼 데이터, x-www-form-urlencoded 형식 ] 으로 전송하면

이를 서버쪽에서 전달 받을 때 사용하는 애너테이션입니다.

 

 

* 쿼리 피라미터

요청 URL 에서 "?" 를 기준으로 붙는 key/value 쌍의 데이터를 말합니다.

 

- 예시
http://localhost:8080/coffees/1?page=1&size=10

 

 

* 리턴 값

postMapping 애노테이션 메서드의 리턴 타입이 String 인 경우에는,

클라이언트 쪽에서 JSON 형식의 데이터를 전송 받아야 하기 때문에, 응답 문자열을 JSON 형식에 맞게 작성해줘야합니다.

 

일반적으로 POST Method 를 처리하는 핸들러 메서드는 데이터를 생성한 후에 클라이언트 쪽에서 생성한 데이터를 리턴해주는 것이 관례입니다.

 

 

 

@GetMapping

클라이언트가 서버에 리소스를 조회할 때 사용하는 애너테이션입니다.

주로 회원 정보를 클라이언트쪽에서 제공할 때 사용하는 메서드입니다.

 

- 예시
/v1/members/{member-id} 의 경우,
member-id 는 회원 식별자를 의미하며 클라이언트가 요청을 보낼 때 URI 로 어떤 값을 지정하느냐에 따라서 동적으로 바뀌는 값입니다.

 

 

@PathVariable

핸들러 피라미터 종류 중 하나입니다.

괄호 안에 입력한 문자열 값은 중괄호 안의 문자열과 동일해야합니다.

다를 경우 MssingPathVariableException 이 발생합니다.

[예시]
@GetMapping("/{member-id}")
public String getMember(@PathVariable("member-id") long memberId){ ~~ }

 

 

 

 

JSON 형식의 응답 문자열을 수작업으로 작성하는 경우를 개선하는 방법

[ 기존 코드와 차이점 ]

1. produce 설정 제거

 

 

2. map 객체로 생성

Map 객체를 리턴해주게 되면 내부적으로 이 데이터는 JSON 형식의 응답 데이터로 변환해야 되는 거구나를 인지하게 됩니다.

그래서 자동으로 JSON 형식으로 변환하게 됩니다.

 

 

3) return value 를 ResponseEntity 객체로 변경합니다.

사실 리턴값을 Map 객체로 리턴해도 JSON 응답 데이터를 받을 수 있습니다.

하지만 ResponseEntity 를 사용하게 될 경우 응답 데이터를 래핑함으로써 응답 상태를 명시적으로 함께 전달 할 수 있다는 장점이 있습니다.

 

- 예시
return new ResponseEntity<>(map, Httpstatus.CREATE);
or
return new ResponseEntity<>(HttpStatus.OK);

* HttpStatus.CREATE 는 클라이언트의 POST 요청을 처리해서 요청 데이터가 정상적으로 생성되었음을 의미하는 HTTP 응답 상태입니다. ( 응답 상태 문서 : https://developer.mozilla.org/ko/docs/Web/HTTP/Status )

 

 

 

 

HTTP 헤더

HTTP 메시지의 구성 요소 중 하나로써 클라이언트 요청이나 서버의 응답에 포함되어 부가적인 정보를 HTTP 메시지에 포함할 수 있도록 해줍니다.

 

[ 사용 목적 ]

 

  • 클라이언트와 서버 관점에서의 대표적인 HTTP 헤더 예시

클라이언트와 서버 관점에서 내부적으로 가장 많이 사용되는 헤더 정보로는 "Content-Type" 이 있습니다.

클라이언트와 서버가 HTTP 메시지 바디의 데이터 형식이 무엇인지를 알려주는 역할을 합니다.

 

그래서 클라이언트와 서버는 Content-Type 이 명시된 데이터 형식에 맞는 데이터를 주고 받는 것입니다.

 

 

  • 개발자들이 직접 실무에서 사용하는 대표적인 HTTP 헤더 예시

사실 개발자들이 직접 HTTP 헤더를 건드릴 일은 없습니다.

하지만 코드 레벨에서 컨트롤해야 하는 경우가 있는데 이런 경우의 대표적인 예시 두가지를 보겠습니다.

 

1. Authorization

이는 클라이언트가 적절한 자격 증명을 가지고 있는지를 확인하기 위한 정보입니다.

일반적으로 REST API 기반 애플리케이션의 경우 클라이언트와 서버간의 로그인 인증에 통과한 클라이언트들은

"Authorization" 헤더 정보를 기준으로 인증에 통과한 클라이언트가 맞는지 확인하는 절차를 가집니다.

 

 

2. User-Agent

여러 유형의 클라이언트가 하나의 서버 애플리케이션에 요청을 전송하는 경우가 많습니다.

어떤 사용자는 데스크탑 웹 브라우저에서 서버에 요청을 보내고, 또 다른 사람은 스마트폰에서 요청을 보냅니다.

이런 경우 들어오는 요청을 구분해서 응답 데이터를 다르게 보내줘야 되는 경우가 있습니다.

예를 들어, 데스크탑 브라우저에서는 더 큰 화면인만큼 더 많은 정보를 보여줍니다.

이 경우, "User-Agent" 정보를 통해서 구분할 수 있습니다.

 

 

 

HTTP Request 헤더 정보 얻기

  • @RequestHeader("user-agent") : 특정 헤더 정보만 읽는 예제입니다.
  • HttpServletRequest 객체 : Request 헤더 정보에 다양한 방법으로 접근이 가능합니다.
  • HttpEntity 객체 : Request 헤더와 바디 정보를 래핑하고 있으며, 조금 더 쉽게 헤더와 바디에 접근할 수 있습니다.

* HttpEntity 객체

Entry 를 통해 각각의 헤더 정보에 접근할 수 있는데, 특이한 것은 자주 사용될만한 헤더 정보들은 get() 으로 가져올 수 있습니다.

 

 

 

HTTP Response 헤더 정보 추가

  • ResponseEntity 와 HttpHeaders 를 이용해 헤더 정보 추가하기
@RestController
@RequestMapping(path = "/v1/members")
public class MemberController{
    @PostMapping
    public ResponseEntity postMember(@RequestParam("email") String email,
                                     @RequestParam("name") String name,
                                     @RequestParam("phone") String phone) {
        // (1) 위치 정보를 헤더에 추가
        HttpHeaders headers = new HttpHeaders();
        headers.set("Client-Geo-Location", "Korea,Seoul");

        return new ResponseEntity<>(new Member(email, name, phone), headers,
                HttpStatus.CREATED);
    }
}

 

 

 

 

RestClient

REST API 서버에 HTTP 요청을 보낼 수 있는 클라이언트 툴 또는 라이브러리를 의미합니다.

Postman 은 UI 가 갖춰진 RestClient 라고 볼 수 있습니다.

 

- Client : 서버쪽의 리소스를 이용하는 쪽

 

* 그래서 [ 어떤 서버가 HTTP 통신을 통해서 다른 서버의 리소스를 이용한다면 그 때만큼은 클라이언트의 역할을 합니다. ]

위의 그림에서는 웹 브라우저가 클라이언트가 됩니다.

 

 

 

RestTemplate

Java 에서 사용할 수 있는 다양한 HTTP Client 라이브러리가 있습니다. ( HttpURLConnection, OkHttp 3, Netty 등 )

Spring 에서는 이 HTTP Client 라이브러리 중 하나를 이용해 다른 백엔스 서버에 HTTP 요청을 보낼 수 있는 REST Client API 를 제공하는데, 이를 RestTemplate 라고 합니다.

 

이 템플릿을 이용하면 Rest EndPoint 지정, 헤더 설정, 피라미터 및 바디 설정을 한 줄의 코드로 쉽게 할 수 있습니다.

 

[ URI 생성 ]

import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

public class RestClientExample01 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate =
                new RestTemplate(new HttpComponentsClientHttpRequestFactory());

        // (2) URI 생성
        UriComponents uriComponents =
                UriComponentsBuilder
                        .newInstance()
                        .scheme("http")
                        .host("worldtimeapi.org")
//                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();
    }
}
[ 설명 ]
newInstance(): UriComponentsBuilder 객체를 생성합니다.
scheme(): URI의 scheme을 설정합니다.
host(): 호스트 정보를 입력합니다.
port(): 디폴트 값은 80이므로 80 포트를 사용하는 호스트라면 생략 가능합니다.
path(): URI의 경로(path)를 입력합니다.
     URI의 path에서 {continents}, {city} 의 두 개의 템플릿 변수를 사용하고 있습니다.
    두 개의 템플릿 변수는 uriComponents.expand("Asia", "Seoul").toUri(); 에서 expand() 메서드 파라미터의 문자열로 채      워집니다. 즉, 빌드 타임에 {continents}는 ‘Asia’, {city}는 ‘Seoul’로 변환됩니다.
encode(): URI에 사용된 템플릿 변수들을 인코딩 해줍니다.여기서 인코딩의 의미는 non-ASCII 문자와 URI에 적절하지 않은 문자를 Percent Encoding 한다는 의미입니다.
build(): UriComponents 객체를 생성합니다.
expand(): 파라미터로 입력한 값을 URI 템플릿 변수의 값으로 대체합니다.
toUri(): URI 객체를 생성합니다.

 

[ 요청 전송 ]

public class RestClientExample01 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate =
                new RestTemplate(new HttpComponentsClientHttpRequestFactory());

        // (2) URI 생성
        UriComponents uriComponents =
                UriComponentsBuilder
                        .newInstance()
                        .scheme("http")
                        .host("worldtimeapi.org")
//                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();

        // (3) Request 전송
        String result = restTemplate.getForObject(uri, String.class);

        System.out.println(result);
    }
}

- getForObject : HTTP get 요청을 통해 서버의 리소스를 조회합니다.

    이는 커스텀 클래스 타입으로 원하는 정보만 응답으로 전달 받을 수도 있습니다.

 

 

 

 

 

 

이 외에도 정보를 전달받는 여러 방법이 있습니다.

'HTTP' 카테고리의 다른 글

HTTP 요청 데이터 작성하기  (0) 2022.11.26
DTO  (0) 2022.08.22
Message States Server  (0) 2022.08.19
HTTP 메서드와 속성  (0) 2022.08.18
HTTP API 설계와 메서드  (0) 2022.08.14

+ Recent posts