민자의 지식창고

RESTful API 활용 본문

개발노트/Back-end

RESTful API 활용

전지적민자시점 2018. 6. 20. 14:23

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


REST API를 URI만 보고도, 직관적을 이해 해야 한다. 

최대 2Depth로 유지한다.


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

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


URL은  HTTP Method에 의해 CRUD(생성, 읽기, 수정, 삭제) 의 대상이 되는 개체(명사)라야 한다.


의미상 단수형 명사보다는 복수형 명사를 사용하는것이 의미상 표현하기가 더 좋다


일반적 권고되는 디자인은 아래와 같다.


 리소스

Post

Get

Put

Delete

 

create

read

update

delete

 /bots

새로운 bot 객체 등록

bot 리스트 

homobot으로 여러 bots 정보를 업데이트

모든 bots 정보 삭제

/bots/dos

error

bot 리스트에서 dos 정보를 리턴

dos라는 이름의 bot 정보를 업데이트

dos라는 이름의 bot 정보를 삭제




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


REST 리소스간에는 서로 연관관계가 있을 수 있다. 


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

/"리소스명"/"리소스ID"/관계가 있는 다른 리소스명" 형태


HTTP Get : /users/{userid}/devices


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

만약 관계 명이 복잡하면 관계명을 명시적으로 표현하는 방법 

HTTP Get : /users/{userid/}likes / devices


Option1과 Option2 어떤 형태를 사용하든 상관없다.

단, 1의 경우 일반적 소유 "has"관계를 묵시적 표현

2의 경우에는 관계의 명이 애매하거나 구체적인 표현이 필요 할떄 사용


Error 처리


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


대표적인 API 서비스들 : Google(10개) , Netflix(9개), Digg


Google GD data

200 201 304 400 401 403 404 409 410 500


Netflix

200 201 304 400 401 403 404 412 500


..


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


200 성공

400 bad request - field validation 실패시

401 Unauthorized - api 인증, 인가 실패

404 Not Found - 해당 리소스가 없음.

500 Internal Server Error 서버 에러


Error Message 형식의 경우

HTTP Status code : 401

{"status": "401" , "message" : "Authenticate", "code": "200003", "moreinfo":"http://.... /errors/20003"}


와 같이 표현 하는데, 에러 코드 번호와 해당 에러 코드 번호에 대한 Error dictionary link를 제공한다.

Error 번호에 대한 Dictionary를 일반적으로제공한다 .


에러메시지에 Error Stack 정보를 출력하는 것은 대단히 위험한 일이다. 해커들의 해킹 위험이 있다.


API를 개발시, 서버의 모드를 Production과 dev 모드로 분리해서, 옵션에 따라 deb모드등으로 기동시, REST API의 에러 응답 메세지에 어러 스택 정보를 포함해서 리턴하도록 하면, 디버깅에 매우 유용하다.



API 버전 관리


API 정의에 중요한 것 중 하나는 버전 관리!

새로운 API를 배포할때는 하위 호환성을 보장하면서 서비스를 제공해야 한다.

같은 API라도 API의 버전을 정의하는 방법은 여러가지가 존재한다.


ex> Facebook ? v=2.0



{servicename} / version/ REST URL


형태로 정의하는것을 권장한다.


자바 애플리케이션의 경우, account.v1.0.war , account.v2.0.war 같은 war 파일 로 각각 배포 및 관리가 가능하다.


외부로 제공되는 URL은 ../acount/v2.0/groups로 하나의 서버를 가르키지만, 내부적으로 HAProxy 등의 reserve proxy를 이용해서 이런 URL을 맵핑할 수 있는데 내부적으로는 .../v2.0./groups로 맵핌이 가능하며, 향후 URL 외부 변경 없이 확장되었을때 서버를 물리적 분리가 쉽다



페이징


큰사이즈의 리스트 형태의 응답을 처리 하기 위해서 페이징 처리와 partial response 처리가 필요하다.

리턴 되는 리스트 내용이 만개 이상, 이를 하나의 HTTP response로 처리하는 것은 서버성능, 네트워크 비용문제도 있지만 가장 큰것은 비현실적 


Facebook  : /record?offset=100& limit =25

twitter : /record?page=5&rpp=25(RPP = record per page로 레코드수로 25이면 25* 5 = 125 레코드가 된다)


100 번쨰 레코드에서 25개의 레코드를 추력한다.

구현관점에서 보면 페이스북 스타일이 직관적이다.



Partial Response 처리


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


필드를 제한한다는 의미는 전체 응답의 양을 줄여서 네트워크 대역폭 절약 할수 있고, 응답 메세지를 간소화하여 파싱등을 간략화 할수가 있다.


Linkedin :/people:(id,first-name,last-name,industry)

Facebookk : /userid/friends?fields=id,name


linkedin 스타일의 경우 가독성이 높지만, :() 로 구별하기 때문에, HTTP 프레임웍으로 파싱하기가 어렵다. 


facebook 스타일이 Partial Response 구현하기가 간단하기 때문에 권장사항이다.





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


