프로그래밍 2014. 12. 4. 13:59

크롬을 활용하여 자바스크립트의 메모리 상태 및 기타 성능등을 측정 할 수 있는 내용

원문 : http://www.smashingmagazine.com/2012/06/12/javascript-profiling-chrome-developer-tools/

javascript profile.pdf


//
프로그래밍 2014. 11. 22. 18:53
Object.keys(JSON[0]);


//
Linux 2014. 10. 25. 11:18

Sep 26, 2013 3:22:14 PM Error: Starting VM 'Ubuntu Precise Pangolin 12.04 (64-bit)' - The bootloader for this VM returned an error -- did the VM installation succeed?  INVALID_SOURCE

Unable to access a required file in the specified repository: http://archive.ubunut.com/ubuntu/dists/precise/main/installer-amd64/current/images/netboot/xen/vmlinuz.


이런식으로 나오는걸

xe vm-list 로 설치하고자 하는 vm의 uuid를 얻어 온 뒤 boot 옵션들은 수정하여 재시작 한다


xe vm-param-set uuid=13005686-4547-599f-9e59-148982868d68 HVM-boot-policy="BIOS order"

xe vm-param-set uuid=13005686-4547-599f-9e59-148982868d68 HVM-boot-params:order=cd

'Linux' 카테고리의 다른 글

쉘스크립트 숫자반복  (0) 2014.12.30
VI에서 찾아바꾸기 등  (0) 2014.09.22
Mysql 컴파일 설치 절차(리눅스에서)  (0) 2014.06.16
sed awk 사용법  (0) 2014.06.01
Linux process explorer  (0) 2014.05.07
//
Linux 2014. 9. 22. 14:45

문자열 찾기(Find)


* 현재 문서를 편집중이라면, 키보드의 Esc 키를 눌러 편집모드에서 빠져나옵니다.

* 키보드의 슬래쉬(/)키를 누르고, 찾을 문자열을 입력합니다. 만약 foo 라는 문자열을 찾는다면

/foo

이렇게 하면 됩니다.

그런데 /키는, 위에서 아래로 찾는 것입니다.

아래에서 위쪽 방향으로 찾으려면 물음표(?)키를 사용합니다. 현재 커서 위치의 위쪽에 있는 foo 라는 문자열을 찾으려면

?foo

라고 하면 됩니다.


다음 문자열(문자) 계속 찾기


다음 문자열 찾기는 소문자 n 입니다. 만약 foo 가 여러 개 있다면, 아래쪽 foo들을 계속 찾게 하는 것입니다.

역방향으로 계속 찾으려면 대문자 N 을 누릅니다.

※ 엔터키를 눌러서 일반모드로 나온 후 n을 눌러야 합니다. 찾을 문자열 뒤에 그냥 n을 붙이면 안 됩니다.
후추나님의 코멘트를 보고 나서야, 여기에 대한 설명이 부족했다는 것을 알았습니다.^^;


대소문자 구분 없이 찾기


Vim은 대소문자를 구분하여 찾기에 불편합니다. Vim 설정 파일인 .vimrc또는 _vimrc 파일에,
set ignorecase
이런 줄을 삽입하면 대소문자 구분 없이 찾기를 할 수 있습니다. (▶▶ [.vimrc] Vim / Gvim 설정 파일 예제 - 리눅스 텍스트 에디터 참고)





문자열 바꾸기(치환)


* 현재 문서를 편집중이라면, 키보드의 Esc 키를 눌러 편집모드에서 빠져나옵니다.

* 콜론(:)을 누르고 %s/foo/bar 라고 하면 모든 foo라는 문자열이 bar로 한꺼번에 치환됩니다.

다음과 같이 c 라는 옵션을 붙이면

:%s/foo/bar/c

바꿀 때마다 바꾸어도 좋은지 물어보기에 더 안전합니다. y를 누르면 바꾸고, n을 누르면 다음으로 건너뛰고, a를 누르면 모두 바꿉니다.


:%s/\<foo\>/bar


이렇게 하면 정확하게 foo에 일치될 때만 바꿉니다. 즉 foo는 바꾸지만, foo 앞뒤로 다른 문자열이 붙어 있는 경우, 예를 들어
fooZZZ
ZZZfoo
ZZZfooZZZ
이런 문자열 속의 foo 는 바꾸지 않습니다.



대소문자 구분없이 바꾸려면

:%s/foo/bar/i

이렇게 i 옵션을 붙입니다. 이것은 ".vimrc" 파일을 고치지 않아도 작동합니다.




전역 치환


이 경우
foofoofoofoofoofoofoofoo

이렇게
barfoofoofoofoofoofoofoo

문장의 첫번째 foo만 bar로 치환됩니다. 문장의 모든 foo를 bar로 치환하려면

:%s/foo/bar/g

이렇게 g 옵션을 사용합니다.


:%s/foo/bar/gi

이렇게 여러 옵션을 혼용할 수도 있습니다.

//
프로그래밍 2014. 6. 22. 21:49

원격저장소로 GitHub을 이용하고 있고, Branch를 만들고 삭제하는 방법에 대해서 알아보자. 


1) 브랜치 생성, 삭제 순서 

  - local 저장소에 branch를 만든다 

  - remote 저장소로 branch를 push 하여 추적(tracking) 한다 

  - 사용하지 않는 branch는 삭제한다 

////////////////////////////////////////////////

// 새로운 브랜치를 생성하고 checkout 한다 

git checkout -b shopping_cart

Switched to a new branch 'shopping_cart'


////////////////////////////////////////////////

// 원격 저장소로 브랜치를 push 한다 

git push origin shopping_cart

Username for 'https://github.com':

Password for 'https://ysyun@yuwin.co.kr@github.com':

Total 0 (delta 0), reused 0 (delta 0)

To https://github.com/ysyun/pro_git.git

 * [new branch]      shopping_cart -> shopping_cart


// github에 새로운 브랜치가 추가 되었다. 


///////////////////////////////////////////////

// 새로운 파일을 추가하고 원격으로 push 한다 

$ touch cart.js

$ git add cart.js

$ git commit -m "add cart javascript file"

[shopping_cart 4856f8d] add cart javascript file

 0 files changed

 create mode 100644 cart.js


git push

Username for 'https://github.com':

Password for 'https://ysyun@yuwin.co.kr@github.com':

Counting objects: 3, done.

Delta compression using up to 2 threads.

Compressing objects: 100% (2/2), done.

Writing objects: 100% (2/2), 245 bytes, done.

Total 2 (delta 1), reused 0 (delta 0)

