블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

REST API 이해와 설계 

#2 API 설계 가이드


REST API 디자인 가이드

그러면 REST의 특성을 이해하고 나쁜 안티패턴을 회피해서 REST API 디자인은 어떻게 해야 할까? 짧지만 여기에 몇가지 디자인 방식에 대해서 소개 한다.


REST URI는 심플하고 직관적으로 만들자

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

  • /dogs
  • /dogs/1234

URI에 리소스명은 동사보다는 명사를 사용한다.

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}

를 사용하는 것이 좋다. 그리고 가급적이면 의미상 단수형 명사(/dog)보다는 복수형 명사(/dogs)를 사용하는 것이 의미상 표현하기가 더 좋다.

일반적으로 권고되는 디자인은 다음과 같다.

리소스

POST

GET

PUT

DELETE

create

read

update

delete

/dogs

새로운 dogs 등록

dogs 목록을 리턴

Bulk 여러 dogs 정보를 업데이트

모든 dogs 정보를 삭제

/dogs/baduk

에러

baduk 이라는 이름의 dogs 정보를 리턴

baduk이라는 이름의 dogs 정보를 업데이트

baduk 이라는 이름의 dogs 정보를 삭제


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

REST 리소스간에는 서로 연관관계가 있을 수 있다. 예를 들어 사용자가 소유하고 있는 디바이스 목록이나 사용자가 가지고 있는 강아지들 등이 예가 될 수 가 있는데, 사용자-디바이스 또는 사용자-강아지등과 같은 각각의 리소스간의 관계를 표현하는 방법은 여러가지가 있다.


Option 1. 서브 리소스로 표현하는 방법

예를 들어 사용자가 가지고 있는 핸드폰 디바이스 목록을 표현해보면

  • /”리소스명”/”리소스 id”/”관계가 있는 다른 리소스명” 형태 
  • HTTP Get : /users/{userid}/devices
    예) /users/terry/devices

과 같이 /terry라는 사용자가 가지고 있는 디바이스 목록을 리턴하는 방법이 있고


Option 2. 서브 리소스에 관계를 명시 하는 방법

만약에 관계의 명이 복잡하다면 관계명을 명시적으로 표현하는 방법이 있다. 예를 들어 사용자가 “좋아하는” 디바이스 목록을 표현해보면

  • HTTP Get : /users/{userid}/likes/devices
    예) /users/terry/likes/devices

는 terry라는 사용자가 좋아하는 디바이스 목록을 리턴하는 방식이다.

Option 1,2 어떤 형태를 사용하더라도 문제는 없지만, Option 1의 경우 일반적으로 소유 “has”의 관계를 묵시적으로 표현할 때 좋으며, Option 2의 경우에는 관계의 명이 애매하거나 구체적인 표현이 필요할 때 사용한다. 


에러처리

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

대표적인 API 서비스들이 어떤 HTTP Response Code를 사용하는지를 살펴보면 다음과 같다.

