티스토리 뷰

사용안함

[REST] RestFul이란 무엇인가?

제부도소년 2014.09.18 17:40

출처 : http://blog.remotty.com/blog/2014/01/28/lets-study-rest/
http://helloreallplay.wordpress.com/2012/07/17/restful-%EC%9D%B4%EB%9E%80/
http://beyondj2ee.wordpress.com/2013/03/21/%EB%8B%B9%EC%8B%A0%EC%9D%98-api%EA%B0%80-restful-%ED%95%98%EC%A7%80-%EC%95%8A%EC%9D%80-5%EA%B0%80%EC%A7%80-%EC%A6%9D%EA%B1%B0/





RestFul이란 무엇인가?

이 글에서는 REST(Representational State Transfer)에 대해서 알아보겠습니다.

목차

머리말

바로 위에서 REST에 대해서 알아본다고 하였지만, REST의 정의와 같은 것은 생략할 예정입니다. 진짜로 이글에서 다룰 것은 실제 RESTFul한 API를 작성할 때 도움될만한 것들을 공부합니다. 또한 여러가지 규칙이 있지만 어느 규칙이 진짜이고, 표준화 된것이 없기때문에(이런것으로 알고있습니다.) 실제 많은 사이트들이 약간씩은 다른 형태로 REST API를 운영하고있습니다. 이 글에서도 필자가 중요하다고 생각하고 직관적이라고 생각하는 요소들을 선택 하여 소개 또는 설명 할 예정입니다.

요즘은 예전과 달리 소비를 위한 장비 및 프로그램이 다양합니다. 반대로 말하면 예전에는 어떠한 인터넷 컨텐츠를 소비하기위한 장비나 프로그램이 몇개 없었습니다. 그렇기때문에 서버와 클라이언트가 거의 1:1이였습니다. 그러나 요즘은 역시 서버는 1인데 클라이언트가 굉장히 다양해졌습니다. 안드로이드는 OS 버전도 굉장히 다양하고 단말기마다 굉장히 다른 특성을 갖기도 합니다. 또 IOS도 있고, 컴퓨터 브라우져의 종류도 많아졌죠.

그래서 예전처럼 하나의 클라이언트를 위한 서버를 구성하는건 비효율적인 일이 되어버렸습니다. 하나의 서버로 여러대의 클라이언트를 대응하도록 할때 필요한것이 RESTFul API입니다.

URI 설계하기

일단 URI(Uniform Resource Identifier)란 영어 약자를 풀어보면 ‘균등한 리소스 식별자’정도로 할 수 있습니다. 말그대로 인터넷의 어떠한 리소스를 식별하기 위해서 만들어진 것입니다. 잘 감이 안오는데 중간중간 특성들을 이야기하면서 내용을 보강하겠습니다.

밑에서 설명하는 규칙들은 RFC3986을 기반으로 작성되었습니다.

소문자를 사용하자(최소한 대소문자를 구분한다는 사실을 알고있자)
http://www.example.com:80/users/1?q=abc#title
|________________________|_______|__________|
         1                   2          3
URI는위와같이 크게 3부분으로 나뉘어져있습니다.
rfc3986에서는 1번부분(host와 port)을 제외한 2번 3번 부분은 대소문자를 구분하도록 하였습니다.

a - http://abc.com/haha
b - HTTP://ABC.COM/haha
c - http://abc.com/HAHA
d - http://abc.com/hAhA

위 예제에서 a와 b만 같은 리소스이고 나머지 조합은 전부 다른 리소스입니다. 그러므로 대소문자를 섞어서 사용하는건 혼란을 가져올 수 있으므로 지양해야겠습니다. 그래도 URI에 사람이름과 같은 고유명사가 들어갈 수 도있죠.. 이땐 대문자를 쓰고싶은데… 사용해도 되긴합니다만 대소문자가 구분된다는걸 이해하셔야 합니다. 위 설명과 중복되긴 하지만 다시한번 언급하겠습니다.

http://www.remotty.com/countries/korea
http://www.remotty.com/countries/Korea

위 두개의 URI는 분명히 다른 리소스를 가리키고 있는 것입니다.

다만 국가코드를 포함하여 도메인을 의미있게 하기위해서 이와 같은 형태로 사용하는 것은 굉장히 좋다고 봅니다.http://cleanHo.mehttp://adBy.mehttp://dishBy.mehttp://googleSear.ch 이 경우에도 경로(path)부분은 소문자를 사용하는게 좋겠습니다.

하이픈(–, hyphen)을 사용하자

경로(path)에 공백(띄어쓰기)가 들어갈땐 경우에따라 띄어쓰기 대신 %20이 쓰일때가 있습니다. 이런건 보기에 별로 좋지 않기때문에 많은 사람들이 밑줄(_, underscore) 또는 하이픈(–, hyphen)을 사용하여 공백을 대체합니다. 여기서 권장하는건 하이픈만 사용하자 입니다. 보통 밑줄은 링크가 걸린부분에 표시되는데 그것과 중복되면 리소스로써의 밑줄은 가려질 수도있기때문에 하이픈을 사용하자.