To https://github.com/ysyun/pro_git.git

   f42a865..4856f8d  shopping_cart -> shopping_cart


///////////////////////////////////////////////

// 로컬 브랜치 내역 과 원격 브랜치 내역을 본다 

git branch

  master

* shopping_cart


git branch -r

  origin/HEAD -> origin/master

  origin/master

  origin/shopping_cart


////////////////////////////////////////////////////

// 로컬의 새로 추가한 shopping_cart 브랜치를 삭제한다

$ git checkout master

Switched to branch 'master'


$ git branch -d shopping_cart

error: The branch 'shopping_cart' is not fully merged.

If you are sure you want to delete it, run 'git branch -D shopping_cart'.


$ git branch -D shopping_cart

Deleted branch shopping_cart (was 4856f8d).


$ git branch

* master


///////////////////////////////////////////////

// 로컬에 이제 shopping_cart 브랜치가 없다 다시 복구 하고 싶다면

// 원격 저장소를 통하여 checkout 하면 된다 

git checkout shopping_cart

Branch shopping_cart set up to track remote branch shopping_cart from origin.

Switched to a new branch 'shopping_cart'


$ git branch

  master

* shopping_cart


///////////////////////////////////////////////

// 원격의 브랜치 내역을 보자

// 어떤 브랜치들이 존재하는지 한눈에 알 수 있다 

git remote show origin

* remote origin

  Fetch URL: https://github.com/ysyun/pro_git.git

  Push  URL: https://github.com/ysyun/pro_git.git

  HEAD branch: master

  Remote branches:

    master        tracked

    shopping_cart tracked

  Local branches configured for 'git pull':

    master        merges with remote master

    shopping_cart merges with remote shopping_cart

  Local refs configured for 'git push':

    master        pushes to master        (up to date)

    shopping_cart pushes to shopping_cart (up to date)


///////////////////////////////////////////////

// 원격에 있는 브랜치를 삭제 하자 

$ git push origin :shopping_cart

Username for 'https://github.com':

Password for 'https://ysyun@yuwin.co.kr@github.com':

To https://github.com/ysyun/pro_git.git

 - [deleted]         shopping_cart


// shopping_cart 브랜치가 삭제되었음을 알 수 있다

$ git remote show origin

* remote origin

  Fetch URL: https://github.com/ysyun/pro_git.git

  Push  URL: https://github.com/ysyun/pro_git.git

  HEAD branch: master

  Remote branch:

    master tracked

  Local branch configured for 'git pull':

    master merges with remote master

  Local ref configured for 'git push':

    master pushes to master (up to date)


///////////////////////////////////////////////

// remote 브랜치 clean up 하기 

git remote prune origin


UserXP@NUKNALEA /d/Git_repositories/pro_git (master)

$ git remote show origin

* remote origin

  Fetch URL: https://github.com/ysyun/pro_git.git

  Push  URL: https://github.com/ysyun/pro_git.git

  HEAD branch: master

  Remote branch:

    master tracked

  Local branch configured for 'git pull':

    master merges with remote master

  Local ref configured for 'git push':

    master pushes to master (up to date)


2) master가 아닌 local 브랜치를 remote 저장소의 master 브랜치에 push 하기 

  - 조건 : local 저장소의 브랜치가 master가 아닌 다른 브랜치로 checkout 되어 있을 경우 예) shopping_cart

  - 명령 :  git push [원격저장소 주소 alias] [로컬저장소명칭]:master

  - 예 : git push origin shopping_cart:master

  - 의미 : origin 원격 주소의 master 브랜치에 local저장소의 shopping_cart 브랜치를 push 한다


출처 : http://mobicon.tistory.com/163


//
프로그래밍/java 2014. 6. 22. 16:02

http://stophyun.tistory.com/37

//
프로그래밍/java 2014. 6. 22. 15:54

 

즉 특정 URL의 웹프로그램을 실행 시키는게 목적이거나

 

특정 URL의 내용을 읽어 오는게 목적이라면..

 

URLConnection객체를 사용

 

import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;

 

public class URLConn{
    public static void main(String args[]){
        URL url;//URL 주소 객체
        URLConnection connection;//URL접속을 가지는 객체
        InputStream is;//URL접속에서 내용을 읽기위한 Stream
        InputStreamReader isr;
        BufferedReader br;

        try{
            //URL객체를 생성하고 해당 URL로 접속한다..
            url = new URL(args[0]);
            connection = url.openConnection();

            //내용을 읽어오기위한 InputStream객체를 생성한다..
            is = connection.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);

            //내용을 읽어서 화면에 출력한다..
            String buf = null;
            while(true){
                buf = br.readLine();
                if(buf == null) break;
                System.out.println(buf);
            }
        }catch(MalformedURLException mue){
            System.err.println("잘못되 URL입니다. 사용법 : java URLConn http://hostname/path]");
            System.exit(1);
        }catch(IOException ioe){
            System.err.println("IOException " + ioe);
            ioe.printStackTrace();
            System.exit(1);
        }
    }
};


//
Linux 2014. 6. 16. 15:35

1)  사이트 방문하여 소스 다운로드 하기

- 각 OS 버전에 맞게 설치파일을 다운로드를 받을 수 있다.

 

http://dev.mysql.com/downloads/mysql/

(주의) 컴파일용으로 다운받기 위해서는 Platform을 "Source Code"를 선택하고 Compressed TAR Archive 를 다운받는다.)

 

2) wget으로 소스 다운로드 하기

# wget http://downloads.mysql.com/archives/mysql-5.0/mysql-5.0.85.tar.gz

 

[MySQL 리눅스에 간단 설치하기]

 

1) usr/local/src          <-- 여기에 다운로드

2) /usr/local/src 에 압축품 (# tar zxvf mysql-5.0.85.tar.gz )

3) mysql-5.0.85 폴더 생성됨 ( /usr/local/mysql-5.0.85 )

4) ./configure --prefix=/usr/local/mysql \
--localstatedir=/usr/local/mysql/data \
--with-charset=euckr \
--with-innodb \
--with-mysqld-user=mysql \
--without-debug \
--enable-large-files \
--with-unix-socket-path=/var/lib/mysql/mysql.sock \
--with-client-ldflags=-all-static --with-mysqld-ldflags=-all-static \
--without-debug \
--without-docs

5) make

6) make install

또는 5) 6) make && make install 같음.

이것으로 설치는 완료 됨.

//
프로그래밍 2014. 6. 16. 15:33

동사보다는 명사를 사용하자

URL을 심플하고 직관적으로 만들자

