Java2011. 8. 2. 14:55

RESTful Web services: The basics

 

Alex Rodriguez (arodrigu@us.ibm.com), Software Engineer, IBM, 06 Nov 2008

원문: https://www.ibm.com/developerworks/webservices/library/ws-restful/

 

번역: RESTful Web Services: The basics (1/2) http://huewu.blog.me/110101220171

번역: RESTful Web Services: The basics (2/2) http://huewu.blog.me/110101273563

 

  REST는 리소스에 초첨을 맞춘 웹 서비스를 디자인할 때 적용할 수 있는, 몇 가지 소프트웨어 디자인 원칙이라고 할 수 있습니다. 리소스 상태를 어떻게 표현하고, 리소스의 위치를 어떻게 표현하며, 다양한 종류의 클라이언트 어플리케이션과 리소스를 어떻게 주고 받을 수 있는지에 관한 내용을 담고 있습니다. 지난 몇 년간 그 간결한 사용법 덕분에, 기존의 SOAP(Simple Object Access Protocol) 이나 WSDL(Web Service Description Language) 기반의 모델을 대신하여, 가장 널리 사용된 는 웹 서비스를 디자인 모델로 사랑받고 있습니다.

 

 2000 Roy Fielding 은 자신의 학위 논문인 "Architectural Styles and the Design of Network-based Software Architectures" 에서, 분산 컴퓨팅을 위한 플랫폼으로서 웹을 사용하고자 할 때 유용한 소프트웨어 아키텍처 디자인 원칙을 정리하고, 이를 REST 라고 이름 붙였습니다. 그리고 몇 년 후, 실제 상용 웹 서비스를 위한 REST 프레임워크가 나타났으며, 2009 12월에 발표된 Java EE 6 버전에서는 RESTful 웹 서비스를 위한 Java API 가 포함되기도 하였습니다.

 

 오늘날 이처럼 각광받고 있는 REST 기술에 관하여, 가장 순수한 형태로 RESTful 한 웹 서비스를 구현하고자 한 다면, 지켜야할 네 가지 기본적인 원칙이 있습니다.

 

1. 명시적으로 HTTP 메서드를 사용할 것.

2. 상태를 저장하지 말 것. (Be stateless)

3. 디렉토리 구조와 유사한 URI 를 사용할 것.

4. XML 혹은 JSON 혹은 두 가지 방법 모두를 사용하여 리소스를 전송할 것.

 

 이 문서에서는, 각각의 항목에 대하여 보다 상세하게 설명하고, 이러한 네 가지 원칙이 REST 웹서비스를 실제로 구현할 때 어떤식으로 적용될 수 있는지 알아보고자 합니다.

 

1. 명시적으로 HTTP 메서드를 사용할 것

 RESTful 한 웹 서비스의 가장 주요한 특징은 바로 RFC 2616 표준에 정의된 대로, HTTP 메서드를 명확하게 구별하여 사용하는 것 입니다. 예를 들어, HTTP GET 메서드는 '데이타 생산'(클라이언트 입장에서) 메서드라고 하는데, 웹서버에서 특정 데이타를 가져오거나, 특정 조건에 부합하는 리소스 목록을 가져올 때 사용하도록 정의되어 있습니다. 그리고 동시에, HTTP GET 메서드는 서버 측에 어떠한 사이드 이펙트를 일으키지 않아야 합니다. 개발자들은 각 메서드에 대한 이러한 제약 조건들을 숙지한 후, 기본적인 CRUD(Create, Read, Update, Delete) 작업에 대하여 이에 대응하는 HTTP 메서드를 사용하도록 웹 서비스를 설계해야 합니다.

 

서버측에 리소스를 생성 할 때는 POST 를 사용합니다.

리소스를 얻어오기 위해서는 GET 을 사용합니다.

리소스의 상태를 변경하거나 값을 업데이트 할 때는 PUT 을 사용합니다.

리소스를 지우거나 삭제할 때는 DELETE 를 사용합니다.

 

 아쉽게도 현재 많은 웹 API 들이 HTTP 메서드를 표준에서 의도하지 않은 방법으로 사용하고 있습니다. 예를 들어 어떤 웹 서비스는 HTTP GET 을 이용하여, 서버측 DB에 데이타를 추가 하는 일을 수행 하기도 합니다. 다음과 같이 말입니다.

 