확장자를 사용하지 말자

기존의 많은 URI들이 확장자를 포함하고 있습니다. 하지만 REST API를 설계할때에는 확장자는 사용하지 않는게 좋겠습니다. 확장자를 사용하지 않으면 리소스가 더 유연해집니다. 어째든 확장자를 사용하지 않는다면 기존에 REST API를 접해보지 않는 사람들은 이런 의문을 갖을 수 있습니다? 결론적으로 Accept header를 사용해야 합니다. 예를들어 내용이 Hello,World인 파일이 있습니다. 서버를 기존방식대로 설계한다면 해당 파일은 http://remotty.com/hello.txt와 같이 요청하여 응답받을 것입니다. 기존의 방식은 분명하게 파일의 형태가 txt로 고정되어있습니다. csv 형태로도 제공하려면http://remotty.com/hello.csv URI도 준비해야 할것이고, 서버엔 hello.txt와 hello.csv 두개의 파일이 존재 하게 될것입니다. http://remotty.com/hello.txt와 http://remotty.com/hello.csv는 분명하게 다른 리소스를 식별하는 URI이지만, 실제론 하나의 리소스를 가르키고 있습니다. 이것은 비 효율적입니다. 리소스가 한개라면 URI도 한개여야합니다.

REST API에서는 http://remotty.com/hello에 대한 대응만 해놓고, 해당 요청이 왔을때 Accept header를 적절히 파싱(parsing)하여 클라이언트(client)가 요청한대로 응답해주면 됩니다.

REST API로 구현했을땐

GET /hello HTTP/1.1
Host: remotty.com
Accept: text/plain

또는

GET /hello HTTP/1.1
Host: remotty.com
Accept: text/csv

Accept를 좀더 적극적으로 활용한다면 이렇게도 가능합니다.

GET /hello HTTP/1.1
Host: remotty.com
Accept: text/csv,text/html;q=0.5,application/xml;q=0.6,text/plain;q=0.9,application/pdf,*/*;q=0.3

Accept header은 클라이언트가 자신이 선호하는 media type을 서버에 보내는 것입니다. 서버에 위 예제와 같은 요청이 왔다면 가장먼저 우선순위는 다음과 같습니다.

  1. text/csv
  2. application/pdf
  3. text/plain;q=0.9
  4. application/xml;q=0.6
  5. text/html;q=0.5
  6. */*;q=0.3

q가 생략된것은 자동으로 1로 설정되며, q의 범위는 0부터 1입니다. 서버가 판단하여 csv로 응답을 할 수 있다면 csv로 응답을 하고 csv가 준비가 되지 않았다면 그다음 우선순위인 pdf로 pdf도 준비되지 않았다면 계속 다음으로 넘어가다가 서버가 응답할수있는 media type가 Accept에 명시되지 않았다면 http status code 406과 body엔 응답 가능한 media type를 명시하여 응답하여야 합니다. 더 자세한 내용은 http content negotiation으로 검색하시어 저도 좀 알려주시기 바랍니다.

위와 같이 Accept header를 적절히 잘 사용하면 하나의 URI로 클라이언트의 요청에 대한 응답을 좀더 유연하게 할 수 있습니다.

CRUD는 URI에 사용하면 안된다

과거에 GETPOST만 사용하였을땐 CRUD를 URI에 표시해주어야 했습니다.

예를들면

GET /posts/13/delete HTTP/1.1
POST /posts/write HTTP/1.1
GET /delete?id=55 HTTP/1.1

하지만 당신은 이제부터 REST API를 설계할 수 있습니다. 뒷부분에 나오는 HTTP Method의 알맞은 역할을 참조하여 적절한 Method를 사용하여 CRUD는 URI에 사용하지 않기로 합시다.

컬렉션과 도큐먼트

이 글을 보기전 REST 관련된 글을 본적이 있다면 컬렉션(collection)이라고 이야기하는 도큐먼트(document)들의 집합을 들어보았을 겁니다. 도큐먼트는 우리말로 문서로 이해해도 되고, 정보라고 이해해도 무관합니다. 도큐먼트는 엘리먼트(element)라고도 하더라고요. 컬렉션은 정보(문서)들의 집합이 이라고 할 수 있겠네요. 컬렉션과 도큐먼트는 모두 리소스라고 표현할 수 있으며 URI에 나타납니다.

예제를 통해 이해도를 높여보겠습니다.

http://www.remotty.com/sports/soccer
http://www.remotty.com/sports/soccer/players
http://www.remotty.com/sports/soccer/players/13/skills