REST API를 URL만 보고도, 직관적으로 이해할 수 있어야 한다
URL을 길게 만드는것 보다, 최대 2 depth 정도로 간단하게 만드는 것이 이해하기 편하다.

/dogs
/dogs/1234

URL에 동사보다는 명사를 사용한다.

REST API는 리소스에 대해서 행동을 정의하는 형태를 사용한다. 예를 들어서

POST /dogs

는 /dogs라는 리소스를 생성하라는 의미로, URL은 HTTP Method에 의해 CRUD (생성,읽기,수정,삭제)의 대상이 되는 개체(명사)라야 한다.
잘못된 예들을 보면

HTTP Post : /getDogs
HTTP Post : /setDogsOwner

위의 예제는 행위를 HTTP Post로 정의하지 않고, get/set 등의 행위를 URL에 붙인 경우인데, 좋지 않은 예 이다. 이보다는

HTTP Get : /dogs
HTTP Post : /dogs/{puppy}/owner/{terry}

를 사용하는 것이 좋다.
일반적으로 권고되는 디자인은 다음과 같다.

리소스POSTGETPUTDELETE
createreadupdatedelete
/dogs새로운 dogs 등록dogs 목록을 리턴Bulk로 여러 dogs 정보를 업데이트모든 dogs 정보를 삭제
/dogs/baduk에러baduk 이라는 이름의 dogs 정보를 리턴baduk이라는 이름의 dogs 정보를 업데이트baduk 이라는 이름의 dogs 정보를 삭제

단수(Singular) 보다는 복수(Plural)형 명상를 사용한다.

되도록이면 추상적인 이름보다 구체적인 이름을 사용하자

리소스간의 관계를 표현하는 방법

Option A.

다른 리소스와의 관계를 표현. 예를 들어 owner가 가지고 있는 개(dogs) 목록

GET /owner/{terry}/dogs

와 같이 /resource명/identifier/other-related-resource 형태로, 해당 리소스에 대한 경로를 /resource명/{그 리소스에 대한 identifier}/{연관되는 다른 리소스 other-related-resource} 형태로 표현한다.

Option B.

https://usergrid.incubator.apache.org/docs/relationships/ 에 보면 다른 형태의 관계 정의 방법에 대해서 나와 있는데, 조금 더 구체적인 API 관계 정의 방법은 다음과 같다.

/resource/identifier/relation/other-related-resource
GET /owner/terry/likes/dogs

리소스간의 관계가 복잡하지 않은 서비스의 경우에는 Option A를, 리소스간의 관계가 다소 복잡한 경우에는 Option B를 사용하도록 한다.

" style="margin: 1em 0px; word-wrap: break-word; color: rgb(0, 0, 0); font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', AppleSDGothicNeo-Medium, 'Segoe UI', 'Malgun Gothic', Verdana, Tahoma, sans-serif; font-size: 11px; line-height: normal;">이 방식은 리소스간의 관계(relationship)을 URL 내에 정의하는 방법으로,훨씬 더 명시적일 수 있다. (세련되어 보이지는 않지만)
리소스간의 관계가 복잡하지 않은 서비스의 경우에는 Option A를, 리소스간의 관계가 다소 복잡한 경우에는 Option B를 사용하도록 한다.

에러 처리

에러 처리의 기본은 HTTP Response Code를 사용한후, Response body에 error detail을 사용해주는 것이 좋다.

Use HTTP Status Code

HTTP Status Code는 대략 70개의 코드가 있다. 일반적인 개발자들이 모든 코드를 기억할리는 없고, 에러 코드에서는 자주 사용되는 몇개의 코드만 의미에 맞춰서 사용하는 것이 좋다.
Google의 GData의 경우에는 10개, Neflix의 경우에는 9개, Digg의 경우에는 8개를 사용한다.
(※ http://info.apigee.com/Portals/62317/docs/web%20api.pdf)

  • Google GData
    200 201 304 400 401 403 404 409 410 500
  • Netflix
    200 201 304 400 401 403 404 412 500
  • Digg
    200 400 401 403 404 410 500 503

필자의 경우, 아래와 같은 정도의 HTTP Code를 사용하기를 권장한다.

  • 200 성공
  • 400 Bad Request - field validation 실패시
  • 401 Unauthorized - API 인증,인가 실패
  • 404 Not found
  • 500 Internal Server Error - 서버 에러

자세한 HTTP Status Code는 http://en.wikipedia.org/wiki/Http_error_codes 를 참고하기 바란다.

Error Message

HTTP Status Code 이외에, Response body에 detail한 에러 정보를 표현하는 것이 좋은데,
Twillo의 Error Message 형식의 경우

HTTP Status Code : 401
{“status”:”401”,”message”:”Authenticate”,”code”:200003,”more info”:”http://www.twillo.com/docs/errors/20003"}

와 같이 표현하는데, 에러 코드 #와 해당 에러 코드 #에 대한 Error dictionary link를 제공한다.
비단 API 뿐 아니라, 잘 정의된 소프트웨어 제품의 경우에는 별도의 Error # 에 대한 Dictionary 를 제공하는데, Oracle의 WebLogic의 경우에도http://docs.oracle.com/cd/E24329_01/doc.1211/e26117/chapter_bea_messages.htm#sthref7 와 같이 Error #와, 이에 대한 자세한 설명과, 조치 방법등을 설명한다. 이는 개발자나 Trouble Shooting하는 사람에게 많은 정보를 제공해서, 조금 더 디버깅을 손쉽게 한다. (가급적이면 Error Code #를 제공하는 것이 좋다.)

Error Stack

에러메세지에서 Error Stack 정보를 출력하는 것은 대단히 위험한 일이다. 내부적인 코드 구조와 프레임웍 구조를 외부에 노출함으로써, 해커들에게, 해킹을 할 수 있는 정보를 제공하기 때문이다. 일반적인 서비스 구조에서는 아래와 같은 에러 스택정보를 API 에러 메세지에 포함 시키지 않는 것이 바람직 하다.

log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: stacktrace.log (Permission denied)
at java.io.FileOutputStream.openAppend(Native Method)
at java.io.FileOutputStream.(FileOutputStream.java:177)
at java.io.FileOutputStream.(FileOutputStream.java:102)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:290)
at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:164)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

그렇지만, 내부 개발중이거나 디버깅 시에는 매우 유용한데, API 서비스를 개발시, 서버의 모드를 production과 dev 모드로 분리해서, 옵션에 따라 dev 모드등으로 기동시, REST API의 에러 응답 메세지에 에러 스택 정보를 포함해서 리턴하도록 하면, 디버깅에 매우 유용하게 사용할 수 있다.

