기술서 읽고 정리

『Web API The Good Parts』를 읽고 - 엔드포인트 설계와 리퀘스트 형식

Jonchann 2024. 2. 23. 17:53

API로 공개할 기능을 설계하기

내부구조를 공개해선 안된다. 더 높은 차원의 기능을 공개해야 한다.

예를 들어, 아래와 같은 URI는 아키텍처를 특정당하기 쉽고 이미 쇄약한 점이 공개되어있기 때문에 공격하기도 쉽다.

 

http://api.example.com/cgi-bin/get%5C_user.php?user=100

 

URI가 반영해야 하는 것은 기능이나 데이터 구조나 의미이지 서버가 어떻게 움직이는지가 아니라는 것이다.

기본적인 설계

짧고 입력하기 쉬운 URI

예를 들어 아래와 같은 URI가 있다고 했을 때 service, api와 같이 비슷한 의미가 중복해서 적혀있다.

http:// api.example.com/service/api/search

아래처럼 간결하게 할 수 있다.

 

http://api.example.com/search

사람이 읽고 금방 이해하는 URI

짧게 하겠다고 너무 줄이면 오히려 알기 어렵다.

 

http://api.example.com/sv/u

 

단, 국가명을 나타내는 코드나 ISO 3166과 같이 전세계적으로 표준화 되어있는 것은 적극적으로 사용하는 것이 좋다.
그리고 웬만하면 잘 쓰는 영단어(세게 공용어)를 사용하는 것이 좋다. 예를 들어, 아래와 같은 URL이 있다고 하자.

 

http://api.example.com/produnts/12345
http://api.example.com/productos/12345
http://api.example.com/jepoom/12345

 

두번째는 스페인어인데 사람들이 o를 빼먹을 경우가 많을 것이 눈에 훤하다. 마지막은 한국어 발음대로 쓴건데 이건 한국인들만 알 수 있다.

일반적으로 어떤 단어가 많이 사용되는지를 여러 API를 보면서 파악하는 것이 좋다.


그리고 철자는 틀리지 않아야 한다. 도큐멘트가 잘못 된건지 API부터가 잘못된건지 헷갈리기 때문이다.

대문자 소문자가 혼재하지 않는 URI

기본적으로 전부 소문자로 하자. 사람들이 틀릴 것을 고려해야할 필요성이 사라진다.
여러 단어를 최대한 잇지 않는 것이 좋지만 별 수 없다면 -혹은 _을 이용하자.

개조하기 쉬운(Hackable) URI

다른 URI로 확장하기 쉬워야한다. API를 공개하면 물론 도큐멘트를 써야하겠지만 많은 개발자의 경우 그것을 정독하는 일은 드물다.
대부분 하나 써보고 다른건 이렇겠지 하기 때문에 추측하기 쉽게 만들어야 한다.

 

예를 들어, alpha는 1 ~ 30000번을, beta는 40000 ~ 50000번을 취득한다고 하자. 매번 alpha와 beta의 범위를 파악해야하고 범위가 바뀌면 바로 에러가 날 것이다.

 

http://api.example.com/items/alpha/:id
http://api.example.com/items/beta/:id

서버의 아키텍처를 반영하지 않은 URI

위에서 말한 php의 예가 이것이다.

룰이 통일 되어있는 URI

예를 들어 친구의 정보를 취득하는 엔드포인트는 /friends?id=100 인데 비해 진구의 메시지를 취득하는 엔드포인트는 /friend/100/message 일 경우 각 상황마다 도큐멘트를 확인해야한다. 그것은 즉 에러가 나기 쉽다는 것이다.

HTTP메서드와 엔드포인트

URI는 조작하는 자원이고 메서드는 조작방법이다. 자원과 그건을 다루는 방법은 분리해서 생각해야 한다.

Web API에서 사용할 수 있는 메서드와 그 목적은 기본적으로 아래와 같다.

  • GET: 자원의 취득
    • 삭제를 GET으로 하는 것은 금기시 되어있다(크롤링 하다가 데이터를 삭제할 수 있기 때문)
      • a 요소가 아니라 form 요소를 이용(method=post)하면 form은 무조건 기입을 요구하기 때문에 막을 수 있다
  • POST: 자원의 신규등록
    • Elasticsearch의 GET :index/_search 가 내부에서는 사실 POST를 사용하는 것과 같이 구조적인 조건 지정을 필요로 하는 자원 취득의 경우 GET 대신 POST를 쓰기도 한다
  • PUT: 자원의 변경
  • PATCH: 자원의 일부 변경
    • 일부분만 수정하면 되는데 만약 한 데이터 당 1MB 정도 송수신을 해야할 때 PUT을 사용하면 비효율적이다
    • X-HTTP-Method-Override헤더를 붙이자
  • DELETE: 자원의 삭제