위 URI를 요청하면 어떤 응답이 오게 될지 대충 예감이 오시나요…?

http://www.remotty.com/sports는 컬렉션입니다. sports컬렉션에 soccer도큐먼트가 있는거고요. 또 soccer도큐먼트에 player이라는 컬렉션이 존재하는겁니다! players 컬렉션에 뭐 등번호가 13번인 선수가 있나봅니다. 여기서 13은 도큐먼트이고요. 아시겠죠…? 조금 더 이야기 해보겠습니다. soccer 도큐먼트와 동일한 수준의 다른 도큐먼트는 뭐가 있을까요…? baseballmarathon 등이 있겠네요. 그 하위의 players의 컬렉션과 동일한 수준의 컬렉션은 뭐가있을까요…?rulesleagues 등이 있겠네요. 이제 뭔지 아시겠죠…?

여기서… 중요한 법칙이랄꺼 까진 없지만 뭔가 있습니다. 바로 컬렉션은 복수로 사용하네요. 어쩌면 당연하지만 직관적인 REST API를 위해선 단수 복수도 정확하게 지켜주면 좋겠습니다. 요즘은 한글이 URI에 많이 들어가는데 players는 선수들로 하면 되려나요…?

HTTP Method의 알맞은 역할

HTTP Method는 여러가지가 있지만 REST API에서는 4개 혹은 5개의 Method만 사용됩니다. POSTGETPUTDELETE 이 4가지의 Method를 가지고 CRUD를 할 수 있습니다. 그러나 REST API에서 사용되는 개수는 4개 혹은 5개라고 한 이유는 PATCH를 포함하면 5개가 됩니다.

각 Method마다 올바른 역할이 있습니다. 아래 표를 보면서 이해를 높이겠습니다.

+--------------------------------------+------+-----+-----+--------+
|                  URI                 | POST | GET | PUT | DELETE |
+--------------------------------------+------+-----+-----+--------+
| http://www.remotty.com/sports        |   1  |  2  |  -  |    -   |
+--------------------------------------+------+-----+-----+--------+
| http://www.remotty.com/sports/soccer |   -  |  3  |  4  |    5   |
+--------------------------------------+------+-----+-----+--------+