GET /adduser?name=Robert HTTP/1.1

 

 이러한 요청이 성공적으로 수행된다면 그 결과 새로운 사용자, 위의 예시에서는 'Robert' 라는 이름을 갖는 사용자가 DB에 추가될 것 입니다. 하지만 위 예에서 GET 은 표준에서 의도한대로 사용된 것도 아니며, RESTful 하지도 않습니다. HTTP GET 요청이 특정 URI 에 대응되는 리소스를 가져오는데 사용되는 것이라는 점을 생각해 보면, 위와 같은 인터페이스를 갖는 웹 서버는 HTTP/1.1 호환 웹 서버라고 할 수 없습니다. 더군다나, HTTP GET 요청으로 인해 서버 측의 상태 정보가 변경되며, 예기치 않은 효과를 불러 일으킬 수도 있습니다. 웹 크로울러나 검색 엔진 등이 그저 데이타를 수집하기 위하여 여러분의 웹 서비스를 들락거리는 와중에 예기치 않게, 서버 측의 데이타를 변경하게 될지도 모를 일 입니다.

 

 이런 문제를 해결 할 수 있는 가장 간단한 방법은  HTTP GET 대신에 HTTP POST 를 사용하고, URI 에 위치한 인자 값들을 HTTP 바디 부분에 XML 태그 형식으로 옮겨 담는 것 입니다.

 

Listing 1. Before

GET /adduser?name=Robert HTTP/1.1

Listing 2. After

POST /users HTTP/1.1

Host: myserver

Content-Type: application/xml

<?xml version="1.0"?>

<user>

  <name>Robert</name>

</user>

  위 메서드는 RESTful 요청의 좋은 예입니다. HTTP POST 요청을 받은 서버는 요청된 URI 의 자식 리소스로 전달 받은 데이타를 이용하여 새로운 리소스를 추가합니다. 위의 경우라면 /users 아래에 자식 리소스로 Robert 라는 이름을 갖는 리소스가 추가될 것 입니다. 다시 말해, 특정 디렉토리에 새로운 파일을 생성하는 것과 비슷하다고 할 수 있습니다. 클라이언트는 HTTP POST 요청을 통해, 부모 리소스와 자식 리소스간에 관계를 셋업하고, 새롭게 추가될 리소스의 URI 를 정의합니다. 이후, 클라이언트는 새로운 URI 를 통해 새롭게 추가된 리소스의 '표현형' 을 획득 할 수 있습니다. 적어도, 논리적으로 추가된 리소스는 /users 아래에 있을 것 이기 때문에, 다음과 같이 HTTP GET 요청을 활용할 수 있을 것 입니다.

 

Listing 3. HTTP GET request

GET /users/Robert HTTP/1.1

Host: myserver

Accept: application/xml

  위의 예에서 GET 메서드는 리소스의 표현형을 획득하기 위해 명시적으로 사용되었습니다. 이와 유사하게 서버 측 데이타를 업데이트 하기 위한 API 도 동일한 방식으로 리팩토링 할 수 있습니다.

 

Listing 4. Update over HTTP GET

GET /updateuser?name=Robert&newname=Bob HTTP/1.1

  API GET 메서드를 이용해 리소스의 이름 속성을 변경하고 있습니다. URL 쿼리 스트링을 이용하여 이런 작업을 수행하는 것이 아주 간단해 보일 수도 있지만, 보다 복잡한 작업을 수행하려고 하면 할 수록 이런 형식의 설계 방향은 말썽을 일으키기 쉽습니다. 따라서, 앞서서 살펴본 이유와 동일한 이유로 HTTP GET 대신에 명시적으로 HTTP PUT 을 사용하는 편이 더 좋습니다.

 

Listing 5. HTTP PUT request

PUT /users/Robert HTTP/1.1

Host: myserver

Content-Type: application/xml

<?xml version="1.0"?>

<user>

  <name>Bob</name>

