mojo's Blog

REST API 본문

JSP

REST API

_mojo_ 2022. 1. 5. 16:34

REST API 개요

 

REST API란?

REST 또는 RestFul 이라는 용어는 네트워크상에서 클라이언트와 서버 사이의 통신을 구현하는 방법에 대한 아이디어이다.

클라이언트가 서버로 요청을 보냈을 때 서버가 응답으로 보내주는 Resource(ex : 파일, 프로그램 호출 등)의 상태를 Representation이라 정의하고 하나의 Resource는 여러 형태의 Representation(ex : json, xml, text, rss 등)으로 전달할 수 있다는 개념을 의미한다.

 

REST API의 등장 배경

서로 다른 시스템에서 네트워크(인터넷)를 통해 데이터를 주고받기 위한 클라이언트-서버 프로그램 구조는 일반적으로 다음과 같은 문제점이 있다.

  • 동시 다중 접속에 대한 안정성, 보안, 백업, 장애 대응, 이중화 등 여러 기술적 문제를 자체적으로 해결할 수 있는 역량과 고수준의 개발자와 서버 엔지니어가 필요하다.
  • 클라이언트와의 통신을 위해 요청, 응답, 메시지 규격 등 프로토콜을 자체적으로 정의해야 한다.
  • 전용 프로토콜 사용으로 서비스 간 호환이 어렵다.

이러한 전통적인 클라이언트-서버 방식의 문제는 사실 웹을 사용하는 것으로 상당 부분 해결이 가능하다.

  • 웹은 오랜 기간 검증된 서버 소프트웨어를 통해 안정성, 보안, 백업 등의 모든 솔루션을 갖추고 있다.
  • HTTP 프로토콜 사용으로 호환성 제공이 가능하다.
  • 자바, 서블릿 등 다양한 서버 측 프로그래밍 기술을 그대로 사용할 수 있다.

이처럼 대부분의 문제가 웹을 사용하는 것으로 해결될 수 있다.

그러나 웹은 기본적으로 클라이언트 요청에 대한 응답으로 화면 중심의 HTML을 제공하는 시스템이기 때문에 단순히 데이터를 주고받고자 하는 서비스에는 적합하지 않다.

 

확장성이 뛰어나고 경량의 데이터 구조라고 할 수 있는 JSON이 주목을 받기 시작했다.

JSON은 JavaScript Object Notation 약어로, 그 자체로 자바스크립트 객체 구조를 가지고 있어 웹 브라우저에서 바로 이해할 수 있고 처리 가능한 구조라는 특징이 있다.

이와 함께 RESTful 개념이 재조명되어 본격적으로 적용되기 시작해 지금의 프런트엔드 중심 개발을 이끌게 되었다.

 

REST는 현재 HTTP와 JSON을 함께 사용하여 Open API를 구현하는 형태로 많이 사용되고 있으며 대부분의 Open API는 REST 아키텍쳐를 기반으로 만들어져 있다. 

일반적으로 REST 원칙을 따르는 시스템을 RESTful이라 하며 웹 기반으로 구현된 서비스이므로 RESTful 웹 서비스라고 이야기한다.

 

OPEN API는 인터넷을 통해 제공되는 데이터 서비스의 인터페이스로, 일반적 프로그램에서의 API가 클래스 라이브러리 형태로 제공되는 것에 비해 웹을 사용하기 때문에 URI 구조를 가지고 있으며 응답 메시지로는 주로 JSON을 사용한다.

 

 

JAX-RS 개요

 

JAX-RS란?

REST 서비스를 제공하기 위해서는 여러 HTTP Method(GET, POST, PUT 등)를 지원하면서 다양한 URI 요청을 처리할 수 있는 서버 프로그램 구조가 필요하다.

단순히 서블릿만 이용해도 어느 정도 REST 형태의 서비스를 개발할 수 있지만 여러 URI 요청을 구조적으로 손쉽게 처리하려면 규격이 필요하다.

이에 따라 자바에서는 JAX-RS라고 하는 표준 규격을 만들었다.

 

JAX-RS(Java API for RESTful Web Services)는 REST 원칙을 사용하는 개발 매커니즘을 제공하는 자바 표준 API다.

즉 JAX-RS는 서비스 측 REST 애플리케이션 개발을 단순화하는 인터페이스 및 Java 애너테이션의 집합체라고 볼 수 있다.

