메뉴

문서정보

목차

소개

나는 PHP 웹 프로그래머로 이 바닥에 들어섰다. 그 후에 시스템/네트워크 프로그래머로 방향을 틀었고, 웹 기반 프로그래밍은 사이트를 유지/보수하는 수준에 머물렀다. 예컨데, 취미생활(moniwiki 커스터마이징)을 영위하기 위한 방편이라고나 할까. 물론 워낙에 프로젝트들이 HTTP와 얽혀있는 경우가 많아서, 완전히 손을 떼었다고는 할 수 없는 노릇이긴 했다. 뭐 그냥 프로젝트를 원할히 진행하기에 무리 없는 수준에서의 틈틈히 필요한 정보에 접근하는 그런 정도였다.

그러다가 다시 웹 프로그래밍 영역, 그 중에서도 API 서버 개발에 관심을 가지게 됐다. 이유는 ? OpenAPI를 신경써야하는 프로젝트를 맡다보니 그렇게 된거다. OpenAPI와 엮이다 보니 자연스럽게 REST도 괌심을 가지게 된 것.

해서 REST 기반의 웹 애플리케이션 서버를 만들게 됐는데, 만들다 보니 정리가 필요하다는 생각이 든다. 나는 웹 애플리케이션 분야 전문가는 아니다. 이 문서는 공부하면서 정리하는 수준이 될거다.

REST

REST(Representational State Transfer)은 WWW(World Wide Web)과 같은 분산 시스템을 위한 소프트웨어 아키텍쳐로 특히, 웹 API 디자인을 위한 지배적인 모델로 각광받고 있다. 아키텍처의 특징은 다음과 같다.

REST 이전에

REST도 결국은 네트워크 상에서 HTTP를 기반으로 정보를 제어하기 위한 방법론 중 하나다. 비교적 최근에 등장한 방법론인데, 이전에는 어떤 방법들이 있었는지 살펴보자. 다양한 방법들이 있다. 이들을 만든 벤더들의 목록은 다음과 같다. 이렇게 다양한 방법들이 있는데, 거대 벤더들의 지원까지 받을 수 있는데 왜 REST라는 방법이 개발됐고, 게다가 이렇게 까지 관심을 받게 됐을까.? 기존방식들에 어떤 문제가 있는건가 살펴보니 등의 문제가 발견됐다. 이러한 문제들을 해결하기 위해서 REST를 만들었다.

HTTP와 REST

REST에 대한 복잡한 설명이 많은데, 다음과 같이 요약할 수 있다. 원격에 명령을 내리는 것은 결국 원격에 있는 자원을 제어하겠다라는 의미다. REST는 원격에 있는 자원을 찾기 위해서 URI를 사용한다. 자원을 찾았다면, 이제 자원에 대한 명령을 내려야 하는데, 자원에 대한 명령의 범주는 결국 CRUD로 압축할 수 있다. 각각 SQL언어의 Insert, Select, Update, Delete에 대응한다.

HTTP는 CRUD를 위한 메서드를 이미 모두 포함하고 있다. 추가적으로 몇개의 메서드들을 더 제공하는데, 여기에서는 설명하지 않겠다. CRUD를 명시해서 자원을 제어하는게 가능하다는 얘기가 되겠다.

설계 목표

REST의 핵심 설계 목표는 다음과 같다.
  1. 컴포넌트들간의 유연한(쉽게 확장가능한) 상호연동성 확보
  2. 범용 인터페이스
  3. 각 컴포넌트들의 독립적인 배포
  4. 지연 감소, 보안강화, 레거시 시스템을 인캡슐레이션하는 중간 컴포넌트로의 역할

상호연동성

상호연동성은 "서로 상이한 컴포넌트"들을 쉽게 연결할 수 있는 성질을 의미한다. 상호연동성은 두 개이상의 컴포넌트들을 결합함으로써, 작업을 더 효율적으로 수행하도록 하는데 목적이 있다.

리눅스 운영체제의 파이프를 생각하면 될 것 같다. 리눅스에서 파이프를 이용하면, 상이한 일을 하는 프로세스들을 연동할 수 있다. 파이프를 이용해서 ls, sort, head라는 전혀다른 프로세스들을 연동한 예다.
# ls -al | sort -r -k 5 | head -10 
프로세스를 컴포넌트로, 파이프를 REST API로 바꾸는 것으로 REST의 상호연동성을 설명할 수 있다.

리눅스에서 프로세스간 상호연동이 간편한 이유는 "파이프"를 어디에서든 간단히 사용할 수 있기 때문이다. REST는 HTTP와 URI기반인데, HTTP와 URI 모두 표준이며, 직관적이고 사용이 간단하다. 한마디로 전 지구적인 표준이다. 광범위한 라이브러리와 소프트웨어 툴을 가지고 있으며, 어디에서든 동일하게 작동할 것을 보장할 수 있다.

범용 인터페이스