</user>

 REST 원칙과 HTTP 표준 정의에 부합하도록 HTTP PUT 을 사용하도록 API 를 변경해 보았습니다. URI 로 업데이트할 데이터를 가리키고, HTTP 바디 부분에 리소스의 새로운 표현형을 포함합니다. 서버는 이러한 요청을 받아, 리소스의 이름을 Robert 에서 Bob 으로 변경하며, 동시에 해당 리소스에 접근하기 위한 URI /users/Bob 으로 변경될 것 입니다. 따라서, 바로 뒤이어서 이루어지는 /users/Robert 리퀘스트는 404 Not Found 에러를 리턴할 것 입니다.

 

 간단히 정리하자면 이렇습니다. 일반적인 소프트웨어 디자인 관점에서 볼 때, HTTP 메서드를 표준이 정해놓은 방식대로 명식적으로 사용하는 것이 좋습니다. URI 는 특정 리소스를 나타내는 '명사' HTTP 메서드는 해당 리소스에 특정한 작업을 수행하는 '동사'로 생각 할 수 있습니다. 그리고 RESTful 웹 서비스에서는 표준적인 POST, GET, PUT, DELETE 와 같은 동사가 이미 정의되어 있습니다.  이상적으로 말해, 웹 서비스 인터페이스를 잘 정의하고, 클라이언트가 자신들이 수행하고 싶은 작업을 명시적으로 표현 할 수 있도록 한다면, 웹 서비스는 예를 들어 '/adduser' 혹은 '/updateser' 와 같은 '동사' 에 해당 되는 새로운 인터페이스나 리모트 프로시저를 정의할 필요가 없을 것 입니다. 그렇게 되면 HTTP 바디 의 경우에도 기존의 SOAP 이나 WSDL 과 같이 바디 내부에 호출하고자 하는 리모트 프로시저의 이름을 지정할 필요 없고, 순수하게 특정 URI 에 해당하는 리소스의 상태 정보를 전달하는데만 사용 될 수 있을 것 입니다.

 

2. 상태정보를 저장하지 말 것. (Be stateless)

 REST 웹 서비스는 높은 성능 요구 사항을 만족 시킬 수 있을 만큼 확장 가능해야합니다. 글로벌한 웹 서비스를 위해서는, 클러스터를 이루는 서버 위에서, 로드 밸런싱과 오류를 복구하는 기능, 프록시, 게이트웨이등의 요소가 포함된 프레임워크가 구성되어야 하며, 응답 시간을 최소화 하기 위하여, 특정 클라이언트의 요청은 한 서버(처리할 일이 많아서 바쁜)에서 다른 서버(조금 더 자원에 여유가 있는)로 손 쉽게 전달(포워딩)될 수 있어야 합니다. 이를 위해, REST 웹 서비스 클라이언트들이 해당 요청을 처리하는데 필요한 정보가 모두 담겨있는 온전하고 독립적인 방법으로 서버 측에 요청을 전달 할 필요가 있습니다. 그렇게 되면 수 많은 요청을 적절한 서버로 나누어 주어야 하는 중계 서버(Load Balancer)가 개별 요청에 대한 내부 상태 정보를 걱정하지 않고 효율적으로 작업을 분산해서 처리할 수 있습니다.

 

 클라이언트 어플리케이션은 HTTP 헤더와 바디를 이용하여 필요한 모든 종류의 파라매터, 컨텍스트, 데이타 정보를 전달할 수 있습니다. 온전하고 독립적인 형태로 서버 측에 요청이 전달되면, 서버는 해당 요청을 처리하여 적절한 응답을 생성하기 위하여, 클라이언트 어플리케이션 컨텍스트나 상태 정보를 확인 할 필요가 없습니다. 이처럼 서버 측에서 상태 정보를 저장할 필요가 없는 형태 (Stateless) 로 설계가 이루어 지면, 웹 서비스의 성능을 향상 시키는 동시에 서버측의 설계와 구현을 단순화 할 수 있습니다.

 

 그림 1은 서버 측에서 상태 정보를 관리하는 Stateful 한 서비스를 나타냅니다. 서버 측에서 여러 페이지로 이루어 리소스를 클라이언트로 전송 합니다. 클라이언트는 getNextPage API 를 호출하여, 현재 자신이 살펴보고 있는 페이지에서 뒤 이어지는 다음 페이지 리소스를 요청할 수 있습니다. 하지만, 이를 위해서 서버는 현재 어플리케이션이 몇 페이지까지 리소스를 획득해 갖는지에 관한 상태 정보를 저장하고 관리해야 합니다.

 

Figure 1. Stateful design

 