스프링 프레임워크의 경우 RestController라고 하는 자체 규격을 제공하며 필요에 따라 JAX-RS를 사용할 수 있다.

시스템 자체가 스프링 기반이라고 하면 JAX-RS를 사용하기 보다는 스프링의 RestController가 좀 더 편리하다.

 

※ JAX-RS 사용 과정

API 서비스 등록

먼저 제공하려는 API 서비스에 대한 정보를 컨테이너에 전달해야 한다.

@Application 애너테이션을 사용하여 어떤 시작 url을 사용할지 지정해야 하며 해당 요청에 대한 구현 클래스의 패키지를 등록해주어야 한다.

서블릿이나 JSP의 경우에도 콘텍스트 루트라고 해서 시작 경로가 정해져 있다(ex : /jwbook).

다음 코드는 모든 REST API 요청이 /api로 시작하도록 지정하고 있다.

@ApplicationPath("/api")
public class RestConfig extends Application {
    public Map<String, Object> getProperties() {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("jersey.config.server.provider.packages", "ch12");
        return properties;
    }
}

 

주의할 점은 RestConfig 클래스에서 속성으로 저장하는 패키지에 대해서만 REST API 클래스로 사용할 수 있다는 점이다.

패키지 이외에도 개별 클래스를 등록하는 방법도 있으니 자세한 사항은 관련 문서를 참고한다.

Jersey 2.35 User Guide (eclipse-ee4j.github.io)

 

API 클래스 구현

API 클래스는 서블릿과 달리 별도의 클래스 상속 없이 일반 자바 클래스로 구현된다.

클래스 앞부분에 @Path 애너테이션으로 하위 URI 시작점을 지정하고(선택 사항) 각각의 요청에 대한 처리를 담당하는 메서드를 구현하면 된다.

REST API 클래스 구현에 필요한 구성요소는 다음과 같다.

  • 메서드 :  GET, POST, PUT, DELETE 등 어떤 HTTP 메서드 요청을 처리할 것인지 지정한다.
  • 요청 경로 : 어떤 URI 요청에 동작할 것인지 지정한다.
  • 응답 콘텐트 타입 : 어떤 콘텐트 타입(ex : text, html, json, xml 등)으로 응답 메시지를 구성할 것인지 지정한다.
  • 파라미터 : 클라이언트 요청 파라미터 및 경로 파라미터 값을 메서드에 전달한다.

REST API를 구성한다는 것은 어떤 HTTP 메서드로 요청되는 특정 URI에 동작할 메서드를 구현하고 요청 파라미터를 메서드에서 사용해 프로그램을 구현한 다음 처리 결과를 어떤 형태로 전달할지 정의한다고 이해하면 된다.

예를 들어서 /api/addrbook/list 요청을 처리하는 API 클래스는 다음과 같이 구현할 수 있다.

@Path("/addrbook")
public class AddrBookApiService {
    Logger logger = Logger.getLogger("RestApiService");
    AddrBookDAO dao = new AddrBookH2DAO();
  
    @GET
    @Path("list")
    @Produces(MediaType.APPLICATION_JSON)
    public List<AddrBook> getList() {
        List<AddrBook> datas = dao.getAll();
        logger.info("API call: /list ");
        return datas;
    }
}
  • @Path("/addrbook") : 클래스부에 선언된 애너테이션의 경우 현재 클래스에서 처리할 서브 경로를 설정한다. 즉 /api/addrbook 요청에 응답한다.
  • @GET : GET 요청을 처리한다.
  • @Path("list") : /api/addrbook/list 요청에 응답한다.
  • @Produces(MediaType.APPLICATION_JSON) : 메서드 처리 후 생성되는 데이터 타입으로, 여기서는 JSON 형식을 리턴하게 된다는 의미다. 내부적으로 List 타입이 JSON으로 변경된다.

 

REST API 설계 원칙

REST API를 구현하는 과정은 비교적 단순하지만 프로그램 문법과 같이 정해진 규칙이 있는 것은 아니기 때문에 잘 설계하기 위해서는 많은 경험과 노력이 필요하다.

일반적인 REST API 설계 원칙은 다음과 같다.

 

■ 동사 대신 명사 사용

예를 들어 전체 상품 목록을 제공하는 API의 경우 getProductList, getAll, getProducts와 같은 동사 형태보다는 products와 같은 명사 형태가 적합하다.