text table generator에서 만든 text table인데 한글을 사용하면 깨지므로… :(

번호를 이용하여 설명하겠습니다.

  1. 현재 리소스 보다 한단계 아래에 리소스를 생성합니다. POST Method를 통해 해당 URI를 요청하면 sports 컬렉션에 알맞은 soccer 또는 baseball과 같은 도큐먼트 리소스를 생성합니다.
  2. 현재 리소스를 조회합니다. 보통 컬렉션 리소스를 조회하게되면 하위의 도큐먼트들의 목록과 아주 간단한 정보들을 가져옵니다.
  3. 현재 리소스를 조회 합니다. 도큐먼트 리소스를 조회하게되면 해당 도큐먼트에 대한 자세한 정보들을 가져옵니다.
  4. 현재 리소스를 수정합니다. soccer에 대한 정보를 수정하게 됩니다.
  5. 현재 리소스를 삭제합니다. DELETE Method를 이용하여 현재 URI를 호출하면 sports 컬렉션에서 soccer 도큐먼트가 삭제됩니다.

※추가로 주목해볼 만한 Method는 PATCH입니다. 기존에 REST에 익숙하신분들은 수정(update)을 위한 Method는 PUT가 익숙하실 겁니다. 하지만 앞으로는 PUT대신 PATCH를 자주 써야할꺼 같아요. 자세한 설명은 Edge Rails: PATCH is the new primary HTTP method for updates을 참조해주세요.

반응형 웹에서의 REST

요즘은 정말 다양한 장비들이 존재합니다. 크기 역시 다양합니다. 그래서 요즘 작은 화면의 기기로 포털사이트를 접속해보면 어느 형태로든 m이 붙은걸 볼수 있습니다. 아마 mobile에서 맨앞의 m인것같은데, 화면이 작은 장비에서는 800*600이 넘어가는 사이트를 돌아다니는건 정말 피곤한 일입니다. 그래서 작은 화면용 페이지가 필요한 이유입니다. 네, 여기까지는 좋습니다. 제가 이 부분에서 소개해드리려는 header는 User-Agent입니다. 그리고 결론적으로 말씀드리고 싶은 내용은http://m.remotty.com/abc 또는 http://www.remotty.com/m/abc처럼 사용하지 말자 입니다.

한가지 예를 들어보겠습니다.

  1. 철수가 안드로이드로 뉴스를 읽고있음
  2. 재미있는 기사 발견,
  3. sns로 공유
  4. http://m.remotty.com/fun 공유됨.
  5. 영희가 이번에 새로산 신상 15형 MacBook Pro Retina을 가지고 sns 보고있음
  6. 철수가 공유한 링크(http://m.remotty.com/fun)클릭.
  7. 영희는 작은화면으로 웹서핑을 하고있는게 아닌데도 불구하고
  8. 모바일에 최적화된 화면으로 뉴스를 읽게됩니다.

뭐가 문제인지 감이 오시나요? 이미 많은 웹사이트가 User-Agent header을 사용중입니다. User-Agent header을 적절히 파싱하여 화면이 작은 장비는 모바일에 최적화된 사이트로 이동(redirect)시켜주고 있습니다.

RESTFul한 웹사이트에서는 User-Agent를 이용하여 다른 곳으로 리다이렉트 시켜주는게 아니라 URI는 그대로이지만 화면만 장비에따라 알아서 최적화 되도록 설계해야합니다.

다시말해서 http://www.remotty.com/info와 http://m.remotty.com/info는 사실상 같은 정보를 보여주고 있지만 화면의 형태만 다를 뿐입니다. REST하게 설계할땐 리소스가 같다면 URI는 하나여야 합니다.

I18n과 REST

현재 많은 웹사이트들이 다국어를 지원하고있고, http://www.remotty.com/ko/info나 http://en.remotty.com등과 같이 언어마다 다른 URI를 운영중인 곳이 있습니다. 여기서 소개해드릴 것은 Accept-Language header입니다.

또 한번 예를 들어보겠습니다.

  1. 한국인 철수가 뉴스를 읽음.
  2. 재미있는 기사발견,
  3. sns로 공유
  4. http://ko.remotty.com/fun 공유됨.
  5. remotty는 다국어가 아주 잘 지원되는 사이트임.
  6. 미국인 Cathy(캐씨)가 sns를 보고있음
  7. 캐씨는 미국인임에도 불구하고,
  8. 한국어로된 뉴스기사를 읽게됩니다.

뭐가 문제인지 감이 오시나요? 다국어 지원을 Accept-Language에 맡긴다면 URI는 그대로인데, 사용자의 환경에 따라 알맞은 언어로 응답할 수 있습니다. 물론 Accept-Language만 가지고 다국어를 하면 조금 어색할 수 있을꺼 같습니다. 사용자가 원하는 언어를 설정하게하여 해당 언어를 세션 또는 쿠키 등에 저장하여 보여줄 언어를 선정할때 우선순위를 약간 조정하여 보여주는게 좋은 방법일꺼 같습니다.

지금 약간 이글의 확장자를 사용하지 말자와 반응형 웹에서의 REST랑 약간 비슷한 느낌인데요, 모두 결론은 URI는 리소스를 식별하기 위해서 사용되었지, 리소스가 어떻게 보여지느냐는 별도의 header을 이용하여 처리하였습니다. 이 점을 생각하면서 다른 문제들도 좀더 REST하게 설계해야겠습니다.

응답 상태 코드

rfc2616을 살펴보면 많은 종류의 상태코드가 존재합니다. 상태코드를 적절히 잘 사용하면 클라이언트에게 많은 정보를 줄 수 있습니다.

성공

  • 200 – 클라이언트의 요청을 정상적으로 수행하였을때 사용합니다. 응답 바디(body)엔 요청과 관련된 내용을 넣어줍니다. 그리고 200의 응답 바디에 오류 내용을 전송하는데 사용해서는 안된다고 합니다. 오류가 났을땐 40x 응답 코드를 권장합니다.
  • 201 – 클라이언트가 어떤 리소스 생성을 요청하였고, 해당 리소스가 성공적으로 생성되었을때 사용합니다.
  • 202 – 클라이언트의 요청이 비동기적으로 처리될때 사용합니다. 응답 바디에 처리되기까지의 시간 등의 정보를 넣어주면 좋다고 합니다.
  • 204 – 클라이언트의 요청응 정상적으로 수행하였을때 사용합니다. 200과 다른점은 204는 응답 바디가 없을때 사용합니다. 예를들어 DELETE와 같은 요청시에 사용합니다. 클라이언트의 리소스 삭제요청이 성공했지만 부가적으로 응답 바디에 넣어서 알려줄만한 정보가 하나도 없을땐 204를 사용합니다.

실패

  • 400 – 클라이언트의 요청이 부적절할때 사용합니다. 요청 실패시 가장 많이 사용될 상태코드로 예를들어 클라이언트에서 보낸 것들이 서버에서 유효성 검증(validation)을 통과하지 못하였을때 400으로 응답합니다. 응답 바디에 요청이 실패한 이유를 넣어줘야 합니다.
  • 401 – 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을때 사용하는 요청입니다. 예를들어 로그인(login)하지 않은 사용자가 로그인했을때에만 요청 가능한 리소스를 요청했을때 401을 응답합니다.
  • 403 – 사용자 인증상태와 관계 없이 응답하고싶지 않은 리소스를 클라이언트가 요청했을때 사용합니다. 그러나 해당 응답코드 대신 400을 사용할 것을 권고합니다. 그 이유는 일단 403 응답이 왔다는것 자체는 해당 리소스가 존재한다는 뜻입니다. 응답하고싶지 않은 리소스는 존재 여부 조차 감추는게 보안상 좋기때문에 403을 응답해야할 요청에 대해선 그냥 400이나 404를 응답하는게 좋겠습니다.
  • 404 – 클라이언트가 요청한 리소스가 존재 하지 않을때 사용하는 응답입니다.
  • 405 – 클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을때 사용하는 응답입니다. 예를들어 읽기전용 리소스에 DELETE Method를 사용했을때 405 응답을 하면 됩니다.

기타

  • 301 – 클라이언트가 요청한 리소스에 대한 URI가 변경 되었을때 사용합니다. 응답시 Location header에 변경된 URI를 적어줘야 합니다.
  • 500 – 서버에 뭔가 문제가 있을때 사용합니다.

마크 마세가 쓴 REST API 디자인 규칙에 이런 말이 있네요.

REST API는 부실한 HTTP 클라이언트에 부합하려는 그 어떤 타협도 해서는 안된다.

마치며

순서가 약간 뒤죽박죽 작성된 느낌이 있네요. 사실 저도 RESTFul한게 좋은건지 나쁜건지 뭔지 아직도 잘 모르는 상태로 작성하였는데, 한가지 확실한건 REST라는 개념(?)이 널리 퍼지고 많은 API들이 RESTFul하다면 REST에서 다루는 내용들은 따로 문서화도 필요없이 자연스레 좀더 체계적인 느낌으로 API를 사용할 수 있을꺼 같은 느낌이 듭니다. 아직 미완성된 글이라 생각합니다. 틀린 내용이나 이해되지 않는 내용이 있으시면 댓글이나 기타 편하신 방법을 통해 적극적으로 글을 완성해주시길 바랍니다.

참고자료








REST, RESTful이란 개념을 한마디로 정의한다면 위와 같이 정의할 수 있을 것 같습니다. 리소스의 구조자체가 URL이다. 즉, 웹서비스에 있는 리소스의 구조적 상태(자원의 구분과 수행하려는 동작 등)를 URL에서 인지할 수 있는 것입니다. 여성들을 대상으로 기술적인 개념을 좀더 쉽게 전달하고자 하는 Skillcrush에서는 REST라는 개념을 아래와 같이 정의하고 있습니다.

REST is a set of simple rules for how to organise and transmit information on the internet

REST란 인터넷의 정보를 조직하고 전송하는 간단한 규칙의 조합, 좀 설명이 어려운가요?^^

사실 REST의 실제 의미는 Representational State Transfer의 줄임말로써 표현 가능한 상태 전송이란 뜻을 가지고 있습니다. 앞서 말씀드린 것과 같이 데이터베이스에서 정보를 가지고 오고 이를 다시 구조화거나 처리하여 사람들에게 서비스로 제공할텐데 이러한 구조가 서비스 제공자들마다 다른 구조를 가지고 있고 유지보수가 용이하지 않기때문에 좀더 보편적이고도 URL을 보고도 쉽게 어떤 것을 의도하려 하는가 알 수 있는 구조가 필요했던 것 같습니다. 이러한 관점에서  REST는 직관적이고도 보편적으로 적용가능한 어떠한 액션을 수행하려고 하고 무슨 개체에 대한 작업을 하려고 하는지 쉽게 이해할 수 있죠.

좀더 깊게 들어가보면 REST가 주창하는 개념은 컴퓨터 세상에서 모든 것이 리소스가 될수 있다는 것입니다. 사람들이 찍은 사진, 비디오, 혹은 여러 문서들이 모두 인터넷에서 유통될 수 있고 가공될 수 있는 것이죠. 이렇게 볼때 웹이라는 것은 리소스들을 표시하는 전체 모음이 될수 있습니다. 그런데 다시 생각해보면 이러한 정보를 제공하는 주체는 우리가 흔히 알고 있는 ‘웹사이트’가 아닌가 하고 생각할 수 있습니다. 맞습니다. 우리는 매일 네이버, 다음과 같은 웹사이트를 접근하고 이들이 주는 여러 링크들을 클릭하고 들어가서 사진을 보고 기사를 읽으며 다시 댓글, 추천 등의 액션을 취하게 되죠. 이러한 표시들은 크게 두가지 포맷으로 나뉘어 집니다. 사람들이 볼 수 있는 1) 웹페이지(흔히 HTML이라는 합니다.)와 기계들이 이해할 수 있는 2) 데이터 파일(XML이라고 부르죠). 모든 웹페이지의 자원들은 이 둘을 아우르며 우리가 항상 접근하고 찾을 수 있는 ‘URL’이란 것을 가지고 있습니다. 즉, 존재하는 정보(HTML, XML)에 위치정보가 있는 URL 이란 것을 통해 사람과 기계는 정보를 접근하고 가공할 수 있는데 정보를 가공한다는 것은 읽고, 쓰고, 수정하고 삭제하는(CRUD: Create, Read, Update, and Delete) 4가지 행위를 수행하게 됩니다. 그래서 이러한 4가지 리소스 가공행위와 리소스의 위치를 나타내는 URL을 합치면 우리는 어떠한 리소스에 어떠한 액션을 취하려 하는가 눈에 들어날 수 있다는 것이죠. 엔지니어들로 하여금 직접적으로 데이터베이스에 접근하지 않으면서도 현제 수행하려고 하는 대상과 동작에 대해서 가시적으로 이해할 수 있다는 것입니다.