https://www.ibm.com/developerworks/webservices/library/ws-restful/figure1.gif

 이러한 Stateful 서비스는 복잡해 지기 쉽습니다. 예를 들어, 자바 엔터프라이즈 에디션(Java EE) 상에서, Stateful 한 서비스를 구현하기 위해서는 효율적으로 세션 정보를 저장할 수 있고 동시에 클러스터를 이루고 있는 다 수의 Java EE 컨테이너 간에 세션 정보를 동기화 할 수 있도록 다양한 작업이 필요하게 됩니다. 쉽지 않은 일 입니다. 이런 환경에서 많은 웹 서비스 개발자들이 java.io.NotSerializableException 오류를 마주치곤 합니다. 서로 다른 컨터네이간에 세션 정보를 주고 받기 위하여, 세션 정보를 시리얼라이즈하게 되는데, 이 과정에서 적절하게 Serializable 인터페이스를 구현하지 않은 오브젝트가 있는 경우 오류가 발생하게 됩니다. 그러면, 개발자들은 서버 측에서 상태 정보를 구성하는 복잡한 오브젝트 중에서 문제를 일으키는 오브젝트가 무엇인지 찾아 내기 위하여 여러 날을 끙끙대곤 합니다. 거기다가, 설령 오류가 없더라도, 세션 정보를 동기화 하는 과정은 서버 측의 성능에 영향을 줄만큼 오버헤드를 일으킬 수 있습니다.

 

 반면에 상태 정보를 저장하지 않는 Stateless 한 서버측 컴포넌트를 디자인 하고, 구현 하고, 로드 밸런싱 되는 분산 서버로 배포 하는 일은 훨신 덜 복잡합니다. Stateless 한 서비스들은 상태 정보를 관리하는 책임을 대부분 클라이언트 어플리케이션에 위임하며, 훨씬 더 잘 동작합니다. RESTful 한 웹 서비스 상에서 서버는 클라이언트가 자신의 상태 정보를 유지할 수 있도록 인터페이스를 제공하고, 각각의 요청에 적절하게 응답하는 책임을 갖습니다. 예를 들어, 앞에서 살펴본 여러 페이지로 이루어진 리소스를 제공하는 서비스는 다음과 같이 변경 될 수 있습니다.

 

Figure 2. Stateless design

https://www.ibm.com/developerworks/webservices/library/ws-restful/figure2.gif

 

 클라이언트 어플리케이션은 getNextPage 라는 API 대신 자신이 얻고자 하는 페이지 번호를 명시하여 서버 측에 요청을 보냅니다. 서버는 클라이언트의 요청에 대하여, 해당 페이지에 해당하는 리소스 정보 뿐만 아니라, 다음 페이지의 리소스를 요청 할 수 있는 링크 정보를 포함한 응답을 전송합니다. 응답을 수신한 클라이언트는 이 링크 정보를 잘 관리해야 합니다. 이런 관점에서 생각해 볼 때, RESTful 웹 서비스는 크게 두 요소로 구분하여 디자인 될 수 있습니다.

 

서버.

어플리케이션이 서로 연관된 리소스를 탐색 할 수 있도롤 연관된 리소스간의 링크 정보를 포함한 응답을 생성합니다. 예를 들어, 클라이언트가 특정 리소스의 부모 혹은 컨테이너 리소스에 관한 요청을 하는 경우, 서버는 해당 컨테이너에 속한 모든 자식 리소스를 참조할 수 있는 링크들이 포함된 응답을 생성할 수 있습니다.

응답을 생성할 때, 성능 향상을 위하여 해당 응답이 캐싱 될 수 있는지 아닌지에 대하여 기술 합니다. 적절한 캐싱 메커니즘이 적용된다면, 동일한 리소스에 대한 요청 횟수가 줄어 들거나, 어떤 경우 완전히 제거될 수도 있습니다. 서버는 HTTP 헤더 중 Cache-Control Last-Modified 헤더를 사용하여 캐쉬 정책을 관리할 수 있습니다.

클라이언트 어플리케이션.