앞서 상호연동성을 부분에서 어느정도 설명이 됐다. REST 모델을 위한 HTTP와 URI는 표준으로, 어디서든지 사용가능한 범용 인터페이스를 제공한다. 개발자는 비지니스 로직만 고민하면 된다.

각 컴포넌트들의 독립적인 배포

리눅스 파이프로 되돌아가 보자. 파이프를 이용해서 ls, sort, head를 연동해서 사용하고 있지만, 이들은 완전히 독립된 프로그램으로 따로 배포할 수 있다. 마찬가지로 다른 컴포넌트들과 독립적으로 개발할 수도 있다. 다른 컴포넌트가 추가 되더라도 연동에 걱정할 필요 없다. 그냥 파이프 규격만 맞추면 된다.

REST 기반의 애플리케이션들도 서로 독립적으로 배포/개발할 수 있다.

컴포넌트를 중계하는 역할

클라이언트는 엔드 서버에 직접 연결할 필요 없이(다른 말로 end server의 위치를 몰라도) 서비스를 이용할 수 있다. REST 서버가 클라이언트와 엔드 서버 중간에서 중계역할을 할 수 있기 때문이다. 중계 서버로 이용하면 로드밸런싱, 공유메모리(캐쉬)등을 이용해서 가용성과 확장성/성능을 향상시킬 수 있다. 보안 정책을 적용하기도 쉽다.

RESTful API

RESTful API는 HTTP와 URI 기반으로 자원에 접근할 수 있도록 제공하는 애플리케이션 개발 인터페이스다. 기본적으로 개발자는 HTTP 메서드와 URI 만으로 인터넷에 자료를 CRUD 할 수 있다.

기존의 웹 접근 방식과 RESTful API 와의 차이점

인터넷 게시판은 자원에 대한 CRUD를 모두 포함한다. 기존의 인터넷 게시판은 GET과 POST 만으로 CRUD를 모두 처리하기도 한다. 예컨데, 데이터를 읽는 것과 삭제하는 것 보다 GET 메서드를 이용하는 경우가 대부분이다. 또한 URI는 액션을 나타내지, 자원의 위치를 나타내지는 않는 경우가 많다. 좋게 말하자면 자유로운 거고, 나쁘게 말하자면 대중없다(명시적이지)않은 방식이다.

두 가지 방식을 비교해 보자. java 게시판의 게시물에 대한 CRUD다.
기존 게시판 RESTful API를 지원하는 게시판
글 읽기 GET /list.php?no=510&name=java GET /bbs/java/510
글 올리기 POST /save.php POST /bbs/java
글 삭제 GET /delete.php?no=510&name=java DELETE /bbs/java/510
업데이트 POST /update.php?no=510&name=java UPDATE /bbs/java/510
RESTful 방식이 명확함을 알 수 있다. 제어하려는 자원이 무언지 명확하고, 자원에 대해서 어떤 행동을 할건지도 명확하다.

RESTful API 개발 원칙

자원을 식별할 수 있어야 한다.

URL 만으로 내가 어떤 자원을 제어하려고 하는지를 알 수 있어야 한다. 자원을 제어하기 위해서, 자원의 위치는 물론 자원의 종류까지 알수 있어야 한다는 이야기다. 실제 데이터, 그러니까 server측 데이터베이스에 저장되야하는 정보는 JSON이나 XML형태로 HTTP body 데이터로 전송하면 된다.

예를 들어 java 게시판에 글을 올리기를 원한다면, 다음과 같이 데이터를 전송하면 될거다.

POST /bbs/java
{
  "author":"yundream",
  "charset" : "UTF-8",
  "title" : "Hello World",
  "text" : "만나서 반가워...",
  "createdDate" : "2013/02/01 11:00:00",
  "email": "yundream@abc.com"
}

행위는 명시적이어야 한다.

REST는 아키텍쳐 혹은 방법론과 비슷하다. 따라서 이런 방식을 사용해야 한다고 강제하지 않는다. 기존의 웹 서비스 처럼, GET을 이용해서 UPDATE와 DELETE를 해도 된다. 이것을 막는 규칙같은건 없지만, REST 아키텍처에는 부합하지 않는 방식으로 REST를 따른다고 할 수 없다.

REST에서 행위는 명시적이어야 한다. GET은 SELECT, POST는 CREATE

자기 서술적이어야 한다.

데이터에 대한 메타정보만 가지고도 어떤 종류의 데이터인지, 데이터를 위해서 어떤 애플리케이션을 실행해야 하는지를 알 수 있어야 한다. 데이터 처리를 위한 정보를 얻기 위해서, 데이터 원본을 읽어야 한다면 이것은 자기 서술적이 아니다.

예를 들어 동영상을 처리하는 웹 서비스의 경우, "application/video"만 보내는 것은 자기 서술적이 아니다. 동영상 정보를 알기 위해선는 원본 파일을 다운로드해서 분석해야 하기 때문이다. 자기 서술적이려면, 해상도, 코덱, 비트레이트, 자막파일의 위치, 플레이타임 등의 정보를 모두 포함해야 한다.

