[Spring boot] REST API의 기초와 설계

Spring boot가 기존의 Spring에 비해 다양한 설정들을 자동화 시켜 개발자가 설정해야 할 부분을 줄이고, 임베디드 톰캣을 탑재하여 더 쉬운 개발들이 가능해졌다는 것을 알았습니다.

이번 포스트에서는 Spring boot로 서버를 개발해보는 첫 단추인 REST API에 대해 알아보도록 하겠습니다.

 

What is REST API ?

REST API란, REST(Representational State Transfer)의 약자로 '대표적인 상태 전달'이라는 의미를 담고 있습니다. 웹과 같은 분산 하이퍼미디어 시스템에서 사용하는 통신 네트워크 아키텍처라고 보시면 됩니다.

본래 웹은 전송 방식으로 HTTP 프로토콜을, 식별 방법으로 URI를 사용하는데, 여기서 혼동하면 안되는 것은 URL과 URI는 다릅니다. URI는 인터넷에서 특정 자원을 나타내는 주솟값이고, URL은 인터넷에서 특정 자원이나 파일의 위치를 나타내는 주솟값입니다.

HTTP는 웹에서 GET, POST, PUT, DELETE 등의 메소드를 이용하여 정보를 주고 받는 프로토콜로 REST는 HTTP와 URI의 단순하고 간결한 장점을 계승한 네트워크 아키텍처입니다. 따라서 다양한 요구 사항에 대응해 때로는 단순하게, 때로는 서버와 클라이언트가 서로 통신하는 리소스에 대해 복잡한 방식으로 상호 작용할 수 있습니다.

REST가 개발된 목적은 아래와 같습니다.

  • 구성요소 상호작용의 규모 확장성
  • 인터페이스의 범용성
  • 구성요소의 독립적인 배포
  • 중간적 구성요소를 이용한 응답 지연 감소, 보안 강화, 레거시 시스템 캡슐화

 

REST API 제약 조건

REST API 서버를 개발할 때는 REST의 구현 원칙을 제대로 지키면서 REST 아키텍처를 만드는 것을 RESTful한 API라고 표현을 보통 많이 하는데, 단순히 무작정 HTTP의 메소드와 URI를 사용하였다고 하여, 무조건 RESTful한 API라고 표현하지 않습니다. 

아래의 제약 조건을 잘 지킨 API를 RESTful한 API라고 표현합니다.

  • 클라이언트-서버 형태 (Client-Server model)
  • 무상태성 (Stateless)
  • 캐시 기능 (Cacheable)
  • 계층화 시스템 (Layered system)
  • 코드 온 디맨드 (Code on demand)
  • 인터페이스 일관성 (Uniform interface)

클라이언트 서버 형태의 원칙은 관심사의 명확한 분리를 말하며, 이를 지킴으로써 서버와 클라이언트의 역할을 분명히 함으로써 서버의 구성 요소가 단순화 되고 확장성이 향상되어, 여러 플랫폼을 지원할 수 있는 것이죠.

무상태성 원칙은 서버에 클라이언트 상태 정보를 일절 저장하지 않음을 이야기 합니다. 단순히 들어오는 요청만을 처리하여 구현을 단순화 하되, 클라이언트의 모든 요청은 서버가 요청을 알아듣는 데 필요한 모든 정보를 알고 있어야 합니다. 이를 테면, 어떤 메소드를 요청했는지, 여기에 필요한 정보는 무엇인지 등을 이야기 합니다.

캐시 기능은 클라이언트의 요청을 캐싱한다는 이야기입니다. HTTP의 기능 중 캐시 기능을 적용한 것입니다.

계층화 시스템 원칙은 애플리케이션 서버가 중계 서버(Proxy, Gateway)나 로드 밸런싱, 공유 캐시 등을 이용하여 확장성 있는 시스템을 구현해야 한다는 원칙입니다.

코드 온 디맨드의 원칙은 반드시 지켜야 할 필수 원칙은 아닙니다. 이 원칙은 클라이언트가 서버에서 Java Applet, Javascript 실행 코드를 전달 받아 기능을 일시적으로 확장할 수 있어야 한다는 원칙입니다.

인터페이스 일관성 원칙은 URI를 가능한 지정된 리소스에 균일하고, 통일된 인터페이스를 제공해야 하는 원칙으로 아키텍처를 단순하게 분리하여 확장이 쉽도록 구현해야 한다는 원칙입니다. 대표적으로는 각 Entity 별로 자원을 식별하는 방법, 혹은 HATEOAS를 이용하는 방법을 이야기 하는데, HATEOAS란, 클라이언트에 응답하는 형식을 단순히 결과 데이터만 제공해주는 것이 아닌 URI를 함께 제공해야한다는 원칙을 말합니다.