클라이언트는 정말로 필요한 경우에만 서버 측에 HTTP GET 요청을 전달해야합니다. 서버 측 응답 중에 Cache-Control 헤더를 활용하여, 응답 받은 리소스 정보를 캐쉬할지 말지 결정합니다. Last-Modified 헤더 정보가 있는 경우, If-Modified-Since 헤더를 활용하여, 서버 측에 해당 요청하고 자 하는 리소스가 특정 날짜 이후 변경 되었는지 확인 할 수도 있습니다. 이런 과정은 조건부 GET 이라고 하는데, 만일 서버가 표준에 정의된 304 코드 (Not Modified) 로 응답한다면, 클라이언트는 실재 리소스에 대한 GET 요청 대신, 기존에 자신이 저장해둔 캐쉬 리소스를 활용할 수 있습니다.

서버 측에서다른 요청과는 독립적으로 처리할 수 있는 온전한 요청을 생성하여 전달합니다. 이를 위해, 클라이언트는 웹 서비스에서 정의한 인터페이스대로 HTTP 헤더를 활용하고 HTTP 바디 부분에 완벽한 리소스 표현형을 담아서 전달해야합니다. 클라이언트는 서버 측에서 관리하고 있는 세션 정보, 컨텍스트 정보등등을 가정해서는 안됩니다.

 

 클라이언트 어플리케이션과 서버 측 웹 서비스 컴포넌트 간의 협력이 바로 RESTful 웹 서비스가 Stateless 한 형태로 구성될 수 있는 핵심입니다. Stateless 한 웹 서비스는 사용되는 대역폭(Bandwidth)를 절약하고, 서버 쪽에서 관리하는 어플리케이션 상태 정보를 최소화 함으로서 성능을 향상 시킬 수 있습니다.

 

3. 디렉토리 구조와 유사한 URI 를 사용할 것.

 클라이언트 어플리케이션의 관점에서 살펴보면 , 웹 서비스가 노출한 URI 가 가장 중요합니다. URI 가 얼마나 잘 정의되어 있는지에 따라, 얼마나 해당 웹 서비스를 사용하기 쉬운지, 동시에 올바른 방향으로 사용하게 되닌즈가 결정됩니다. 그런만큼, 세 번째로 소개드릴 RESTful 웹 서비스의 특징은 모두 URI 에 관련된 내용입니다.

 

 REST 웹 서비스가 제공하는 URI 는 쉽게 그 의미를 추측할 수 있을 만큼 직관적이어야 합니다. 일반적인 프로그래밍에서 이름만 보고도 그 의미를 알 수 있는 인터페이스 같은 URI 를 상상해 보세요. URI 문자열만 보고도, 개발자는 해당 URI 가 어떤 리소스를 가리키고 있는지, 그리고 이와 관련된 리소스에는 어떤 것들이 있는지 쉽게 상상할 수 있을 것 입니다. 이를 위하여, URI 의 구조는 이해하기 쉽고 예측 가능하도록 설계되어야 합니다.

 

 이런 요구 사항을 만족시킬 수 있는 한가지 방안은 바로 URI 을 파일 디렉토리 구조와 유사하게 디자인 하는 것 입니다. 파일 디렉토리는 하나의 루트 노드를 기준으로 계층적으로 구성되며, 시스템의 다른 중심 영역 부분 부분을 나타내는 자식 노드로 나누어집니다. 이런식으로 URI 는 단순하게 '/' 로 구분되는 문자열이 아니라, 서로 연관된 노드들로 이루어진 트리 구조로 설계될 수 있습니다. 예를 들어, 다양한 주제에 관하여 토론하는 게시판 서비스를 상상해 본다면, 이런 서비스는 다음과 같은 URI 구조를 갖을 수 있을 것 입니다.

http://www.myservice.org/discussion/topics/{topic}

 루트 노드 뒤에 discussion 노드가 그 뒤에 topics 노드가 위치 하고, 그 뒤에는 gossip, technology 등등의 개별적인 토픽 이름이 위치합니다. 클라이언트 어플리케이션 개발자는 /topics/ 뒤에 원하는 이름을 덧붙여, 특정 주제에 해당하는 게시판을 손쉽게 가져 올 수 있습니다. 어떤 경우에는 특정 리소스를 가리키는 경로 그 자체가 너무나도 자연스럽게 스스로 디렉토리 형식의 구조를 갖는 경우도 있습니다. 예를 들자면, 시간 순으로 정렬되는 리소스를 한번 생각해 보시기 바랍니다.