가령 A라는 모델의 100번째 데이터를 수정한다고 한다면 기존의 웹서비스에서는 웹사이트마다 다를 수는 있겠지만 아래와 같은 모습일수 있지 않을까 생각됩니다.

http://hostname/service/update.jsp?model=A&id=100

물론 변수가 아닌 다르게 처리할수도 있겠지만 좀 복잡해보일 수 있는 것이 사실이죠. REST개념을 적용한다면 아래와 같이 표혀할 수 있습니다. 복잡해지더라도 이해하기에는 쉬운것이 사실입니다. 물론 그것을 구조화해서 내부적으로 돌아가게끔 설계한다는 것이 어려울수는 있지만요.^^

http://hostname/service/A/100/edit ( updated 2014/06/09, edit은 URI로는 적절치않다고 하여 아래와 같이 변경)

http://hostname/service/A/100

사실 REST라는 것은 Roy Fielding이란 박사의 2000년 논문에 인용된 것으로써 상당히 심플하고 인터넷의 리소스를 표준가능하게 핸들링할 수 있는 방법이었지만 기술적으로는 혼돈 스러웠다고 합니다. 그러나 최근에 운좋게도 많은 서비스들이 쉽고 협업가능하게 만들어가려는 움직임에 REST가 좋은 대안이 된것 같습니다. 그리고 트위터, 그루폰 등이 이러한 REST구조를 서비스 설계시에 적용했고 앱, 웹 등의 여러 기기와의 서비스 연동을 위해 설계구조로 많이 활용되고 있습니다. 국내같은 경우는 미투데이, 카카오톡도 Ruby on Rails를 통해 이러한 REST구조를 적용하고 있구요. 오늘은 간단하지만 조금은 설명하기 쉽지 않았던 REST에 대해 정리해보았습니다. 궁금하신 분들은 언제든지 댓글이나 트위터, 이메일로 말씀해주세요.