엔드포인트 설계

복수형을 적극적으로 쓰자. /list 를 붙이지 않아도 집합이라는 것을 누구나 알 수 있다.

 

ID는 최소한으로 할 수 있게 설계하는 것이 좋다. 예를 들어, 유저 식별자와 친구 식별자가 따로 있다면 서버의 처리가 복잡해질 것이다.
이용자가 알기 쉽고 엔드포인트 생성을 하기 쉽게 설계해야 한다. 예를 들어 내부에서는 따로 식별자를 두고 있어도 엔드포인트에 내부의 사정을 반영하면 안된다.

 

스페이스나 엔코딩을 필요로 하는 문자를 쓰지 않는 것이 좋다. 단어를 잇지 않도록 하는게 좋겠지만 어쩔 수 없다면 -을 쓰자.
스페이스는 URI 상에서는 +로 표시되니 알기 어렵다. _는 호스트명에서 사용할 수 없고 대소문자의 구별은 없어지며 .은 특별한 의미를 갖기 때문이다.

검색과 쿼리 파라미터

한번에 데이터 전체를 취득하는 것은 비현실적이라 pagination을 많이 이용한다. 하지만 페이지라는 개념은 상대적이라 뒤로 갈수록 스킵해야하는 아이템이 몇 개인지 세는 처리 때문에 느려진다.

 

할 수 있다면 지정한 ID까지 혹은 특정 기간 등으로 절대위치를 지정하는 것이 좋다.

쿼리 파라미터와 패스를 구별하는 기준은 아래와 같다.

  • 의미가 있는 자원을 나타낼 필요가 있는가(URI는 자원을 나타내니까)
  • 생략 가능한가

예를 들어, 식별자는 자원이기 때문에 패스로 표현해야 한다.

 

/users/100

 

반면에 액세스 토큰 등은 자원이라기 보단 그 유저가 인증할 수 있도록 하기 위한 것이므로 쿼리 파라미터로 한다.

 

/users/100?access_token=:token

로그인과 인증

OAuth는 제 3자에게 공개되는 API의 인증을 위산 기술이다. 여러 서비스의 엔드포인트를 보면 여러가지 이지만 X(구 트위터)가 제일 알기 쉽다.

  • 트위터: /oauth2/token
  • 드롭박스: /oauth/authorize
  • 텀블러: /oauth/access_token

OAurh 2.0이라는 것이 명확하고 RFC 6749의 예시와 가장 비슷하기 때문이다.

인증 토큰은 Base64로 변환한 것을 쓴다. 바이너리 데이터를 텍스트로 바꿀 때 공통 ASCII 영역의 문자로만 이뤄지는데 64진법이 가장 큰 진법이다.

 

token_type으로 지정되는 bearer는 RFC 6750에서 정의한 OAuth 2.0 용 토큰 형식이다. bearer 토큰은 아래 3가지 방법으로 송신할 수 있다.

  1. 리퀘스트 헤더에 첨부하는 법
  2. 리퀘스트 바디에 첨부하는 법
  3. URI에 쿼리 파라미터로 첨부하는 법

액세스 토큰 취득 시 expires_in 에 만료까지 걸리는 시간(초)가 적혀있다.

 

누구나 접근 가능한 데이터에 접근량을 조절하는 목적으로 인증을 요구하기도 하는데 그럴 땐 Client Credentials 방식을 사용하면 한번만 인증하면 된다.

 

본인의 정보를 취득하기 위해 /me 혹은 /self 를 사용한다. 본인의 정보를 알기 위해 본인의 식별자 등을 알아야 하는 것은 이용자 편의성을 생각했을 때 좋지 못하다. 또한 각 처리와 분리하기 쉽고 잘못 타인의 개인정보를 표시할 염려도 없다.

 

어플리케이션의 한 화면을 구성하는 엔드포인트는 하나여야 한다. 여러번 리퀘스트 하면 그만큼 시간이 걸려 유저가 기다려야 할 수도 있다. 또한 일부 데이터만 표시되거나 보존되는 문제도 막을 수 있다.

 

이 책에서는 REQUEST LEVEL2까지를 권장하지만 REQUEST LEVEL3(데이터 반환시 해당 데이터로 리퀘스트 가능한 URL을 같이 반환해 엔드포인트를 몰라도 되게 하는 방식)도 있다. 아직 시기상조인 측면도 있지만 케이스에 따라 고려해봐도 좋다.