http://www.myservice.org/discussion/2008/12/10/{topic}

 설명할 필요도 없이 첫 번째 네 글자는 특정 연도를 다음 두 글자는 특정 월 그 다음 두 글자는 특정 일을 나타냅니다. 우리가 URI 의 구조를 설계할 때 추구해야 할 목표가 바로 이 지점입니다. 구조는 단순하고, 서비스 사용자가 이해하기 쉽습니다. URI 를 생성하기 위한 일정한 규칙이 정해지면, 사람이건 기계건 손쉽게 구조적인 URI 를 생성할 수 있습니다. 예를 들어 다음과 같이, URI PATH 각각의 항목의 의미를 명확하게 결정하면, 남은 일은 빈 슬롯에 적절한 문자열을 집어 넣는 것 뿐 입니다.

http://www.myservice.org/discussion/{year}/{day}/{month}/{topic}

 그 외에 RESTful 한 웹 서비스를 위한 URI 구조를 설계할 때 염두해두면 좋은 몇 가지 팁이 있습니다.

서버 측에서 사용되는 스크립트 기술에 관한 파일 확장자는 숨길 것(.jsp, .php, .asp ).

소문자만 사용 할 것.

공백대신 밑줄(_)이나 하이픈(-)을 사용 할 것.

가능한 쿼리 문자열은 사용하지 말 것. (URI 뒤에 ?name='Robert' 식으로 붙는 것)

요청 URI 가 전체 PATH 중에 일부분만을 포함하는 경우 404 Not Found 에러 대신, 기본 페이지나 기본 리소스를 제공할 것.

 마지막으로, URI 는 리소스가 변경되거나 서비스의 내부 로직이 변경되더라도 해당 리소스를 참조할 수 있는 링크 정보가 변경되지 않도록 정적으로 구성되어야 합니다. 이렇게 되면 클라이언트는 특정 리소스를 북마크 해 둘 수 있습니다. 또 한가지, URI 상에 표현되는 리소스간의 관계는 실제 해당 리소스가 물리적으로 어떻게 저장되어 있는지와는 무관하게 독립적으로 유지되어야 합니다.

 

4. XML 혹은 JSON 아니면 두 가지 모두를 지원 할 것.

 리소스 표현형(Representation) 은 클라이언트 어플리케이션이 해당 리소스를 요청한 순간의 리소스의 상태 정보와 속성 값을 반영합니다. 말하자면, 리소스 표현형 이란 해당 리소스에 대한 특정 시간에 촬영한 스냅사진 같은거라고 할 수 있습니다. 단순하게 생각하면 특정 데이타 베이스 저장된 하나의 ROW XML 형식으로 매핑한 것일 수도 있습니다. 혹은 여러분의 시스템에서 갖추고 있는 특정한 데이타 모델에 따라 정교하게 설정된 값일 수도 있겠지요. 여하튼간에 리소스 표현형이란, 여러분이 구현한 REST 웹 서비스에서 서비스 하길 원하는 바로 '그 것' 이라고 할 수 있습니다.

 

 RESTful 웹 서비스를 위해 고려해야할 마지막 제약 조건이 바로 이 리소스를 적절한 포맷에 맞추어 표현하는 방법에 관한 내용입니다. 클라이언트 어플리케이션과 서비스는 HTTP 바디 부분을 통해 정해진 형식으로 리소스 표현형을 주고 받게 됩니다. 따라서, 이 표현형은 가능한 단순하며, 사람이 이해하기 쉽고, 동시에 다양한 리소스 표현형들과 서로 연결 될 수 있어야 합니다.

 

 일반적으로 서비스되는 리소스들간에는 여러가지 연관 관계가 성립하게 됩니다. 그리고 특정 리소스 표현형이 클라이언트로 전달될 때, 이러한 연결관계 또한 함께 전달되어야 합니다. 위에서 예로 든 토론 게시판을 생각해 본다면, 어느 특정 토론을 나타내는 리소스 표현형에는 토론 내용과 몇 가지 속성 값을 물론이고, 해당 내용에 관한 다른 사람들의 의견을 가리키는 링크 정보가 포함되어 있을 것 입니다.

 

 

Listing 6. XML representation of a discussion thread

<?xml version="1.0"?>

<discussion date="{date}" topic="{topic}">

  <comment>{comment}</comment>

  <replies>

    <reply from="joe@mail.com" href="/discussion/topics/{topic}/joe"/>

    <reply from="bob@mail.com" href="/discussion/topics/{topic}/bob"/>

  </replies>