그 중에서도 제가 중요하다고 생각되는 부분이 있다면, 자기 서술적인 설계를 하는 것입니다. 자기 서술적인 설계란, 인터페이스 일관성 원칙을 준수함과 동시에 이것이 어떻게 처리되는지에 대한 충분한 정보, 관련된 리소스를 HyperLink로 담는 것까지가 좀 더 이해하기 쉽고, 좋은 설계가 될 수 있겠죠.

 

REST API 설계

자 그럼 이제 직접 REST API를 만들어보는 시간을 가져보도록 하겠습니다. REST API 서버를 개발할 때는 무작정 REST API 서버를 만들기 위해 키보드를 두들기기 보단, 먼저 적절한 설계를 갖춘 후에 코딩을 진행하는 것을 추천하는 바입니다.

REST API는 HTTP의 메소드, URI로 이루어진 API 서버이므로, 필요한 것은 요청과 응답 이렇게 2가지가 존재하고, 어떠한 요청에 필요한 데이터(파라미터)와 그 결과 모델을 구성해야 합니다.

  • 자원(Resource): URI
  • 행위(Action): HTTP Method
  • 표현(Representations): HTTP Message Body

만약 기존의 HTTP API를 설계해보신 분들이라면, 이러한 설계 작업이 그렇게 어렵지는 않을 것이지만, 처음 REST API 서버를 개발해보시는 분들이라면, 조금 생소할지도 모르겠군요. 

예를 들어, 쇼핑몰 REST API 서버를 개발한다고 하였을 때, 어떤 상품에 대한 자원을 가져오고자 할 때는 아래와 같이 API를 설계할 수 있습니다.

http://localhost:1412/api/items/1

여기서 만든 위 주소를 URI라고 합니다. 음? URL이랑 무슨 차이가 있는 것일까요? URL은 어떤 자원 예를 들면, tistory.pdf 처럼 어떤 파일이나 자원의 위치를 나타내는 것이라면, URI는 문자열을 식별하기 위한 것입니다. 따라서 명사를 사용해야 하며, 동사를 사용하는 것은 피해야 합니다. 그 이유는 HTTP에 대한 행위에 대해서는 이미 HTTP Method가 이를 수행하고 있으며, 이를 URI에 적는 것은 오히려 혼동을 줄 수도 있겠지요.

명사를 사용할 때도 단수보다는 복수를 사용하는 것이 좋습니다. 왜냐하면, API를 설계할 때, 어떠한 자원을 가져오게 되는데, 그것은 보통 DB 등에서 가져오게 되고, 그들은 여러 개의 데이터로 존재하기 때문입니다. 따라서 컬렉션이라는 것을 명확하게 알려줌이 되고, 여러 데이터를 가져온다면, 그들 밑으로 단수를 표현하는 방향으로 간다면, 더욱 깔끔한 API가 되겠죠.

# 상품을 가져오는(GET) API

GET http://localhost:1412/api/items
content-type: application/json

그러나 피해야 하는 명사들도 있습니다. 이를 테면, 주문 현황을 나타내는 orders 등의 명사는 가능한 사용하지 않는 것이 좋겠습니다. 왜냐하면, SQL 쿼리문에서 order는 정렬의 키워드로써 사용하기 때문에 이를 같이 사용하면 혼동을 주게 됩니다. 따라서 SQL 질의문에 존재하는 키워드 등의 사용은 자제하는 것이 좋겠습니다.

다음은 행위에 대한 설계입니다. REST API 서버 개발시에 자원에 대해서는 동사를 사용하지 않는 것인데, 그렇다면 우리는 동사를 HTTP 메소드를 사용하게 되는 것이고, 가능한 여기에 있는 행위를 가지고 API를 구현해야 합니다.

Resource GET(read) POST(create) PUT(update) DELETE(delete)
/items 상품 목록 보기 상품 추가 - -
/items/{id} ID값 상품 보기 - ID값의 상품 수정 ID값의 상품 삭제

위 작업은 데이터베이스 등을 이용해서 상품을 추가하고, 보고, 삭제하는 것을 말하는데, 우리는 이를 CRUD(Create, Read, Update, Delete)라 합니다. 실제로 CRUD는 우리가 데이터베이스에서 하는 행위를 말하는 것이고, 이를 HTTP Method 즉, REST API에서의 행위로 표현한다면, GET, POST, PUT, DELETE가 되는 것이죠.