구글의 gdata 서비스의 경우 10개, 넷플릭스의 경우 9개, Digg의 경우 8개의 Response Code를 사용한다.  (정보 출처:  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

여러 개의 response code를 사용하면 명시적이긴 하지만, 코드 관리가 어렵기 때문에 아래와 같이 몇가지 response code만을 사용하는 것을 권장한다.

  • 200 성공
  • 400 Bad Request - field validation 실패시
  • 401 Unauthorized - API 인증,인가 실패
  • 404 Not found ? 해당 리소스가 없음
  • 500 Internal Server Error - 서버 에러

추가적인 HTTP response code에 대한 사용이 필요하면 http response code 정의 http://en.wikipedia.org/wiki/Http_error_codes 문서를 참고하기 바란다.

다음으로 에러에는 에러 내용에 대한 디테일 내용을 http body에 정의해서, 상세한 에러의 원인을 전달하는 것이 디버깅에 유리하다.

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 정보를 출력하는 것은 대단히 위험한 일이다. 내부적인 코드 구조와 프레임웍 구조를 외부에 노출함으로써, 해커들에게, 해킹을 할 수 있는 정보를 제공하기 때문이다. 일반적인 서비스 구조에서는 아래와 같은 에러 스택정보를 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라도 버전에 따라서 다른 기능을 제공하도록 하는 것이 필요하다.

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 처리가 필요하다.

리턴되는 리스트 내용이 1,000,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
  • 구현 관점에서 보면 , 페이스북 API가 조금 더 직관적이기 때문에, 페이스북 스타일을 사용하는 것을 권장한다.
  • record?offset=100&limit=25

100번째 레코드에서부터 25개의 레코드를 출력한다.


Partial Response 처리

리소스에 대한 응답 메세지에 대해서 굳이 모든 필드를 포함할 필요가 없는 케이스가 있다.

 예를 들어 페이스북 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는 Facebook 스타일이 구현하기가 간단하기 때문에, 필자의 경우는 Facebook 스타일의 partial response를 사용하는 것을 권장한다.


검색 (전역검색과 지역검색)

검색은 일반적으로 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

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


HATEOS를 이용한 링크 처리

HATEOS는 Hypermedia as the engine of application state의 약어로, 하이퍼미디어의 특징을 이용하여 HTTP Response에 다음 Action이나 관계되는 리소스에 대한 HTTP Link를 함께 리턴하는 것이다.

예를 들어 앞서 설명한 페이징 처리의 경우, 리턴시, 전후페이지에 대한 링크를 제공한다거나

{  

   [  

      {  

         "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"

      }

   ]

}

와 같이 표현하거나

연관된 리소스에 대한 디테일한 링크를 표시 하는 것등에 이용할 수 있다.

{  

   "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 엔드포인트 활용

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를 사용하는 클라이언트 입장에서는 단일 엔드포인트를 보면 되고, 관리 관점에서도 단일 엔드포인트를 통해서 부하 분산 및 로그를 통한 Audit(감사)등을 할 수 있기 때문에 편리하며, API 에 대한 라우팅을 reverse proxy를 이용해서 함으로써 조금 더 유연한 운용이 가능하다.


REST에 문제점


그렇다면 이렇게 많은 장점이 있는 REST는 만능인가? REST역시 몇가지 취약점과 단점을 가지고 있다.


JSON+HTTP 를 쓰면 REST인가?

REST에 대한 잘못된 이해중의 하나가, HTTP + JSON만 쓰면 REST라고 부르는 경우인데, 앞의 안티패턴에서도 언급하였듯이, REST 아키텍쳐를 제대로 사용하는 것은, 리소스를 제대로 정의하고 이에대한 CRUD를 HTTP 메서드인 POST/PUT/GET/DELETE에 대해서 맞춰 사용하며, 에러코드에 대해서 HTTP Response code를 사용하는 등, REST에 대한 속성을 제대로 이해하고 디자인해야 제대로된 REST 스타일이라고 볼 수 있다.

수년전 뿐만 아니라 지금에도 이러한 안티패턴이 적용된 REST API 형태가 많이 있기 때문에, 제대로된 REST 사상의 이해 후에, REST를 사용하도록 해야 한다.


표준 규약이 없다

REST는 표준이 없다. 그래서 관리가 어렵다. 

SOAP 기반의 웹 서비스와 같이 메시지 구조를 정의하는 WSDL도 없고, UDDI와 같은 서비스 관리체계도 없다. WS-I이나 WS-*와 같은 메시지 규약도 없다. 

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

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

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

근래에 들어서 YAML등과 같이 REST 에 대한 표준을 만들고자 하는 움직임은 있으나, JSON의 자유도를 제약하는 방향이고 Learning curve가 다소 높기 때문에, 그다지 확산이 되지 않고 있다.

이런 비표준에서 오는 관리의 문제점은, 제대로된 REST API 표준 가이드와, API 개발 전후로 API 문서(Spec)을 제대로 만들어서 리뷰하는 프로세스를 갖추는 방법으로 해결하는 방법이 좋다.


기존의 전통적인 RDBMS에 적용 시키기에 쉽지 않다.

예를 들어 리소스를 표현할 때,  리소스는 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 사용시 아키텍쳐적인 접근의 필요성을 의미한다. 

그래서 근래에 나온 mongoDB나 CouchDB,Riak등의 Document based NoSQL의 경우 JSON Document를 그대로 넣을 수 있는 구조를 갖추는데,하나의 도큐먼트를 하나의 REST 리소스로 취급하면 되기 때문에 REST의 리소스 구조에 맵핑 하기가 수월하다.



  • REST API 이해와 설계 - #1 개념 잡기 http://bcho.tistory.com/953
  • REST API 이해와 설계 - #2 디자인 가이드  http://bcho.tistory.com/954
  • REST API 이해와 설계 - #3 보안 가이드  http://bcho.tistory.com/955


빠르게 훝어보는 node.js

#15  - Passport를 이용한 OAuth 2.0 API 인증 (Facebook 1/2)

조대협 (http://bcho.tistory.com)



REST 기반의 OPEN API 인증을 고민하다가 보니, 가장 많이 쓰이는게, OAuth 2.0이라서, OAuth 2.0을 보다보니, 도저히 이해가 안되겠다 싶어서, 간단하게 직접 구현해보기로 했다. OAuth 서버를 구현하기전에 먼저 테스트 클라이언트가 필요했기 때문에, node.js + passport 를 이용해서 facebook API를 호출하는 간단한 웹 사이트를 만들어보기로 했다.

Facebook API는 기본적으로 OAuth 2.0을 사용하고, Passport 모듈에서 잘 추상화된 라이브러리를 제공하기 때문에 쉽게 구축할 수 있으리라 생각했다. 실제로 구축해보니, 간단한 예제를 만드는데 약 1시간 30분 정도가 소요되었다.

자아 그러면 이제부터 Passport node.js를 이용해서 간단한 Facebook API를 호출하는 예제를 만들어보도록 하자.

OAuth 2.0

먼저 OAuth 2.0에 대한 개념을 알아보도록 하자. OAuth 2.0, 서비스에 대한 Authentication (인증) Authorization(권한 인가)에 대한 포괄적인 프레임웍이다. 특히 API 인증에 유용하게 사용될 수 있는데, 사용하는 애플리케이션의 타입(,모바일,자바스크립트)에 따라서 다양한 인증 메카니즘을 제공한다. 이를 grant type이라고 하는데, 대표적으로 4가지 형태의 grant type을 제공한다.

Ÿ   Authorization Code for webserver

Ÿ   Implicit for browser-based or mobile apps

Ÿ   Resource owner password credential for logging in with a username and password

Ÿ   Client credential for application access

다른 grant type에 대해서는 차차 소개하기로 하고, 오늘은 authorization code 방식의 grant type에 대해서 알아보도록 하자.

※ 다른 grant type에 대해서는 http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified#web-server-apps 에 잘 정리가 되어 있다.

지금 구축하려고 하는 것은 facebook API를 내 서비스 웹서버에서 호출하는 시나리오이다.

Facebook API를 호출하기 위해서는 node.js 애플리케이션을 facebook 에 등록해야 한다. 이 등록은 facebook developer portal을 통해서 진행할 수 있는데, 아래 그림과 같이



1.  포탈에 node.js 사이트 관련 정보 (서비스 URL, CallBack URL, 서비스 명 등)을 입력하면,

2.  포탈에서 client_id client_secret을 발급해준다. client_id는 서버에서 발급되는 node.js 만든 서비스에 대한 id 라고 생각하면 되고, client_secret은 그 id에 대한 일종의 인증용 패스워드이다. (절대로 외부에 노출되면 안되는)

3.  이렇게 받은 client_id client_secret node.js 애플리케이션 내에 저장한다.

이렇게 해서 node.js 애플리케이션이 만들어졌으면 호출을 해보자. 호출은 다음과 같은 순서로 이루어 진다. 잠깐 용어를 짚고 넘어가면 OAuth 2.0에서는 Facebook 과 같이 Protected resource (API)를 제공하는 서버를 Resource Server 라고 하고, node.js와 같이 Protected resource (API)에 대한 접근을 요청하는 대상을 Client 라고 정의 한다. Client Resource Server에 접근할때, 사용자의 신분 (id,password)를 기반으로 하여, Resource Server에 접근하는데, 이러한 사용자를 User 라고 정의한다. 그러면 다음과 같은 흐름을 보자.



1.  먼저 사용자는 Web Browser에서, node.js 서버로 서비스를 요청한다.

2.  Node.js 서버는 사용자가 로그인이 되어 있지 않은 상태라면, Facebook log in URL에 대한 rediretion URL을 브라우져에게 보낸다. 이 때, node.js 서버임을 식별하기 위해서 client_id와 몇 가지 추가적인 정보를 보내는데, 그 내용은 다음과 같다.

Ÿ   client_id : 사용자를 통해서 인증을 요청하는 서비스가 앞에서 등록한 node.js 애플리케이션임을 알려준다.

Ÿ   redirect_url : 페이스북 인증서버에서 인증이 끝난후에, 인증 결과를 받을 node.js  애플리케이션으 HTTP URL을 정의한다.

Ÿ   scope : 페이스북에 접근을 요청한 리소스 목록을 정의한다. 예를 들어, 글쓰기, 읽기, 사진 올리기, 연락처 공유등과 같이 리소스에 대한 범주를 정의한다. Oauth 2.0의 특징중의 하나가 단순히 사용자 인증(Authentication)만을 하는 것이 아니라, 사용자가 소유한 리소스중, 접근을 허가 하는 권한 제어(Authorization) 기능을 함께 제공한다는 것이다.

https://oauth2 authorizationserver.com/auth?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos

실제 facebook redirection URL

https://www.facebook.com/login.php?skip_api_login=1&api_key=253044994897796&signed_next=1&next=https://www.facebook.com/v2.0/dialog/oauth?redirect_uri=http://localhost:8080/auth/facebook/callback&scope=read_stream&response_type=code&client_id=253044994897796&ret=login&cancel_uri=http://localhost:8080/auth/facebook/callback?error=access_denied&error_code=200&error_description=Permissions error&error_reason=user_denied#_=_&display=page

3.  Browser Redirect URL을 받아서,페이스북의 인증 서버 URL Redirect를 한다.

4.  페이스북 인증 서버는 log in page를 사용자에게 보낸다.



5.  사용자는 사용자 ID PASSWORD를 입력한다.

인증이 되고 나면, scope에 의해서 리소스에 대한 접근 요청을 허가할 것인지를 물어보는데, 아래는 node.js 애플리케이션이 글쓰기 권한을 요청했을때 사용자에게 node.js 애플리케이션에 글쓰기 권한을 허용할지를 물어보는 화면이다.



6.  페이스북의 인증서버는 ID,PASSWORD를 인증과 권한 획득에 성공하면, 인증과 권한 획득에 성공했다는  Authorization Code와 함께, 다시 2에서 정의된 Service Consumer node.js server callback URL (redirect_url= redirect_uri=http://localhost:8080/auth/facebook/callback ) redirect request를 보낸다.

7.  Browser는 위에서 받은 Authorization code와 함께, 앞에서 받은 node.js 서버의 callback URL redirect를 한다.

http://localhost:8080/auth/facebook/callback?code=AQAKlwhopD1DD5(중략)

8.  Node.js 서버는 이 사용자가 인증 되었음  증명하는 받은 authorization code를 가지고, 페이스북의 authorization server에 문의한다.
POST https://api.oauth2server.com/token
    grant_type=authorization_code&
    code=AUTH_CODE_HERE&
    redirect_uri=REDIRECT_URI&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET

Ÿ   grant_type : grant type은 앞에서 설명한 4개중에서, 현재 사용하는 grant type authorization code 방식이기 때문에 이를 정의한다.

Ÿ   code : 앞에서 받은 authorization code

Ÿ   redirect_uri

Ÿ   client_id : node.js 서버를 인증하기 위한 client id. 앞서 developer portal에서 발급받아서, node.js 서버 애플리케이션안에 넣어놓았다.

Ÿ   client_secret : node.js 서버를 인증하기 위한 client_secret(password). 앞서 developer portal에서 발급받아서, node.js 서버 애플리케이션안에 넣어놓았다.

9.  페이스북의 authorization server는 이 authorization code를 가지고해당 요청이 인증되었음을 확인하고, node.js 서버에게로 API 접근을 허용하는 access_token을 발급한다.

10. Node.js 서버는 이 access_token을 가지고 페이스북 API에 접근을 요청하면, 페이스북 API서버는 access_token을 통해서 API 접근 가능 여부를 판단한 후, 인가된 요청인 경우 API 요청을 수락하여 서비스를 제공한다.

간단하게 authorization code 방식을 이용한 애플리케이션 인증 방식에 대해서 알아보았다. 몇가지 더 짚고 넘어가면, authorization code 방식의 장점은 node.js 서버가 사용자 id,password를 알수 없다. API를 제공하는 서비스 제공자 입장에서, 3’rd party (협력 파트너)에게 자사의 사용자 id,password를 노출 시킬 필요가 없기 때문에, 파트너를 대상으로 안전하게 서비스 사용자의 id,password 없이 사용자 인증을 진행할 수 있다.

아울러 access_token에 대해서 몇가지 짚고 넘어갈것이 있는데, access_token을 취득한 이후에는 별도의 사용자 인증 절차가 필요하지 않다. Node.js 서버에서 access_token만을 기억하고 있으면 해당 사용자에 대한 리소스를 호출하는 API를 이 access_token을 통해서 호출할 수 있다. (즉 호출할때 마다 매번 사용자 인증을 할 필요가 없다는 말이다.)


다음글에서는 실제로 Passport 모듈을 이용하여 Facebook Open API를 호출하는 방법을 설명하도록 하겠다.

Python에서 Open API 호출하기

프로그래밍/Python | 2013.11.22 19:09 | Posted by 조대협

Rest API를 호출하기

여러가지 라이브러리 (urllib2, httplib2)등을 체크해봤으나, https 를 가장 쉽게 호출할 수 있고, 사용하기 편한것은 requests라는 것이 가장 편리함 http://www.python-requests.org/en/latest/user/quickstart/#make-a-request 에서 curl 로 다운로드 하고 설치해서 사용



위는 도스창을 이용해서 간단하게 https로 dna.daum.net을 호출한 코드인데, 리턴값이 한글이라서 그런지. cp949 encode 에러가 남. (이건 나중에 수정해야 할거 같고)


기타 참고 자료 (아래)


참고 : API 호출 하기

https://dna.daum.net/tools/python/tutorial


SSL 사용하기

urllib2는 https가 지원되지 않음


1. Python 인스톨본이 SSL을 지원해야 한다.

. 확인하는법

>>> import socket

>>> socket.ssl

<function ssl at 0x4038b0>


2. httplib2 설치

https://code.google.com/p/httplib2/



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

Python 공부 노트 11. Class  (0) 2014.01.03
Python 공부 노트 11. Module install  (0) 2014.01.02
Python에서 Open API 호출하기  (0) 2013.11.22
Django에서 static file (css,img 사용하기)  (0) 2013.11.21
Django Template  (0) 2013.11.21
Django Hello World  (0) 2013.11.21



Open API design

아키텍쳐 /SOA | 2013.07.06 13:14 | Posted by 조대협

OPEN API Design Consideration Point


1. API Type 

Internal APIs

Internal System in same network

User for internal user or authorized user

 

External APIs

for Public Developer

Developer Support is key point

 

for Partner

- Business value is key

 

2. API Design Best Practice

Easy to use

with out documentation, API should be easy enough to use.

Easy to Try and use

For private APIs, it is important to demonstrate real value in running a system or app off of the API

public APIs, one approach is to offer some level of free access. Many developers won’t even consider using your API if there are only paid options. At this point in the customer acquisition cycle, the developer may not know if your API meets their needs or if their app’s business model will support paid access.

 

Diffentiate API

Ÿ   The data is unique, more complete, or more accurate than that of your competitors

Ÿ   You offer better support or an easier signup process

Ÿ   Your API is more robust, reliable, cooler, or faster than alternatives

Ÿ   Your terms are more developer friendly; perhaps you offer more data traffic for free or at better rates

Provide mandatory functionality first time and enhance later

There are other aspects of simplicity that can help make your API easier to adopt. One success factor is to stick to conventions that the developer might already know

Target Specific Developer Segment 

3. Technology Selection

REST API

pragmatic REST API design

Figure 1 Wrong design for shopping cart

 

Figure 2 Good design for shopping cart

Binary protocol

Ÿ   Protocol Buffer

Ÿ   Thrift

 

Versioning

Having mediation layer like ESB

4. Security

Identification

- grant access by using API Key

Authenticate

- Determine who is accessing API.

Ÿ   User name & password

Ÿ   Session based

After log in with user name & password, session token key will be issued. with the session key authentication can be passed

Ÿ   Standard way

SAML

OAuth

 

Authentication vs Identification

Identification based API provides same functionalities and data to client.

Authentication based API provides user dependent data to client

Encryption

use SSL (can be attacked by Man in middle attack)

partial or all message encryption

 

Threat Detection and prevention

 

General recommendation of Security

API Keys for only nonsensitive & read-only data.

Use OAuth 2.0 for more sensitive authentication

use SSL for everthin sensitive data.

Sanitize incoming and outgoing data - prevent javascript attack and SQL attack. (especially in writable API)

 

5. Legal Consideration

 

Consideration point

- What content will be provided

- What right can u or do u want to grant the consumer of API

- Are they have different level of API access?

 

Perspective

Ÿ   Contract & Terms of Use

Ÿ   Privacy Policy

Ÿ   Data retention policy

 

6. API Operation

Monitoring

Throttling (Traffic management)

Depends on contract & consumer, API traffic can be managed. It is important to monetization

Reporting

SLA

Issue management

Internal operation issue tracking

Support

Ÿ   Issue management & ticketing

Ÿ   Documentation

Ÿ   Sand box

 

7. API Measurement

Effectiveness measurement - call per day

Effective measurement - call per day, call per client (by region ,model etc)

Performance measurement - response time

 

 

 참고

http://www.layer7tech.com/

http://www.apigee.com

 

 

'아키텍쳐  > SOA' 카테고리의 다른 글

Microservice architecture note  (0) 2014.08.20
Open API design  (0) 2013.07.06
통신 사업자의 SDP의 필수 컴포넌트  (0) 2010.08.03
SDP (Service Delivery Platform)  (1) 2009.09.15
모차세대 시스템의 WAS 아키텍쳐 Blue Print  (8) 2009.07.30
EAI관점에서 본 SOA  (6) 2009.07.29

오픈 환경과 우물안의 개구리....

아키텍쳐 /WEB 2.0 | 2008.09.16 17:11 | Posted by 조대협
요즘 오픈 플랫폼에 관련된 프로젝트를 하면서 여기저기 기웃거리고 있는데...
Open Social, Open API. Mash up 플랫폼등..
근데 보면서 느끼는 것이..
Facebook이나 MyFaces와 같은것들이나 여러 사이트에서 제공하는 OPEN API의 인프라를 보면
무섭게도 빨리 발전하고 있다는 것이다.
국내에 잘나간다는 개발자분들 블로그에는 오히려 접하기 힘든 내용이고 국내에서 제공되는 OPEN API도 네이버나 다음에서 그것도 일부만이 제공되지 외국 환경과 같이 강력한 환경이나 이미 널리 전파되어 있는 주요 영역으로 보이지 않는다.
오히려 이런점이 블루 오션이 되지 않을까? 반대로 아래 포스트에서 언급한데로 포탈벤더의 지배력이 강해서 일까??

자바스크립트에 국내 개발자들이 약한것도 하나 이유가 되지 않을까도 싶고..
이미 GLOBAL IT는 오픈 환경으로 움직이기 시작했고.. 이게 Enterprise 에 적용되는 것도 그리 멀지 않았을것 같은데..

지속적으로 관심을 기울여 봐야 겠다..

'아키텍쳐  > WEB 2.0' 카테고리의 다른 글

REST 아키텍쳐에 대한 연재를 시작합니다.  (2) 2009.05.27
REST 연재-1회 REST 아키텍쳐의 기본  (15) 2009.05.27
AJAX Overview  (1) 2009.04.09
REST의 반격?  (0) 2008.12.08
오픈 환경과 우물안의 개구리....  (0) 2008.09.16
Open Social Zembly..  (0) 2008.09.16