</discussion>

 마지막으로, 클라이언트 어플리케이션이 자신들에게 꼭 알맞은 형태로 리소스 표현형를 요청할 수 있도록, RESTful 한 웹 서비스는 HTTP Accept 헤더를 활용할 수 있습니다. HTTP Accept 헤더에는 클라이언트가 원하는 리소스 표현형에 대한 MIME 타입 정보가 담겨 있으며, 일반적으로 RESTful 서비스에서는 다음과 같은 MIME 타입을 사용하고 있습니다.

 

Table 1. Common MIME types used by RESTful services

 

 MIME-Type                        Content-Type

 application/json                       JSON

 application/xml                         XML

 pplication/xhtml+xml                  XHTML

 

 

 JSON XML 을 모두 지원하는 서비스는 다양한 프로그래밍 언어, 다양한 디바이스, 다양한 플랫폼에서 동작하는 다양한 종류의 클라이언트에서 사용될 수 있습니다. MIME 타입과 HTTP Accept 헤더를 이용하여 적절한 리소스 표현형을 요청하고 이에 응답하는 과정은 이른바 '컨텐트 협상(Content Negotiation)' 과정이라고 알려진 메카니즘으로, 클라이언트가 자신에게 가장 적합한 데이타 포맷을 직접 선택할 수 있게 함으로, 서비스와 서비스를 사용하는 어플리케이션간의 데이타 의존성을 최소화 할 수 있게 해 줍니다.

 

결론

 REST 는 만병 통치약은 아닙니다. 기존의 SOAP 이나 WSDL 과 같은 방법과 비교하여 미들웨어에 보다 덜 의존적인 웹 서비스를 디자인하는 하나의 방법론입니다. 그리고 REST URI HTTP 와 같은 인터넷 표준 규약을 보다 잘 준수하여, 웹을 보다 더 웹 답게 사용할 수 있는 방법이기도 합니다. 또한, 지금까지 살펴본 HTTP 표준 메서드와 간결한 XML 을 사용하는 RESTful 인터페이스 디자인 원칙은 자바 스크립트나 플래쉬 등의 클라이언트 단 어플리케이션에서 손쉽게 특정 리소스를 가리키고 사용할 수 있도록 해줍니다. 사실 오늘날 REST 가 각광받는 가장 주요한 이유중에 하나가 바로 이것입니다.

 

 시스템의 리소스를 RESTful API 를 통해 노출하는 것은, 다양한 종류의 데이타 포맷을 표준적인 방법으로 제공할 수 있는 유연한 방법입니다. 이에 따라, API를 사용하는 웹 개발자들은 특정 서비스에서 제공하는 리소스를 이용하여 손쉽게 메시업된 다양한 서비스를 만들 수 있습니다. 이 문서는 REST 에 관한 아주 기본적인 사항들에 대해서만 다루고 있지만, 저는 이 글이 이 주제에 관해 보다 다양한 내용을 살펴볼 수 있도록 흥미를 돋구는데 도움이 되었기를 희망합니다.

Posted by Brian Hwang
Oracle2011. 8. 2. 14:46
####################################################
.bash_profile 환경변수
    export ORACLE_BASE=/home/oracle
    export ORACLE_HOME=$ORACLE_BASE/oracle/product/10.2.0/db_1
    export ORACLE_SID=ora10
    export LD_LIBRARY_PATH=$ORACLE_HOME/lib
    #export LD_ASSUME_KERNEL=2.4.19
    export PATH=$PATH:$ORACLE_HOME/bin
    
    export NLS_LANG=KOREAN_KOREA.KO16KSC5601       #한글
    export NLS_LANG=KOREAN_KOREA.KO16MSWIN949    #한글(추천:지원캐릭터가 더 많음 -뷃,숖..)
    export NLS_LANG=AMERICAN_AMERICA.UTF8            #유니코드


    
####################################################
캐릭터 셋 설정 확인

    SELECT NAME,VALUE$ FROM PROPS$ WHERE NAME ='NLS_LANGUAGE' OR
                NAME ='NLS_TERRITORY' OR NAME ='NLS_CHARACTERSET';