그럼 만약, 상품 목록 중, 내가 원하는 값, 원하는 형태로 보고 싶다면 어떻게 해야 할까요? SQL로 보자면, where, order by 등의 조건을 사용하겠다는 것이 되는데, 이를 어떻게 처리할 수 있을까요?

이 때는 JPA에서 제공하는 Pageable를 이용하는 방법이 있는데, 이 방법은 차후, JPA를 다루게 된다면, 더 상세하게 다뤄보도록 하겠습니다. 먼저, 이 Pageable을 사용한다면, 어떤식으로 URI가 나오는지만 보도록 하겠습니다.

# Pageable을 이용한 경우

GET http://localhost:1412/api/items?page=0&size=10&sort=desc
content-type: application/json

page, size, sort 파라미터는 Pageable 객체에 존재하는 멤버 변수들로, 이러한 프로퍼터 값을 넣어, 원하는 데이터를 뽑을 수 있도록 합니다. 이러한 기능은 보통 웹 게시판에서 많이 사용하는 데, 게시판의 글이 100,000개라면, 이런 기능이 없을 때 100,000개를 모두 받아, 웹 브라우저가 렌더링 해야 하지만, 이렇게 하면 웹 브라우저의 로딩 속도가 느려지게 되죠, 따라서 페이지별로 이를 정해진 갯수만큼 데이터를 받도록 하고, 클라이언트에서 이를 동적으로 나누도록 처리하면, 게시글을 적절하게 등분하여 사용자에게 표시할 수 있게끔 됩니다.

POST 메소드는 새로운 상품을 생성하여 저장하는 역할을 수행하게 되는데, 생성할 상품은 아직 ID 값 등이 존재하지 않기 때문에 단순한 items라는 URI로 끝나도록 설계하고, 대신 POST 메소드를 요청하는 형태로 API를 설계합니다. 생성 이후에는 ID 값이 나오기 때문에 수정이나 삭제 등의 작업은 ID를 붙여서 설계를 하면 되겠죠.

 

기존의 클라이언트 애플리케이션에서 DB를 사용했을 때를 주황색으로 표시하였고, 서버를 구축했을 때를 파란색으로 표시하였습니다. 주황색으로 표시하였을 때는 직접 데이터베이스에 액세스하여, 클라이언트가 직접 접근했다면, 이번에는 서버를 사용하여 서버에서 제공하는 행위를 통해 데이터를 받는 구조로 설계가 된 것이죠.

이러한 구조는 REST API 서버를 통해 서버가 노출하고 싶은 데이터에 대해서만 제공을 하고, 데이터를 캐시함으로써, 성능에 대한 향상되는 구조를 가질 수 있게 됩니다.

 

Spring boot를 이용한 REST API 서버 개발

Spring boot를 이용하여 REST API 서버를 개발하는 방법에는 두 가지 방법이 있습니다.

  • MVC 패턴을 이용하는 방법
  • Spring boot data rest를 활용하는 방법

구체적인 구현에 대해서는 다음 포스트에서 다룰 것입니다. 그 전에, 미리 이 방법에 차이가 어떤 것이 있는지 설명을 드리자면, MVC 패턴은 Model View Controller로 이루어진 형태의 디자인 패턴으로 REST API 서버를 설계하겠다는 것입니다.

 

Spring boot로 본다면, Controller, Service (DAO), Repository로 나누어 데이터의 운반 처리를 세분화 하겠다는 것이죠. 기존의 Spring MVC와 차이가 있다면 반환 형식이 기존의 Spring MVC는 HTML이었다면 REST API는 XML이냐, JSON이냐의 차이가 있습니다.

 

Spring boot data rest는 Repository 하나만 있다면 DB에서 CRUD를 모두 수행할 수 있도록하는 아주 간단한 라이브러리입니다. MVC 패턴과는 달리 Controller, Service가 없고, 레포지터리 내부의 CRUD 메소드와 매핑하여 처리합니다. 즉, MVC에서는 CRUD를 모두 직접 구현해주고, 이를 Service와 Controller로 붙이는 걸 개발자가 모두 구현해줘야 하지만, 그렇지 않아도 된다는 것이죠.

그렇다고 하여, Spring boot data rest에서 Controller, Service를 구현할 수 없는 것은 아닙니다. 이 부분과 함께 다음 포스트에서는 MVC 패턴을 이용한 REST API 서버 개발과 Spring boot data rest를 이용한 REST API 서버 개발에 대해 상세하게 다뤄보도록 하겠습니다.

comments powered by Disqus

Tistory Comments 0