버전 관리

API 정의에서 중요한 것중의 하나는 버전 관리이다. 이미 배포된 API 의 경우에는 계속해서 서비스를 제공하면서,새로운 기능이 들어간 새로운 API를 배포할때는 하위 호환성을 보장하면서 서비스를 제공해야 하기 때문에, 같은 API라도 버전에 따라서 다른 기능을 제공하도록 하는 것이 필요하다.
API의 버전을 정의하는 방법에는 여러가지가 있는데,

  • Facebook ?v=2.0
  • salesforce.com /services/data/v20.0/sobjects/Account
    필자의 경우에는

    {servicename}/{version}/{REST URL}
    example) api.server.com/account/v2.0/groups

형태로 정의 하는 것을 권장한다.
이는 서비스의 배포 모델과 관계가 있는데, 자바 애플리케이션의 경우, account.v1.0.war, account.v2.0.war와 같이 다른 war로 각각 배포하여 버전별로 배포 바이너리를 관리할 수 있고, 앞단에 서비스 명을 별도의 URL로 떼어 놓는 것은 향후 서비스가 확장되었을 경우에, account 서비스만 별도의 서버로 분리해서 배포하는 경우를 생각할 수 있다.
외부로 제공되는 URL은 api.server.com/account/v2.0/groups로 하나의 서버를 가르키지만, 내부적으로, HAProxy등의 reverse proxy를 이용해서 이런 URL을 맵핑할 수 있는데, api.server.com/account/v2.0/groups를 내부적으로 account.server.com/v2.0/groups 로 맵핑 하도록 하면, 외부에 노출되는 URL 변경이 없이 향후 확장되었을때 서버를 물리적으로 분리해내기가 편리하다.

페이징 처리와 Partial response

페이징

큰 사이즈의 리스트 형태의 응답을 처리하기 위해서 필요한 것은 페이징 처리와 partial response 처리이다. 리스트 내용이 1000,000개인데, 이를 하나의 HTTP Response로 처리하는 것은 서버 성능, 네트워크 비용도 문제지만 무엇보다 비현실적이다. 그래서, 페이징을 고려하는 것이 중요하다.
페이징을 처리하기 위해서는 여러가지 디자인이 있다.

예를 들어 100번째 레코드부터 125번째 레코드까지 받는 API를 정의하면

  • Facebook API 스타일 : /record?offset=100&limit=25
  • Twitter API 스타일 : /record?page=5&rpp=25 (RPP는 Record per page로 페이지당 레코드수로 RPP=25이면 페이지 5는 100~125 레코드가 된다.)
  • LikedIn API 스타일 : /record?start=50&count=25

apigee의 API가이드를 보면 좀더 직관적이라는 이유로 페이스북 스타일을 권장하고 있다.
record?offset=100&limit=25

Partial Response (Optional)