####################################################
오라클 캐릭터 셋 변경

    update props$ set VALUE$='UTF-8' where name='NLS_CHARACTERSET';
    update props$ set VALUE$='KO16MSWIN949' where name='NLS_CHARACTERSET';
    update props$ set VALUE$='KO16KSC5601' where name='NLS_CHARACTERSET';
    
    update props$ set VALUE$='KOREAN' where name='NLS_LANGUAGE';
    update props$ set VALUE$='KOREA' where name='NLS_TERRITORY';
    


####################################################
캐릭터 셋 변경후에 확인 사항(필수)

    에러 유형 : 
        EXP-00008: ORACLE 오류 6552가 발생했습니다
        ORA-06552: PL/SQL: Compilation unit analysis terminated
        ORA-06553: PLS-553: 알 수 없는 문자 집합 이름입니다


    Problem description
    ===================
    You receive the following error when (re)compiling or calling a piece of pl/sql:
    ORA-06550: line <num>, column <num>: ....
    or
    ORA-06552: PL/SQL: Compilation unit analysis terminated
    followed by
    ORA-06553: PLS-553: character set name is not recognized
  에러 원인 :  character set 이 섞여있음.

 

    캐릭터셋 확인 쿼리 : 
    select distinct(nls_charset_name(charsetid)) CHARACTERSET,
           decode(type#, 1, decode(charsetform, 1, 'VARCHAR2', 2, 'NVARCHAR2','UNKOWN'),
                         9, decode(charsetform, 1, 'VARCHAR', 2, 'NCHAR VARYING', 'UNKOWN'),
                        96, decode(charsetform, 1, 'CHAR', 2, 'NCHAR', 'UNKOWN'),
                       112, decode(charsetform, 1, 'CLOB', 2, 'NCLOB', 'UNKOWN')) TYPES_USED_IN
       from sys.col$ where charsetform in (1,2) and type# in (1, 9, 96, 112);

    캐릭터셋 확인 쿼리 결과(잘못된 경우): varchar2가 2개 의 캐릭터셋이 설정되어있음.
        CHARACTERSET                            TYPES_USED_IN
        -----------------------------------------------------
        AL16UTF16                               NCHAR
        AL16UTF16                               NVARCHAR2
        AL16UTF16                               NCLOB
        US7ASCII                                CHAR
        US7ASCII                                VARCHAR2
        WE8DEC                                 VARCHAR2
        US7ASCII                                CLOB
        
        
    캐릭터셋 확인 쿼리 결과(정상인 경우): TYPES_USERD_IN 하나당 하나의 캐릭터셋
        CHARACTERSET                            TYPES_USED_IN
        -----------------------------------------------------
        AL16UTF16                               NCHAR
        AL16UTF16                               NVARCHAR2
        AL16UTF16                               NCLOB
        AL32UTF8                                CHAR
        AL32UTF8                                VARCHAR2
        AL32UTF8                                CLOB


    해결 방법 : 

        1. INIT.ORA 안에 있는 parallel_server parameter 가 false 거나 아예 세팅되어있지 않은지 확인.
           SQL>show parameter parallel_server

        2. sqlplus "/as sysdba"로 다음 쿼리 실행(기존 데이터 백업 필수)
           SHUTDOWN IMMEDIATE;
           STARTUP MOUNT;
           ALTER SYSTEM ENABLE RESTRICTED SESSION;
           ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
           ALTER SYSTEM SET AQ_TM_PROCESSES=0;
           ALTER DATABASE OPEN;
           COL VALUE NEW_VALUE CHARSET
           SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER='NLS_CHARACTERSET';
           COL VALUE NEW_VALUE NCHARSET
           SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER='NLS_NCHAR_CHARACTERSET';
   
           -- UTF8로 바꿀 경우(선택)
           ALTER DATABASE CHARACTER SET INTERNAL_USE UTF8;
           ALTER DATABASE NATIONAL CHARACTER SET INTERNAL_USE AL16UTF16;
   
             -- 한글로 바꿀 경우(선택)
           ALTER DATABASE CHARACTER SET INTERNAL_USE KO16MSWIN949
           ALTER DATABASE NATIONAL CHARACTER SET INTERNAL_USE AL16UTF16;
           
           -- oracle reboot 2번.
           SHUTDOWN IMMEDIATE;
           STARTUP;
           SHUTDOWN IMMEDIATE;
           STARTUP;

        3. parallel_server parameter 수정한 경우 원복.
Posted by Brian Hwang