자기 서술적이지 않은 정보
{
  "filename":"test.mp4",
  "type":"application/video"
}

자기 서술적인 정보
{
  "filename":"test.avi",
  "title":"Hello world",
  "type":"application/mp4",
  "bitrate":"128kbps",
  "resolution":{"height":1280, "width":1024},
  "codec":"H.264/MPEG-4",
  "playtime":1850,
  "subtitle":"abc.smi",
  # 기타등등등..
}

(HATEOS) Hypermedia as the Engine of Application State

클라이언트의 요청에 대해 응답 할 때, 추가적인 정보를 제공하는 링크를 포함할 수 있어야 한다. REST는 독립적인 컴포넌트들을 손쉽게 연결하기 위한 목적으로도 사용한다. 서로 다른 컴포넌트를 유연하게 연결하려면, 느슨한 연결을 만들어 줄 어떤게 필요하다. 바로 링크다. 서버는 클라이언트 응용 애플리케이션에 하이퍼 링크를 제공한다. 클라이언트는 이 하이퍼 링크를 통해서 전체 네트워크와 연결된다. HATEOAS는 서버가 서로 독립적으로 진화할 수 있도록 서버와 서버, 서버와 클라이언트를 분리할 수 있게 한다.

RESTful API 테스트를 위한 도구들

curl

아이작 클라크에게 플라즈마 커터가 있다면, 우리에겐 curl이 있다.

플라즈마 커터가 그런 것 처럼, curl은 범용 결전병기라 할만하다. 웹과 관련된 모든 용도의 개발에서 평균이상의 성능을 보여주며, 약간의 수고를 더 한다면 결전병기로 사용할 수 있다. 다만 CLI 도구인 만큼, 결전병기 수준으로 사용하려면 꽤 많은 학습이 필요하다는 단점이 있다.

Postman

Postman은 firefox와 chrome에서 사용할 수 있는 플로그인이다. 간단하게 설치할 수 있으며 사용역시 직관적이다. RESTful API를 비롯한 웹 사이트 테스트에 사용할 수 있다. 웹 서비스 개발자의 친구.

https://lh4.googleusercontent.com/-0E8u0QqDLdg/UeLAZGL1maI/AAAAAAAADK0/mSlo7YcxQfE/s640/chrom_05.png

REST의 장점과 단점

REST의 장점을 정리했다.
  1. 언어, 플랫폼에 독립적이다.
  2. SOAP보다 쉽고 간단하다.
  3. 학습이 용이하고, 개발도구가 거의 필요 없다.
  4. (익숙한)웹기반의 설계
  5. 개발 인프라가 탄탄하다. HTTP, URI 기반 서버, 클라이언트툴, 각종 라이브러리들은 완성단계의 기술이다. 개발자들은 하부구조에 신경쓰지 않고 비지니스 로직의 구현만 신경쓰면 된다.
  6. 트랜드다. 예컨데 대세. 구글,야휴,트위터,facebook등의 기업들이 사용하고 있다. SOAP 기반으로 만들어
REST의 단점은 다음과 같다.
  1. REST는 point-to-point 통신모델을 기반으로 한다. 서버와 클라이언트가 연결을 맺고 상호작용해야하는 어플리케이션의 개발에는 적당하지 않다.
  2. REST는 URI, HTTP 를 이용한 아키텍처링 방법에 대한 내용만을 담고 있다. 보안과 통신규약 정책 같은 것은 전혀다루지 않는다. 따라서 개발자는 통신과 정책에 대한 설계와 구현을 도맡아서 진행해야 한다.
  3. HTTP에 (상당히)의존적이다. REST는 설계 원리이기 때문에 HTTP와는 상관없이 다른 프로토콜에서도 구현할 수 있기는 하지만 자연스럽게 녹여내기가 쉽지 않을 수 있다. 대부분의 서비스가 웹으로 통합되는 상황에 비춰볼때 큰 단점은 아닌 것 같다.
  4. CRUD의 4가지 메서드만 제공한다. 대부분의 일들을 처리할 수 있기는 한데, 4가지 메서드 만으로 처리하기엔 모호한 표현들이 있다.

REST 개발 패턴

Sinatra

개인적으로 Ruby sinatra의 REST 개발 패턴이 제일 깔끔한 것 같다. DSL을 이용해서, 특정 도메인을 위한 새로운 언어의 개발이 가능하다는 장점 때문 일 거다.
get '/user/:name' do
  // 유저 정보 읽기 관련 코드 
end

post '/user' do
  // 유저 정보 업데이트 혹은 추가 관련 코드 
end

delete '/usr/:name' do
  // 유저 탈퇴 관련 코드
end
이 얼마나 직관적인가..

Flask

Sinatra와 비슷한 python 진영의 경량 프레임워크다.

참고