556
우리는 매일 웹 기술을 통해 수많은 정보에 접근하고 있습니다. 각종 뉴스를 제공하는 포털 서비스는 물론이고 편리하게 온라인 쇼핑몰에 이르기까지 웹 기술이 사용되지 않은 곳이 거의 없을 정도입니다. 웹 기술이 어떻게 발전해 왔는지 살펴보고 웹 기반의 클라이언트와 서버 간 연동 규격인 RESTful API에 대해 간단히 알아보겠습니다.
웹 화면은 정적 웹 페이지static web page와 동적 웹 페이지dynamic web page로 나눌 수 있습니다. 예를 들면 회사 소개 웹 페이지가 정적인 웹 화면이고, 늘 최신 뉴스를 업데이트 하는 포털 사이트나 실시간으로 순위가 바뀌는 상품이 표시되는 쇼핑몰이 동적인 웹 화면입니다.
웹 화면 뒤에는 다양한 기술이 사용되고 있습니다. HTML 페이지나 이미지 같은 정적 리소스와, 이러한 리소스를 저장하고 브라우저 요청에 따라 전달하는 Apache, Nginx 같은 웹 서버가 대표적입니다.
웹 서버와 달리 톰캣, JBoss와 같은 웹 애플리케이션 서버는 브라우저의 요청을 분석하고 데이터베이스를 조회해 요청한 정보 또는 최신화된 정보를 생성한 후 동적인 웹 화면을 구성해 전달합니다.
최근에는 웹 브라우저 대신 리액트React, 플러터Flutter와 같은 프론트엔드 기술이 등장해 모바일 기기에 최적화된 화면 구성을 제공하고 있습니다. 이에 대응하고자 서버 애플리케이션도 웹 브라우저에게 기존처럼 HTML로 완성된 화면을 전달하는 방식에서 벗어나, 프론트엔드 기술을 사용한 클라이언트에게 JSON 형태로 데이터를 직접 제공하는 RESTful API 서버 개발이 활발해지고 있습니다.
프론트엔드 기술이 다양한 만큼 백엔드 기술도 다양합니다. 그중에서도 자바 진영의 스프링 기술은 소규모부터 대규모까지 다양한 애플리케이션 개발에 알맞은 가장 인기 있는 백엔드 기술로, 국내에서도 공공 기관은 물론 금융, 커머스 등의 다양한 분야에서 서버 애플리케이션 개발을 위한 기술로 채택되고 있습니다.
스프링 기술은 자바 EEJava Enterprise Edition(현재는 Jakarta EE)에서 정의한 서블릿을 바탕으로 하고 있으며, 이를 운영하기 위해 서블릿 컨테이너Servlet Container라는 WASWeb Application Server가 필요합니다. 스프링 부트 애플리케이션은 톰캣이라는 오픈 소스 기반의 서블릿 컨테이너를 내장하고 있으며, 클라이언트가 요청한 URL에 따라 컨트롤러로 흐름을 분배해 주는 디스패처 서블릿Dispatcher Sevlet으로 구성되어 있습니다.
게시판 서비스를 위한 RESTful API 서버를 작성하는 경우 클라이언트는 API를 호출해 게시판에 글을 생성하거나 수정할 수 있으며, 게시글을 작성하는 사용자 또한 생성, 수정, 삭제할 수 있습니다.
RESTful API를 작성할 때도 설계 원칙에 따라 작성하는 것이 중요합니다. 개발의 효율성을 높이고 유지보수를 용이하게 하는 RESTful API 설계 원칙에 대해 알아보겠습니다.
RESTful API는 서버가 다루어야 할 자원resource에 집중해 설계해야 합니다. 즉, 서버가 관리하는 자원을 어떻게 해야 하는지 나타내는 ‘동사’보다 어떤 자원을 다루어야 하는지 나타내는 ‘명사’를 중심으로 URI를 설계합니다. 서버가 관리하는 자원에 회원, 게시글 등이 있다고 가정하는 경우 회원과 게시글을 대상으로 RESTful API를 설계한 예입니다.
다루어야 할 자원을 대상으로 RESTful API의 URL을 설계했다면, 자원을 어떻게 할 것인지는 HTTP 메서드HTTP Method 타입으로 나타내 활용하면 됩니다. RESTful API 호출의 목적이 회원 목록을 조회(GET)하기 위한 것인지, 회원 정보를 새롭게 생성(POST)하거나 수정(PUT)하려는 것인지 등을 HTTP 메서드 타입으로 구분하면 됩니다.
RESTful API를 설계할 때 URI는 동사를 포함하지 않고, 명사형으로 사용하되 소문자와 복수형을 사용하는 것이 일반적입니다. 또한 언더스코어(_)는 사용하지 않아야 합니다. 다음과 같은 설계는 URI에 동사가 포함되었거나 대문자가 포함되었으므로 잘못된 예시입니다.
RESTful API는 클라이언트의 요청을 처리하고 그 결과를 HTTP 상태 코드로 명확하게 전달해야 합니다. 예를 들어 회원 생성 요청을 잘 처리했는지 또는 수정 요청한 회원이 없는 회원이라 처리하지 못했는지 등에 대한 응답을 전달해야 합니다. 자주 사용하는 응답 코드는 다음과 같습니다.
회원 생성을 요청했지만 필수 정보인 이메일이 누락된 경우처럼 클라이언트의 요청 정보가 부족하거나 잘못되었다면 400 Bad Request를 전달합니다. 또한 존재하지 않는 회원 아이디로 삭제를 요청했을 때는 404 Not Found를 전달하면 됩니다.
서버는 클라이언트의 요청을 처리할 때 어떠한 상태 정보도 저장하지 않아야 합니다. 모든 요청은 독립적으로 처리되어야 합니다. 즉, 서버가 이전 요청을 기억해두고 다음 요청에 영향을 주지 않아야 합니다.
예를 들어 택배 배송 정보를 조회하기 위해 운송장 번호로 배송 정보를 조회했다고 해서 서버가 이를 기억하지 않습니다. 따라서 같은 택배 정보를 수정하거나 삭제할 때도 매번 운송장 번호를 다시 보내야 합니다. 다시 말해, 서버는 이전 요청을 기억하지 않고 오직 현재 요청에 포함된 운송장 번호만 보고 응답하므로 RESTful API 설계의 무상태성Stateless 원칙을 따릅니다.
계층화 구조Layered System란 RESTful API 아키텍처에서 클라이언트와 서버 사이에 여러 개의 계층layer이 있어도 된다는 것을 의미합니다. 예를 들어 클라이언트와 서버 사이에 로드 밸런서나 API Gateway가 있을 수도 있고 어떤 경우에는 인증 서버가 있을 수도 있습니다. 이러한 계층은 기능을 각각의 계층이 담당하도록 나누는 역할을 위해 필요하지만, 클라이언트 입장에서는 알 필요도 없고 그저 투명하게 보일 뿐입니다. 이러한 계층화 구조는 계층별로 역할이 분리되어 유지보수가 쉽고 계층별로 독립적으로 확장할 수 있어 유연한 시스템을 구축할 수 있습니다.
클라이언트 서버 구조란 클라이언트는 사용자 인터페이스(UI)를 담당하고 서버는 데이터와 로직으로 비즈니스를 처리한다는 것을 의미합니다. 예를 들어 서버는 RESTful API를 사용해 상품 목록을 JSON으로 전달하고 클라이언트는 JSON으로 전달받은 상품 목록을 모바일 앱이나 브라우저 화면을 사용해 사용자에게 보여줌으로써 두 역할을 명확하게 분리합니다.
RESTful API 서버가 응답에 Cache-Control 헤더를 설정해 클라이언트나 그 중간에 있는 서버가 응답 데이터를 캐싱할 수 있도록 합니다. 이러한 캐싱을 통해 동일한 요청에 대해 캐싱되어 있는 응답을 사용함으로써 속도를 높일 수 있습니다. 일반적으로 GET 요청에 대해서는 캐싱을 하지만 POST/PUT/DELETE에는 캐싱을 하지 않습니다.
이러한 여덟 가지 원칙을 따라 설계한 RESTful API는 일관성과 예측 가능성을 높여 줍니다. 또한 이를 사용하는 클라이언트 개발자가 API 문서를 보지 않고도 URL과 HTTP 메서드만으로 기능을 추측할 수 있고, 서버가 개발되기 전에 API 명세만 보고 작업할 수 있는 등 효율을 높일 수 있습니다.
위 콘텐츠는 『이것이 스프링 부트다 with 자바』의 내용을 재구성하여 작성되었습니다.
댓글