검색은 일반적으로 HTTP GET에서 Query String에 검색조건을 정의 하는 경우가 일반적이다.

예를 들어 검색 query만 이용하며느 

/users? name=cho & region=seoul


그런데, 여기에 페이징 처리를 추가하게 되면

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


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


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


이런식으로 검색 조건을 URL Encode를 써서 q=name%3Dcho & region%3Dseoul 처럼 표현하고, ㅇ디드ㅑㅜㅁ색fmf , 등을 사용하게 되면 검색 조건은 다른 Query 스트링과 분리가 된다.


예를 들어 시스템에 user,dogs,cars 와 같은 리소스가 정의 되어 있을때, id='terry'인 리소스에 대한 전역 검색

/search ? q= id%3dterry


와 같은 / search와 같은 전역 검색 URI를 사용하는 것이다.

반대로 특정 리소스만의 검색은

/user?q=id%3Dterry


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




REST API 보안


인증(Authentication) : 누가 서비스를 사용하는지 확인 절차


인가(Authorization) : 사용자가 그 리소스를 사용할 권한이 있는지 체크하는 권한 체크 과정


네트워크레벨 암호화 :네트워크 레벨의 암호화 HTTPS 보안프로토콜 사용


메시지 무결성 보장 : 메시지에 Signature를 생성해서 메시지와 같이 보낸 후 수신쪽에서 받은 문자열과 이 받은 문자열로 생성한 해쉬 코드를 문자열고 함께 온 해쉬코드와 비교하는 방법이 있다.


메시지 본문 암호화 : 특정필드만 암호화 한다.



API Key 방식


API Token 방식 : 사용자 ID,Password 사용자 인증 후 그 사용자가 APi 호출에 사용할 기간이 유효한 API Token을 발급해서 API Token으로 인증 하는 방식



1.  API client가 사용자 ID,Password를 보내고  API 호출을 위한 API Tokenㅇ을 요청

2. API 인증서버는 사용자 ID,Password를 가지고, 사용자 접ㅇ보를 바탕으로 사용자 인증

3.인증된 사용자에 대해서 API Token을 발급(유효기간 존재)

4.API Client는 이  API Token으로  API 호출


HTTP Basic Auth 

가장 기본적이고 단순한 형태 인증 방식. 사용자ID/Password를 HTTP Header에 Base64 인코딩 형태로 넣어서 인증을 요청


Digest access Authentication

HTTP Basic Auth가 Base64형태로 passwd를 실어서 보내는 단점을 보강하여 나온 인증 프로토콜





클라이언트 인증 추가


제 3자 인증 방식





API 인가 방식


RBAC(Role Based Access Control) 방식 : Role에 권한을 연결해 놓고, 이 Role을 가지고 사용자에게 해당 권한을 부여한다.


ACL(Access Control List) 방식 : 사용자(그룹과 같은 권한의 부여 대상) 에게 직접 건한을 부여하는 방식


클라이언트에 의한 API 권한 인가 처리

API를 호출 하는 클라이언트 쪽에서 사용자 권한에 따라 API를 호출 하는 방식




Gateway에 의한 권한 인가 처리

서버에 의한 권한 인가 처리

...




네트워크 (전송)레벨 암호화





자바 스크립트 클라이언트 지원


SPA(sigle page application)가 유행하며, 브라우져에서 페이지간의 이동없이 자바스크립트를 이용해서 동적으로 페이지를 변경 하는 방식

페이지의 reloading 없기 때문에 반응성이 좋고,  SPA의 경우 서버와 통신을 자바스크립트가 직접 XMLHTTPRequest 객체를 이용해 API 호출 하는 형태


Same Origin Policy에 대한 처리

자바스크립틔  API에 대한 호출은 위 제약을 받는다. Same Origin policy란, 웹브라우져에 동작하는 프로그램은 해당 프로그램이 로딩된 위치에 있는 리소스만 접근이 가능하다.




Proxy를 이용하는 방법






Pre-flight를 이용한 CORS 통제



API access Token에 대한 인증 처리


1. Secure cookie를 통해 주고 받는 방법

서버에서 토큰을 발급하고, 리턴할때 HTTP body에 리턴하는 것이 아니라 Secure Cookie에 넣어서 리턴한다.

Secure Cookie는 일반 HTTP 프로토콜을 통해서는 전송이 불가능 하고 항상 HTTPS를 통해서만 전송이 가능하다.

같은 API서버로도 일반 HTTP 호출 할 경우 api access token이 Cookie를 통해서 전달되지 않기 떄문에, 네트워크를 통해서  access token을 탈취하기 불가능하다



2. api access token은 해당 세션에서만 유효하도록 한다.

특정 IP와 시간내에서만 API 유효하도록 하는 방식

API가 호출될때마다 IP와 Origin을 확인하고 유효시간 시간 내면 다시 연장 되고, 일정시간 호출하지 않으면 폐가하고 다시 발급하도록 유도한다.







728x90

'개발노트 > Back-end' 카테고리의 다른 글

BehaviorSubject  (0) 2020.08.25
RxJava  (0) 2020.08.25
Spring Framework1  (0) 2018.06.14