/getProductList -> /products
/getAllStudent -> /students

 

■ 상태 변경 시 GET 메서드와 쿼리 파라미터 사용 금지

수정, 삭제와 같이 데이터의 상태를 변경하는 경우 파라미터 형태가 아닌 HTTP 메서드와 경로 파라미터로 처리하는 것이 좋다.

GET /api/products?action=delete&id=1021 -> DELETE /api/products/1021

 

■ 복수 명사 사용

집합형 데이터를 다루는 API의 경우 단수형보다는 복수형을 사용하는 것이 좋다.

GET /product -> Get /products
GET /studentAll -> Get /students

 

■ 관계 형태 표현의 하위 리소스 사용

예를 들어 컴퓨터공학과 학생들 중 홍길동 학생을 찾는 경우 다음과 같이 찾는다.

GET /depts/CE/students/홍길동

 

■ 에러 정보 제공

에러 발생 시 단순히 서러 에러 500만 표시하는 것이 아니라 여러 HTTP 상태 코드를 활용해야 하며, 별도의 에러 정보를 응답 메시지 구조에 포함할 수 있어야 한다.

{
    "errors": [
        {
            "userMessage": "요청 데이터를 찾을 수 없습니다!!!",
            "internalMessage": "데이터베이스 검색 오류", "code": 211,
            "more info": "http://xxx.xxx.com/api/v1/errors/12345"
        }
    ]
}

 

 

REST 클라이언트

 

REST 클라이언트는 REST API를 사용하는 프로그램을 의미한다.

REST API 자체가 HTTP를 사용하기 때문에 지원하는 모든 프로그램은 REST API 클라이언트가 될 수 있다.

예를 들어 웹 브라우저도 서버와 HTTP로 통신하기 때문에 웹 브라우저로 REST API를 호출하는 것이 가능하다.

물론 웬 브라우저 자체만으로는 GET 이외의 메서드 호출에는 어려움이 있지만 GET 요청을 처리하는 API는 기본적으로 웹 브라우저만으로 호출할 수 있다.

만일 스마트폰 앱을 개발하면서 서버로부터 데이터를 가져오기 위해 REST API를 사용한다면 스마트폰 앱도 REST 클라이언트가 되는 것이다.

 

REST 클라이언트 구현은 언어에 중립적이기 때문에 자바, 자바스크립트, 파이썬, C/C++ 등 거의 모든 언어를 사용할 수 있다.

다만 HTTP 프로토콜에 따라 통신할 수 있는 일종의 통신 프로그램을 구현해야 하고 수신되는 JSON 메시지를 프로그램에 적합한 객체로 변환하는 작업등이 요구된다.

별도의 라이브러리 없이 구현하려면 자바에 기본적으로 포함된 URLConnection 클래스를 사용할 수 있으나 다소 코드가 많아지고 처리 과정이 복잡해진다.

URL url = new URL(strUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
con.addRequestProperty("Accept", "text/html");

con.setRequestMethod("GET");

StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"));
String line;
while((line = br.readLine()) != null) {
    sb.append(line).append("\n");
}
br.close();
...

 

아파치의HttpClient 라이브러리를 사용해 구현하는 경우에는 비교적 간결하게 코드를 작성할 수 있다.

// HttpClient 객체 생성
HttpClient client = HttpClientBuilder.create().build();
// Get 요청을 위한 객체 생성
HttpGet getRequest = new HttpGet(requestURL);
// 헤더 정보 설정
getRequest.addHeader("Accept", "text/html");
// 요청 실행 및 응답 객체 생성
HttpResponse response = client.execute(getRequest);
// 응답 메시지 처리
String body = handler.handleResponse(response);

 

응답 메시지의 경우 단순 문자열로 처리하거나 문자열을 자바 객체로 변환하거나 JSON 객체로 변환해 원하는 값만 추출하거나 다양한 형태로 활용할 수 있으며, 이 부분에 대해서만 별도 라이브러리를 사용하는 것도 가능하다.

 

'JSP' 카테고리의 다른 글

REST API 구현  (0) 2022.01.05
리스너와 필터  (0) 2022.01.03
프로젝트 : 뉴스 기사 관리 웹 서비스  (5) 2022.01.03
SQL 및 JDBC 기본 구조와 API  (0) 2022.01.02
데이터베이스와 JDBC  (0) 2021.12.31
Comments