리소스에 대한 응답 메세지에 대해서 굳이 모든 필드를 포함할 필요가 없는 케이스가 있다. 예를 들어 페이스북 FEED의 경우에는 사용자 ID, 이름, 글 내용, 날짜, 좋아요 카운트, 댓글, 사용자 사진등등 여러가지 정보를 갖는데, API를 요청하는 Client의 용도에 따라 선별적으로 몇가지 필드만이 필요한 경우가 있다. 필드를 제한하는 것은 전체 응답의 양을 줄여서 네트워크 대역폭(특히 모바일에서) 절약할 수 있고, 응답 메세지를 간소화하여 파싱등을 간략화할 수 있다.
그래서 몇몇 잘 디자인된, REST API의 경우 이러한 Partial Response 기능을 제공하는데, 주요 서비스들을 비교해보면 다음과 같다.

  • Linked in : /people:(id,first-name,last-name,industry)
  • Facebook : /terry/friends?fields=id,name
  • Google : ?fields=title,media:group(media:thumnail)
    Linked in 스타일의 경우 가독성은 높지만 :()로 구별하기 때문에, HTTP 프레임웍으로 파싱하기가 어렵다. 전체를 하나의 URL로 인식하고, :( 부분을 별도의 Parameter로 구별하지 않기 때문이다.
    Facebook과 Google은 비슷한 접근 방법을 사용하는데, 특히 Google의 스타일은 더 재미있는데, group(media:thumnail) 와 같이 JSON의 Sub-Object 개념을 지원한다.
    Partial Response는 Google 스타일을 이용하는 것을 권장한다.

검색

검색은 일반적으로 HTTP GET에서 Query String에 검색 조건을 정의하는 경우가 일반적인데, 이 경우 검색조건이 다른 Query String과 섞여 버릴 수 있다. 예를 들어 name=cho이고, region=seoul인 사용자를 검색하는 검색을 Query String만 사용하게 되면 다음과 같이 표현할 수 있다.
/users?name=cho&region=seoul
그런데, 여기에 페이징 처리를 추가하게 되면

/users?name=cho&region=seoul&offset=20&limit=10

페이징 처리에 정의된 offset과 limit가 검색 조건인지 아니면 페이징 조건인지 분간이 안간다. 그래서, 쿼리 조건은 하나의 Query String으로 정의하는 것이 좋은데

/user?q=name%3Dcho,region%3Dseoul&offset=20&limit=10

이런식으로 검색 조건을 URLEncode를 써서 “q=name%3Dcho,region%3D=seoul” 처럼 (실제로는 q= name=cho,region=seoul )표현하고 Deleminator를 , 등을 사용하게 되면 검색 조건은 다른 Query 스트링과 분리된다.
물론 이 검색 조건은 서버에 의해서 토큰 단위로 파싱되어야 하낟.

전역 검색과 리소스 검색

다음으로는 검색의 범위에 대해서 고려할 필요가 있는데, 전역 검색은 전체 리소스에 대한 검색을, 리소스에 대한 검색은 특정 리소스에 대한 검색을 정의한다.
예를 들어 시스템에 user,dogs,cars와 같은 리소스가 정의되어 있을때,id=’terry’인 리소스에 대한 전역 검색은

/search?q=id%3Dterry

와 같은 식으로 정의할 수 있다. /search와 같은 전역 검색 URI를 사용하는 것이다.
반대로 특정 리소스안에서만의 검색은

/users?q=id%3Dterry

와 같이 리소스명에 쿼리 조건을 붙이는 식으로 표현이 가능하다.

HATEOAS (Optional)

HATEOS는 Hypermedia as the engine of application state의 약어로, 디자인의 요지는 하이퍼미디어의 특징을 이용하여 HTTP Response에 다음 Action에 대한 HTTP Link를 함께 리턴하는 것이다.
예를 들어 앞서 설명한 페이징 처리의 경우, 리턴시, 전후페이지에 대한 링크를 제공한다거나

HTTP GET users?offset=10&limit=5
{
[
{‘id’:’user1’,’name’:’terry’}
,{‘id’:’user2’,’name’:’carry’}
]
,’links’ :[
{
‘rel’:’pre_page’,
‘href’:’http://xxx/users?offset=6&limit=5
}
,
{
‘rel’:’next_page’,
‘href’:’http://xxx/users?offset=11&limit=5
}
]
}
와 같이 표현하거나
연관된 리소스에 대한 디테일한 링크를 표시 하는 것등에 이용할 수 있다.
HTTP GET users/terry
{
‘id’:’terry’
‘links’:[{
‘rel’:’friends’,
‘href’:’http://xxx/users/terry/friends
}]
}

HATEOAS를 API에 적용하게 되면, Self-Descriptive 특성이 증대되어 API에 대한 가독성이 증가하는 장점을 가지고 있기는 하지만, 응답 메세지가 다른 리소스 URI에 대한 의존성을 가지기 때문에, 구현이 다소 까다롭다는 단점이 있다.
요즘은 Spring과 같은 프레임웍에서 프레임웍 차원에서 HATEOAS를 지원하고 있으니 참고하기 바란다.http://spring.io/understanding/HATEOAS

단일 API URL

API 서버가 물리적으로 분리된 여러개의 서버에서 동작하고 있을때, user.apiserver.com, car.apiserver.com과 같이 API 서비스마다 URL이 분리되어 있으면 개발자가 사용하기 불편하다. 매번 다른 서버로 연결을 해야하거니와 중간에 방화벽이라도 있으면, 일일이 방화벽을 해제해야 한다.
API 서비스는 물리적으로 서버가 분리되어 있더라도 단일 URL을 사용하는 것이 좋은데, 방법은 HAProxy나 nginx와 같은 reverse proxy를 사용하는 방법이 있다.
HAProxy를 앞에 새우고 api.apiserver.com이라는 단일 URL을 구축한후에
HAProxy 설정에서

api.apiserver.com/user는 user.apiserver.com 로 라우팅하게 하고
api.apiserver.com/car 는 car.apiserver.com으로 라우팅 하도록 구현하면 된다.

보안

API 서비스에 있어서 보안은 매우 중요한 요소이다. API 에 대한 보안은 다음과 같이 보안 대상에 따라서 몇가지로 나눠진다.

인증

인증은, API를 호출하는 클라이언트가 VALID한 사용자인지, 불법적인 사용자인지를 구별하는 방식이다.

HTTP Basic Auth

가장 쉬운 방식으로는 사용자 id,password를 표준 HTTP Basic Auth에 넣어서 전송하는 방식으로 사용자 단위의 인증과 권한 컨트롤이 가능하다는 장점을 가지고 있다. 그러나 이 경우, 매번 사용자 id와 password가 네트워크를 통해서 전송되기 때문에, 해커에 의해서 사용자 id,password가 누출될 수 있다. 사용자 id,password가 누출되면 API 호출 권한뿐만 아니라 웹에 로그인해서 다른 서비스를 사용하는 등 치명적이기 때문에 그리 권장되지 않는 방법이다.
SSL을 사용해서 암호화할 수 는 있겠지만 기본적으로 SSL은 Man in the middle attack (중간에 인증서를 가로체서 SSL 패킷을 열어보는 방법) 에 취약하기 때문에 완벽하다고 볼 수 없다.

Access Token

매번 네트워크를 통해서 사용자 id,password를 보내는 것이 위험하다면, 처음 인증시에만 id,password를 보내고, 인증이 성공하면 서버에서 access_token을 발급하여 API 호출시 access_token으로만 호출하는 방식이다. (OAuth2.0이 유사한 메커니즘을 사용한다.) 이 경우 API를 호출하는 클라이언트가 access_token을 저장하는 메카니즘을 가져야 한다. 또한 access_token이 누출될때를 대비하여, 서버쪽에서 compromised된 (노출된/오염된) token의 경우 revoke(사용금지 처리)를 하고, 클라이언트에게 다시 access_token을 발급하도록 하는 메커니즘과, Expire time을 둬서 주기적으로 token을 교체하도록 하는 방식이 좋다.

API Key

API Key 시나리오는 일반적으로 API 제공자가 API 포탈등을 통해서, 개발자를 인증하고 개발자에게 API Key를 발급한후, 개발자가 API Key를 애플리케이션 코드내에 탑재해서 사용하는 방법을 사용한다. API를 외부 파트너에게 공개하는 경우에 손쉽게 사용할 수 있으며, 꽤 많이 사용되던 방식이다. 단 애플리케이션 (특히 모바일 애플리케이션)이 디컴파일 될 경우 API Key가 누출될 수 있는 위험성을 가지고 있기 때문에, API Key를 잘 관리 하는 것이 중요하다. (난독화를 한다던가)
이 시나리오의 경우 애플리케이션 단위의 인증을 하기 때문에 앞서 설명한 두 방식처럼 사용자 단위의 인증은 불가능 하다.
(사용자 단위의 인증이 필요한 경우 API Key로 애플리케이션을 인증한 후에, 클라이언트 마다 새로운 access_token을 발급하는 방식을 사용할 수 있다. 사실 이게 OAuth 2.0의 client_secret과 access_token 시나리오와 유사하다.)

OAuth 2.0 (Recommended)

OAuth는 근래에 가장 많이 사용되는 API 인가/인증 기술이다. 특징중의 하나는 Authentication(인증)만이 아니라 권한에 대한 통제(Authorization)이 가능하다는 특징을 가지고 있으며, 3 legged 인증을 통해서, 파트너사가 API를 사용할 경우, 인증시에 사용자 ID와 비밀번호를 파트너에게 노출하지 않을 수 있는 장점이 있다. (페이스북 계정을 이용한 웹 애플리케이션들을 보면 가끔, 페이스북 로그인 화면으로 리다이렉트되어 “XX 애플리케이션이 XX에 대한 권한을 요청합니다. 수락하시겠습니까?”와 같은 창이 뜨는 것을 볼 수 있는데, 페이스북 로그인 화면에, 사용자 ID와 비밀 번호를 넣고 페이스북은 인증이 되었다는 정보를 인증을 요청한 웹애플리케이션으로 보내서, 해당 사용자가 인증되었음을 알려준다. 이경우, 웹 애플리케이션은 사용자의 비밀번호를 알 수 없다. )
기본적인 OAuth의 원리는, 사용자 ID/PASSWD로 인증을 한 후에, access_token을 받아서, access_token을 이용해서 추후 커뮤니케이션을 하는 방식이다.

OAuth는 크게 용도에 따라 4가지 타입의 인증 방식을 제공한다.

  • Authorization Code 방식 - 주로 웹 애플리케이션 인증에 유리하며, 위에서 설명한 케이스와 같이 웹을 통해서 Redirect 하는 방식이다.
  • Implicit 방식 - 자바스크립트 기반의 애플리케이션이나 모바일 애플리케이션 처럼 서버 백엔드가 없는 경우 사용한다.
  • Resource Owner password credential 방식 - 인증을 요청하는 클라이언트에서 직접 ID와 PASSWD를 보내는 방식으로, (이 경우 위의 방식들과 다르게 서비스 제공자의 로그인창으로 리다이렉션이 필요 없다.) 클라이언트가 직접 ID,PASSWD를 받기 때문에, 클라이언트에 사용자의 비밀번호가 노출될 수 있어서 서버와 클라이언트를 같은 회사에서 제작한 경우나, 사용자의 정보를 공유해도 되는 1’st party 파트너등과 같은 경우에 사용한다.
  • Client Credential 방식 - 일반적인 애플리케이션 Access에 사용한다.

일반적으로 API를 3’rd party에 제공할 경우에는 Authorization Code 방식을, 자사의 API를 자사나 1’st party 파트너만 사용할 경우에는 Resource Owner password credential 방식이 좋다.

Mutual SSL

가장 강력한 인증 방법으로,클라이언트와 서버가 각자 인증서를 가지고 상호 인증하는 방식이다. 양방향(2-way)SSL 이라고도 한다. 이 경우에는 클라이언트의 인증서(Certificate)를 서버에게 안전하게 전송할 수 있는 메커니즘이 필요하다. 클라이언트가 접속했을때, Certificate를 네트워크를 통해서 전송하고, 서버는 이 인증서가 공인된 인증서인지를 확인하는 방법도 있고, 내지는 서버의 Admin Console등을 통해서 클라이언트가 사용하는 인증서 자체를 업로드 해놓는 방법등 다양한 방법이 있다.
Mutual SSL은 양쪽에 인증서를 사용하기 때문에, Man in the middle attack이 불가능하고, Packet을 snipping해서 보는 것 조차도 불가능 하다. (대신 구현이 다소 까다롭다.)

WhiteList 방식

서버간의 통신에서는 가장 간단하게 할 수 있는 방식이 서버가 API 호출을 허용할 수 있는 IP 목록을 유지하는 방법이다. (WhiteList 방식). 다른 IP에서 들어오는 API 호출의 경우 받지 않는 방법으로, 가장 구현이 간단하다. 방화벽이나 Reverse proxy 설정등으로도 가능하고, 필요하다면, VPN (Virtual Private Network)등을 이용할 수 도 있다.

프로토콜 레벨 암호화

HTTP 통신 프로토콜 자체를 암호화 하는 방식인데, SSL을 이용한 HTTPS가 대표적인 경우이다. API 디자인에서 HTTPS는 반드시 적용하는 것을 권장한다.
HTTPS는 앞에서도 잠깐 언급했듯이 Man in the middle attack에 취약한데 Man in the middle attack의 기본적인 메커니즘은 서버에서 보낸 인증서를 바꿔치기 해서, 클라이언트로 보내는 방식을 이용한다. (http://en.wikipedia.org/wiki/Man-in-the-middle_attack)
가능하면, 인증서 체크 로직을 클라이언트에 두는 것이 좋다. 인증서가 공인된 인증서인지, (또는 그 서버의 인증서가 맞는지를 Issuer등을 통해서 확인할 수 있다. 인증서에 있는 내용들은 기본적으로 중간에 해커가 바꿀 수 다 없다. Signing이 되어있기 때문에, 내용을 바꾸면 Singing된 Signature가 맞지 않는다.) attack

메세지 레벨 암호화

다음으로 JSON과 같은 메세지 자체를 암호화할 수 있는데, 앞서 설명해듯이 SSL을 사용하더라도, 중간에 인증서를 바꿔 치는 등의 행위를 통해서 패킷을 열어볼 경우, 메세지 내용을 노출될 가능성이 있기 때문에 이를 방지 하기 위해서, 중요한 메세지는 암호화하는 것을 권장한다.
이때 전체 메세지를 암호화 하는 것은 비효율적이며 특정 필드의 값만 필요에 따라서 암호화를 하는 것이 좋다.


출처 : http://bcho.tistory.com/914

'프로그래밍' 카테고리의 다른 글

how to get key values in json object  (0) 2014.11.22
Github 사용방법 및 등  (0) 2014.06.22
REST에 대한 이해  (0) 2014.06.16
재귀함수의 원리 및 동작  (0) 2014.06.13
git 잘못된 커밋 삭제 및 합치는 법  (0) 2014.06.08
//
프로그래밍 2014. 6. 16. 15:32

REST 아키텍쳐

REST는 웹의 창시자(HTTP) 중의 한 사람인 Roy Fielding의 2000년 논문에 의해서 소개되었다. 현재의 아키텍쳐가 웹의 본래 설계의 우수성을 많이 사용하지 못하고 있다고 판단했기 때문에, 웹의 장점을 최대한 활용할 수 있는 네트워크 기반의 아키텍쳐를 소개했는데 그것이 바로 Representational safe transfer (REST)이다. 

Basic of REST 

한마디로 REST를 정리하면 HTTP URI + HTTP Method 이다. URI로 대상 자원을 명시하고 Method로 해당 자원에 대한 행위를 정의한다. 

Resource

REST의 가장 큰 특징중의 하나가 모든 자원을 Resource 즉 자원으로 표현한다는 것이다. 이 Resource는 HTTP URL에 의해서 표현된다. 예를 들어 javastudy 사이트의 bcho 라는 사용자를 표현하면  http://www.javastudy.co.kr/users/bcho 로 표현이 가능하고, 서울 강남구 사무실의 9층의 HP프린터를 표현할때는 http://printers/localtion/seoul/kangnamgu/9f/hp 식으로 표현을 한다. 이로써 HTTP URI를 통해서 모든 Resource를 표현이 가능하다. 

Action

그렇다면 해당 자원에 대한 행동은 어떻게 표현할것인가? 이는 HTTP Method를 사용한다.

l       자바스터디 사이트의 bcho에 대한 회원 정보를 가지고 오고 싶을때는
URI : http://www.javastudy.co.kr/users/bcho
Method : GET  

l       또는 해당 회원을 생성하고 싶을 때
URI : http://www.javastudy.co.kr/users/bcho
Method : POST
PayLoad
 <payload>
  <name>조대협</name>
     :
 </payload>

l       해당 회원을 삭제하고 싶을 때
URI : http://www.javastudy.co.kr/users/bcho
Method : DELETE

l       해당 회원에 대한 정보를 변경하고 싶을 때
URI : http://www.javastudy.co.kr/users/bcho
Method : PUT
PayLoad
 <payload>
  <name>조대협</name>
    :
 </payload>

 HTTP 프로토콜에 정의된 4개의 메서드들이 자원(Resource)에 대한 CRUD를 정의한다.

 HTTP Method의미  
 POSTCreate  
 GETSelect  
 PUT Create or Update 
 DELETEDelete  

REST 문제점

그런데 문제가 있다. 우리가 사용할 수 있는 메서드가 4가지 밖에 없다는 것이다. 예를 들어 send email이라던가, Log write와 같은 메서드들은 HTTP Method로 표현하기가 모호해진다.

기존의 프로그래밍 스타일이 Function이나 Method를 중심으로 한 행위 중심적인 접근이었기 때문에, REST가 지향하고 있는 자원 기반의 접근에 맞지 않는 것이다. 오히려 DBMS와 같이 CRUD를 가지고 있는 자원에 대해서는 적절하게 적용된다. 이런 이유가 REST를 단순하게 프로토콜이라고 부르지 않고 아키텍쳐라고 정의한 이유이다. 

그렇다면 이 문제를 어떻게 해결해야 할 것인가?

사실 CRUD만으로 모든 행위를 표현할 수 는 없다. Control성이나 함수성의 의미를 갖는 것들을 표현해야 하는데, 이런 경우는 HTTP/PUT이나 POST 메서드를 사용하거나 또는 함수에 대한 의미를 재해석하는 접근이 필요한데. Send Mail을 예를 들어보면 “메일을 보낸다” 라는 행위를 “누구한테 보내는 메일을 생성한다” 라는 의미로 바꾸면 다음과 같은 표현이 가능하다.  HTTP/POST http://www.xxx./sendmail/to/{emailaddress}

 그래도 문맥상으로 의미 변환이 불가능한 경우가 생긴다.

이런 경우는 HTTP/PUT과 URI를 사용하여 control의 의미를 부여한다. 사용자 ID bcho에 대한 등급 변경을 하는 경우는 다음과 같이 표현할 수 있다.

예를 들어 http://www.xxx/users/bcho/upgrade 

사실상 REST 기반의 아키텍쳐를 설계하려면 가장 어려운 것이 이 URI를 어떻게 정의하는 것이다. REST의 장점중 하나는 이 URI와 HTTP Method만으로도 쉽게 의미를 파악할 수 있다는 것이기 때문에, URI 정의에 많은 노력을 기울이는 것이 좋다 

장단점 

REST 장점

기존의 웹 인프라를 그대로 이용할 수 있다.

가장 큰 장점중의 하나일거다. 기존 HTTP를 그대로 사용하기 때문에, Remote Call을 할때도 방화벽을 새로 뚫어야 하느니등의 요건이 없고, L4등의 로드 밸런서 장비들도 그대로 사용이 가능하다.

.엇.보.다. 웹캐쉬 서버를 그대로 사용할 수 있다. 모든 Resource가 URI로 Unique하게 표현되기 때문에, 웹 캐쉬상에 보관될 수 있고, 특히나 SELECT성의 Operation은 이 캐쉬에 의해서 실제 Biz Transaction을 타지 않고 바로 리턴될 수 있기 때문에, 성능과 리소스 활용 측면에서 어마어마한 장점을 가지고 있다. 

쉽다.

웹서비스와 비교해보면 웹서비스는 스펙이 정말 많다. WS*-I, WS Reliable Messaging, WS Transaction 등등등 스펙 덩어리다. 그러나 REST는 별도의 SPEC이 없다. 보통 Defactor 표준이라고 하는데, HTTP URI와 Method만 잘 지켜서 사용하면 그게 REST다. 

REST 문제점

표준이 없다. 즉 관리가 어렵다.

REST가 요즘 들어 부각되는 이유 자체가 WebService의 복잡성과 그 표준의 난이도 때문에 Non Enterprise 진영 (Google,Yahoo,Amazone) 을 중심으로 집중적으로 소개되었다. 데이터에 대한 의미 자체가 어떤 비즈니스 요건 처럼 Mission Critical 한 요건이 아니었기 때문에 서로 데이터를 전송할 수 있는 정도의 상호 이해 수준의 표준만이 필요했지 Enterprise 수준의 표준도 필요하지 않았고, 벤더들 처럼 이를 주도하는 회사도 없었다.

 단순히 많이 사용하고 암묵적으로 암암리에 생겨난 표준 비스무리 한 것이 있을 뿐이다. (이런 것을 Defactor 표준이라고 부른다.) 

그런데 문제는 정확한 표준이 없다보니, 개발에 있어서 이를 관리하기가 어려워진다는 것이다. 표준을 따르면 몇가지 스펙에 맞춰서 개발 프로세스나 패턴을 만들 수 가 있는데, 이는 표준이 없으니, REST 기반으로 시스템을 설계하자면 사용할 REST에 대한 자체 표준을 정해야 하고, 어떤 경우에는 REST에 대한 잘못된 이해로 인하여 잘못된 REST 아키텍쳐에 이건 REST다 라는 딱지를 붙이는 경우가 많다. 실제로 WEB 2.0의 대표 주자격인 Flickr.com 도 REST의 특성을 살리지 못하면서 RPC 스타일로 디자인한 API를 HTTP + XML을 사용했다는 이유로 Hybrid REST라는 이름을 붙여서 REST 아키텍쳐에 대한 혼란을 초래했다. 

. Flickr의 Hybrid Rest는 어떤 Operation을 처리할 때,

 http://URL/operation?name=operationname 과 같은 형태로 메서드를 Query String으로 넘기는 형태를 사용했다. 언뜻 봐서는 RESTful한 디자인 같지만, 모든 Resource의 URI는 같고 operation을 Query String으로 나눈것에 불과 하기 때문에, 모든 Resource에 Unique 한 URI를 부여하는 REST의 원래 설계 원칙과 벗어난다.

 그런데, 국내에는 이런 형태의 디자인을 REST로 이해하고 있는 사람들이 많은 것 같아서 걱정이고 몇몇 포탈에서도 이런 형태의 서비스를 제공하는 것으로 알고 있다.

 

REST적인 접근과 설계가 필요하다.

위에서도 잠깐 설명했지만,  REST는 WebService와 같은 프로토콜이 아니다. REST는 아키텍쳐이다 Resource를 기반으로 하는 아키텍쳐이기 때문에 시스템 설계도 Rest 에 맞는 설계가 필요하다. 

Alternative Key의 사용

예를 들어 Resource를 표현할 때,  이러한 Resource는 DB의 하나의 Row가 되는 경우가 많은데, DB의 경우는 Primary Key가 복합 Key 형태로 존재하는 경우가 많다. (여러 개의 컬럼이 묶여서 하나의 PK가 되는 경우) DB에서는 유효한 설계일지 몰라도, HTTP URI는 / 에 따라서 계층 구조를 가지기 때문에, 이에 대한 표현이 매우 부자연 스러워진다.

예를 들어 DB의 PK가 “세대주의 주민번호”+”사는 지역”+”본인 이름일 때” DB에서는 이렇게 표현하는 것이 하나 이상할 것이 없으나, REST에서 이를 userinfo/{세대주 주민번호}/{사는 지역}/{본인 이름} 식으로 표현하게 되면 다소 이상한 의미가 부여될 수 있다.

이외에도 resource에 대한 Unique한 Key를 부여하는 것에 여러가지 애로점이 있는데, 이를 해결하는 대안으로는 Alternative Key (AK)를 사용하는 방법이 있다. 의미를 가지지 않은 Unique Value를 Key로 잡아서 DB Table에 AK라는 필드로 잡아서 사용 하는 방법인데. 이미 Google 의 REST도 이러한 AK를 사용하는 아키텍쳐를 채택하고 있다.

그러나 DB에 AK 필드를 추가하는 것은 전체적인 DB설계에 대한 변경을 의미하고 이는 즉 REST를 위해서 전체 시스템의 아키텍쳐에 변화를 준다는 점에서 REST 사용시 아키텍쳐적인 접근의 필요성을 의미한다. 

사실 그외에도 REST적인 설계를 하기 위해서는 Resource간의 관계를 href로 (링크)로 표현하는 기법,Versioning 방법,Naming Rule, ESB를 이용한 Cross cutting concern의 처리와 Routing 등 여러가지 고려 사항이 있으나, 아키텍쳐 설계 방법과 고급 REST에 대해서는 다음 기고 (고도화된 REST 아키텍쳐)에 대해서 논의 하기로 하겠다. 

REST 대한 잘못된 인식

REST = HTTP + XML 프로토콜?

프로젝트 성격상 고도화된 REST 시스템에 대한 설계가 필요했기 때문에 필자가 작년 중반즘에 국내의 한 커뮤니티 사이트에 REST에 대한 토론을 제안한적이 있었는데. 대부분의 사람들의 REST에 대한 이해는 REST는 HTTP를 써서 XML을 보내면 REST라고 생각하고 있었다.

절대 아니다.

REST는 웹의 특성을 잘 활용하여 자원을 리소스로 표현하는 아키텍쳐이다.(프로토콜이 아니다) 물론 HTTP는 사용해야 한다. 그러나 XML은 필수가 아니다. JSON이나 YAML과 같은 다른 표현 언어를 사용해도 무방하다. 리소스에 대한 표현과 웹의 특성을 얼마나 잘 활용했는가가 REST 아키텍쳐를 제대로 이해하는가에 대한 판단 기준이 될것이다. 

이번 글을 쓰는 이유중의 하나도 국내에 제대로된 REST에 대한 기고나 원칙을 설명한 문서가 없는 것 같아서 다소 부족한 글이지만 정리한다. 

REST는 WebService보다 쉽다.?

사실 그렇지도 않다. 맨 바닥에서 개발한다면야 REST가 더 쉽다. 자체 표준을 만들어서 Simple XML로 메시지를 정의해서 단순히 HTTP로만 보내면 되니까.. 그런데 이건 서비스 제공자 입장이다. 서비스를 사용하는 입장에서는 HTTP Client로 요청을 보내서 리턴받은 XML이나 JSON 데이터를 일일이 파싱해서 처리해야 한다.

 그러나 WebService는? 이미 잘 짜여진 표준 때문에, POJO나 JAX-WS등으로 코딩만 하면 자동으로 웹서비스가 생성된다. 무엇보다 WSDL에 의해서 정해진 서비스 Contract에 의해서 Client Stub을 자동으로 생성할 수 있기 때문에, 프로토콜 Spec을 전혀 모르더라도 마치 Java Library를 호출해서 사용하는 것처럼 쉽게 사용할 수 있다. 

본인의 경우에는 REST보다 WebService개발이 더 쉬워 보인다. 가장 쓰기 좋은 것은 복잡도가 낮고 잘 정리된 WS-I 기반의 WebService를 사용하는 것이 가장 간단하고 생산성면에서도 좋다. 

REST 전망

국내에서는 아직 REST에 대한 수요가 그다지 많지는 않다. 복잡도가 높은 시스템 설계를 기피하는 현상때문인지.. 아니면 아직 개방형 시스템에 대한 수요가 많지 않아서인지…

그러나 이미 해외의 유수 사이트들은 REST 기반의 아키텍쳐를 통해서 서비스 하고 있으며 대표적인 Open API 업체중의 하나인 Amazon역시 기존에 WebService로 개발되어 있었던 Open API들을 REST 기반으로 Migration할 계획이다. REST가 Defactor표준이기는 하지만 웹세상에서는 이미 무시하기 어려운 표준으로 자리잡아 가고 있다. 

또한 이렇게 오픈 진영에서 탄생한 REST가 J2EE Spec중의 하나인 JAX-RS로 (JSR311)로 추가되어 다음 JEE6 버전에 포함될 예정이다. (오픈 소스로는 Sun의 Jersey 라는 프레임웍과 Apache CXF에 포함도어 있다. 그리고 Spec화 된다해도 어디까지나 구현 방법에 대한 Spec이지 REST가 가지고 있는 그 자유도는 매우 높다. ) REST에 대한 표준화의 일환으로 WebService의 WSDL과 유사한 WADL이라는 Spec이 나오기는 했지만 REST 서비스의 URI정도를 표현하는 뿐이지, 실제 Operation안에 들어가는 Message의 Scheme등을 표현하고 있지 않고 있기 때문에 여전히 REST에 대한 Service Contract 표준은 없다고 보는 것이 맞을 것이고 이것이 앞으로 장점이 될지 단점이 될지는 판단하기 어렵다. 


출처 : http://bcho.tistory.com/321

//