RESTful 이란

회사에서 진행하는 프로젝트에서 백엔드 서비스를 담당하게 됐다. 결론적으로 RESTful API 서버 서비스를 구축하는 일인데, 그 놈의 RESTful 이 도대체 뭔지 감이 안왔다. (어깨 넘어로 듣기는 엄청 들었지만, 정확히 무슨 뜻인지 몰랐다.)

먼저 REST 란 무엇인가?

RESTful API 를 알아보기 전에 REST 가 어떤 의미를 가지고 있는지 알아 볼 필요가 있다. 로이 필딩(Roy Fielding) 은 웹이 왜 이렇게 성공했는지, 왜 이 정도의 대규모 시스템이 성립된 것인지에 대해 소프트웨어 아키텍처의 관점에서 분석하고, 하나의 아키텍처 스타일로 정리했는데 이를 “REST(Representational State Transfer)” 이라 이름지었다. REST 는 네트워크 시스템의 아키텍처 스타일이다. 네트워크 시스템의 아키텍처라고 하면 클라이언트/서버 구조를 떠오르는데, REST 는 여기서 파생된 아키텍처 스타일이다. REST에서 가장 중요하며 기본적인 규칙은 아래 두 가지이다.

  • URI는 정보의 자원을 표현해야 한다.
  • 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)으로 표현한다.

만약에 한 마디로 REST를 정리하라고 한다면 HTTP URI + HTTP Method 이다. 즉, REST 란 URI로 대상 자원을 명시하고 Method로 해당 자원에 대한 행위를 정의한다. 자세한 내용은 위키백과(http://ko.wikipedia.org/wiki/REST) 와 블로그(http://spoqa.github.io/2012/02/27/rest-introduction.html) 를  참고하자.

결론적으로 RESTful 의 의미?

RESTful 이란 REST 의 제약에 따르고 있고, REST 다운 것을 말한다. 별거 없다.




최근에 “Lorna Mitchell” 라는
Five Clues That Your API isn’t RESTful (당신의 API가 RESTful 하지 않는 5가지 증거)
의 내용을 기본으로 저의 견해를 덧붙여서 재구성 해봤습니다.

참고로 “Lorna Mitchell” 여성 PHP 개발자 이면서, 특히 API 디자인에 대해서
좋은 아이디어 와 글을 포스팅 하고 있습니다.
그녀의 블로그 :http://www.lornajane.net/

개인적으로 일을 하고 있는 도메인 특정상 많은 시스템  과 다양한 업체의
사람들 과 API 연동을 합니다.

API 정의서“를 보면 서두에 “본 API 정의서는 RESTful 기반에…부랴부랴“로 시작을
합니다.
예전에는 “TCP/IP 기반 소켓 통신” 과 “RESTful“이 방식이 아닌
각자 회사 또는 팀에서 개별적으로 정의한 “HTTP/XML “를 사용을 했습니다.

하지만 최근에는 “RESTful” 아키텍쳐를 거의 대부분 사용을 하고 있습니다.
(물론 RESTful  방식이 기술이 아니고 API 디자인 아키텍쳐 입니다.  ^^)

하지만 막상 정의서의 연동 방식을 보면 “도대체 뭐가 RESTful”하게 설계를 했다는 거지?
라는 의문점들이 생깁니다.

그래서 “100% RESTful 아키텍쳐링“을 다 지킬수는 없지만
최소한 아래에 “언급하는 5가지 디자인“에 대해서는 인식할 필요가 있습니다.

 

1. API의ENDPOINT가 오직 한개인가?

 

실제 경험한 사례로써 한번은 어떤 시스템의 연동 문서를 보니
오직 한개의 URL로 fix” 되어 있었습니다.
예를 들어서 URL은 “http://example.com/rest” 이며, 모든 request는
해당 URL로 통합니다.

실제 자원에 대한 정보, 호출 서비스 정보, 파라미터 정보 등은 “XML 형태의 Body 데이터“로
전송 하도록 되어 있었습니다.

REST의 매우 중요한 구성 요소중 하나는 “Resource” 입니다.
“Resource”의 의미는 말 그대로 서비스를 제공 하는 시스템의 자원을 말합니다.

예를 들어서 “영화 예매 시스템“일 경우 “고객“, “예약번호“, “좌석번호“, “영화정보” 같은 것이며
대부분 명사(noun) 형태의 특성을 갖습니다.
또한 각 “Resource“는 “URL로 표시가 되며, 유일한 식별자“로써 표현 됩니다.

 

2. 모든 요청을 POST 방식으로만 요청 하는가?

 

RESTful“에서 위에서 언급한 “Resource“를 핸드링하기 위해서 “HTTP의 전송 메서드
를 사용합니다.
자원의 생성은 “POST“, 수정은 “PUT“, 조회는 “GET“, 삭제는 “DELETE” 메서드를 사용합니다.
예를 들면
예약 생성 : POST /reservation/2013012500001
예약 수정 : PUT /reservation/2013012500001
예약 조회 : GET /reservation/2013012500001
예약취소 : DELETE /reservation/2013012500001

하지만 실제 실무에서 이런 부분에 대해서 오해를 잘못해서
아래와 비슷한 방식으로 표현을 했었습니다.

예약 생성 : POST /reservation/2013012500001?cmd=insert
예약 수정 : POST /reservation/2013012500001?cmd=update
예약 조회 : POST /reservation/2013012500001?cmd=select
예약취소 : POST /reservation/2013012500001?cmd=delete

이와 같은 표현은 “RESTful“한 설계라고 할수 없습니다.

 

3. 응답에 대한 메타데이터를 BODY에 포함 하는가?

 

RESTful” 한 설계에서 “Request/Response“에 대한 메타 데이터는 최대한
HTTP 프로토콜의 방식을 준수 합니다.

클라이언트에서 요청 후 “처리 결과 값이 성공“일 경우 해당 시스템은
처리 결과를 “Body”에 포함하는 것이 아니고, HTTP Status의 값으로써
표현을 합니다.

저 같은 경우는 최대한 “Pure한 HTTP Status” 코드를 사용하고, 추가되는 부분은
별도로 “사용자 정의” 코드로 관리 합니다.

사용자 정보가 없을 경우는 : 404 (Not Found)
요청 정보가 정확하지 않을 경우 : 400 (Bad Request)
인증 실패 : 401 (UNAUTHORIZED)

즉, 이러한 전송에 대한 메타 데이터(결과 값, 세션 키)는 최대한 HTTP 헤더로
선언하고 실제 “Body 데이터“는 위에서 언급한 “Resource의 순수한 데이터
만을 전송 해야 합니다.

 

4. URL에 동사(VERB)가 포함 되어 있는가?

 

위에서 언급 했듯이 “RESTful“한 API 설계에서 시스템에서 제공하는 것들은 “Resource“라고
말하며 “URL“로 표기 한다라고 말씀을 드렸습니다.
또한 이러한 “Resource“들은 “명사(noun)“적 특성을 같습니다.

만약 “URL“로 표기할때 동사(Verb)가 포함이 되면 혼돈이 올수 있습니다.
행위적 표현이기때문에 RPC(메서드)를 의미하는지 “Resource“를 하는지
구분이 모호해 집니다.

예를 들어서 예약 상태 정보를 조회를 하기 위해서 “/reservation/001/activate
라는 표현 보다 “/reservation/001/status” 라고 표현을 해야 합니다.

 

5. URL에 RPC 호출 메서드 명이 있는가?

 

다양한 시스템 연동 스펙을 보면 아래 와 같이 실제 비지니스 컴포넌트
메서드를 URL에 포함되서 호출하는 경우가 있습니다.

?action=createReservation
?action=modifyReservation
?action=findReservation
?action=removeReservation

또한 URL에 노출되지는 않지만 “Body“안에 “XML” 형태로 선언 하는 경우도 있습니다.

하지만 “RESTful” 설계의 컨셉은 “RPC (Remote Procedure Call)” 목적이 아니고
시스템에서 제공하는 “Resource“를 “bucket“화 하는 것입니다.

 

MY THOUGHT

 

실제 실무에서 외부연동을 하면 “RESTful” 방식이라고 하지만 실제로는
위에서 언급한 5가지중 몇개를 지키지 않은 경우도 있고, 심지어 5개 모두
적용이 안되는 경우가 많습니다. 또한 HTTP/JSON/XML 통신만 하면
RESTful” 하다고 생각들을 하는 것 같습니다.

개인적으로 아쉬운 부분은 약간의 시간을 내서 검토만 했었으면 어떨까 생각 듭니다.
그런데 필자도 말했지만 모든 연동 시스템이 반드시 “RESTful” 해야 하는 것인가?
에 대해서는 저는 약간 다른 생각을 합니다.

너무 유행이 되어 버려서 요새는 반드시 연동은 “RESTful“로 하려고 해서
오히려 시스템을 복잡하게 만들거나,  심지어 시스템 아키텍쳐가 흔들리는 경우도
있습니다.

2년전 제가 “일본 결제 시스템” 과 연동 한적이 있었습니다. 통신 방식은
HTTP/XML” 이었습니다. 문서가 일본어로 되어 있어서 “번역기” 돌리고
추후에는 한글 번역본을 받아서 작업을 했는데..

연동 항목에 “Data Type, Length, Header 선언부, Null 유무” 등 깔끔하고
심플하면서, 쉽게 구성이 되었습니다.

구현은 어렵지 않았고 “결제 GW 테스트” 서버로 연동 테스트를 했는데
이해하고, 연동 테스트 하는데 3일정도 소요가 되었던것 같습니다.

반면 국내 다른 업체 연동을 할때 “RESTful” 방식으로 한다고 했는데
전혀 “RESTful” 하지도 않고 항목도 불명확해서 완전하게 테스트하는데
무려 한달이란 시간이 소요 되었고, 그 한달이란 기간이 정말 스트레스
엄청 받았었습니다.

또한 모든걸 “JSON“포맷으로 통신하는 것도 문제가 있습니다.
단말 <-> 서버는 “JSON” 포맷이 가볍고 좋을 수 있지만,
실제 “Server to Server” 연동은 가볍고, 빠른게 중요한게 아니라.
데이터의 정합성이 키포인트 입니다.

그럴 경우는 패캣이 다소 무거울수 있더라도 “XML” 포맷으로
해서 보내야 서로 비교 문석하기가 수월 합니다.

대량의 요청을 처리하는 서버는 하나의 바이트도 빼야 한다면
A,B,C” 같은 토큰 방식으로 정의해서 보내야 하는 경우도 있습니다.

이렇듯 “연동 아키텍쳐링“을 할때

명분 없이 단지 “대세”라는 모호한 논리로 맞지도 않은 것을 도입하면
안된다고 생각 합니다.
저희는 개발자이고 아키텍트이기 때문에 “현 Usecase”에 맞는 것인지
냉정한 판단이 필요합니다.

RESTful” 아키텍쳐는 “외부 OpenAPI“에 매우 적합한
연동 아키텍쳐인것 같습니다.
마지막으로 “차니 블로그“님께서 “API Strategy & Strata 2013 Conference” 참관기에서
했던 말을 남기며 본 글을 마무리 하겠습니다.

API 333 목표 : 3초만에 API를 이해하고, 30초만에 API 키를 발급 받아서, 
3분안에 첫번째 요청이 오도록 해라

http://wekeroad.com/2007/12/06/aspnet-mvc-using-restful-architecture/
http://bcho.tistory.com/321
http://bitworking.org/news/201/RESTify-DayTrader
https://dev.twitter.com/docs/api/1.1





댓글
댓글쓰기 폼