# API

“API(Application Programming Interface, 응용 프로그램 프로그래밍 인터페이스)는 응용 프로그램에서 사용할 수 있도록, 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스를 뜻한다.” - 위키피디아

API의 뜻이 좀 광범위하여 처음 언뜻 이해하기가 힘들 수도 있습니다. Interface라는 부분만 집중하면 결국은 나 혼자가 아닌 누군가를 위한 규약이라고 생각하면 됩니다. 주로 라이브러리 개발자가 어플리케이션 개발자한테 인터페이스를 제공하거나 웹이 클라이언트한테 서비스를 프로그래밍적으로 제공하기 위한 규약이라고 보면 됩니다. 여기서는 후자에 해당하는 웹에서 사용하는 API에 대해서 알아보겠습니다.

현재 제일 많이 사용되고 있는 것이 REST API 방식이나 이제 점점 죽어가고(?) 있으며 차세대 API 방식으로 GraphQL을 많이 사용하고 있습니다. 각 API 방식과 차이점에 대하여 알아보고 정리하겠습니다.

# REST API란?

다음은 REST API의 정의들입니다.

REST(REpresentational State Transfer) API: 대의적(대표적) 상태 전달 API

HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고 자원에 대한 행위를 HTTP Method를 통해 정의한다.

2000년도 Roy Fielding의 박사학위 논문에서 최초로 소개되었고, Roy Fielding은 HTTP의 주요 저자 중 한 사람으로 웹의 아키텍처의 우수성에 비해 제대로 사용되어지지 못하는 모습에 안타까워하면서 웹의 장점을 최대한 활용할 수 있는 아키텍처로써 REST를 발표했다고 합니다.

REST는 거의 20년이나 된 것이기 때문에 자료도 너무 많은데도 불구하고 아직 개념을 제대로 이해하지 못한 분들도 있고, "읽어봐도 뭔 소리인지 잘 모르겠다"라고 하는 사람들도 있습니다. 대충 어렴풋이는 알고 있는데 명확하게 설명을 잘 못하는 사람들도 있습니다. 제가 보았을 때 공학을 너무 공학적으로 설명한(?) 글들이 많아 내용을 보고도 이해가 잘 되지 않았던것 같습니다.

사실 좋은 글들이 많은데 굳이 같은 내용을 제가 다시 설명하는 것은 큰 의미가 없는 것 같아서 조금 다른 방식으로 접근해보려고 합니다.

# REST API 의 시작

웹 개발자로 일하던 Roy이라는 사람이 있습니다. Roy은 여러 Third Party 서비스를 한 번에 연동하는 서비스를 개발하고 있습니다.

A라는 서비스의 친구 관련 API 를 물어보니, GetFriendInfo 라고 합니다.
B라는 서비스에 물어보니 GetFriends 라고 합니다.
C라는 서비스에 물어보니 GetMyFriendsInfo 라고 합니다.

세 업체 친구 리스트를 연동해야 하는데 각각 이름이 다 다릅니다. 이번에는 친구 추가 API 입니다.

A 서비스: AddFriendInfo
B 서비스: AddFriends
C 서비스: AddMySuperUltraLovelyFriendInfo

이런 API 각 서비스별로 120개씩 존재합니다. Roy는 식은 땀이 나기 시작합니다.

이번에는 연동을 위해서 어떤 프로토콜을 사용하는지 물어봤습니다.

A 서비스: HTTP/JSON
B 서비스: SOAP/XML
C 서비스: TCP/PACKET

비슷한 작업을 하기 위해서 서로 다른 이름의 API 이름을 일일이 지정하고 프로토콜을 다르게 해야 합니다. 지겹고 반복되는 야근의 연속입니다.

# REST API로 통합

각각의 서비스들마다 API 를 정의하는 방식과 연동 방법이 다르다보니 일일이 각 서비스에 맞춰서 개발을 하느라 시간이 오래 걸리고 생산성이 나지 않습니다. 결국 하고 싶은 것은 데이터를 읽기,추가,수정,삭제 4가지 뿐인데 부가적으로 할 것이 너무 많습니다.

DB에서 하는 일이라고는 복잡한 것 같아도 결론적으로는 읽기(SELECT),추가(INSERT),수정(UPDATE),삭제(DELETE) 뿐이 없습니다.

HTTP 에서는 GET,POST,PUT,DELETE 의 4가지 Methods 를 지원합니다.(사실 몇 개 더 있습니다.)

바로 이거다. 하나의 자원에 대해서 HTTP를 통해서 GET(SELECT), POST(INSERT), PUT(UPDATE), DELETE(DELETE) 를 하자. 그리고 편의를 위해서 무조건 JSON 형태로 주고 받자.

URL GET POST PUT DELETE
service/friends 친구 정보 얻기 친구 추가 친구 정보 수정 친구 삭제
service/items 아이템 정보 얻기 아이템 추가 아이템 정보 수정 아이템 삭제

이것이 바로 REST API 입니다. 물론 Roy가 각 서비스들에게 API 를 변경하라고 할 수는 없지만, 현실에서 각 서비스 제공자든 서비스 소비자든 통합을 원했고 이런 방식으로 표준스럽게 채택하여 사용하기 시작합니다.('표준스럽게'라고 표현한 것은 표준 위원회에서 공식적으로 채택한 내용은 아니나 사람들이 많이 사용하여 표준처럼 사용이 되어왔기 때문입니다.)

REST API 란 각기 다른 서비스나 서버-클라이언트 간에 규약입니다. 이름도 방식도 중구난방으로 하면 서로 힘드니 우리 이런 방식으로 통일해서 사용하자 해서 고착화 된 것이 REST API 입니다.

# REST API 설계

위에서 언급한 바와 같이 REST API 는 정확한 표준은 아닙니다. 그냥 이런식으로 하자라고 고착화 된 것이다보니 완전히 통일이 되지 않았습니다. 대부분 많이 쓰는 방식이 존재하나 그것이 REST다 라고 정의하기는 힘듭니다.(REST 스럽게 구현했다고 해서 RESTFul API 라는 표현도 합니다.)

이에 필자가 많은 사람들이 사용하는 방식으로 간단한 REST API를 정의하려고 합니다만, 다른 사람도 모두 같은 방식을 쓰는 것은 아니라는 것만 염두에 두시면 됩니다.

# REST API 필요 개념

REST API 의 URL의 끝에 ID가 붙는지 안 붙는지에 따라서 크게 두 가지 형태로 나뉩니다.

  • 컬렉션(Collection): 집합(Array) > 유저들, 아이템들, 이벤트들
  • 도큐먼트(Document): 객체 하나(Object) > 유저, 아이템, 이벤트

중첩된 구조일 경우 상위 URL 에 종속적입니다. 다음은 예시입니다.

URL 구분 설명
/users 컬렉션 유저 리스트
/users/111 도큐먼트 유저 번호가 111 인 유저 정보
/users/111/items 컬렉션 유저 번호가 111 인 유저의 모든 아이템 리스트
/users/111/items/123 도큐먼트 유저 번호가 111 인 유저의 아이템중 아이템 번호가 123 인 아이템 하나의 정보

# REST API 설계 규칙

  • 소문자, 숫자, -(대시)만 사용: _(언더바 사용안함)
  • 동사보다는 명사를 사용
  • 복수 명사만 사용, 단수 사용 안함
  • 슬래시(/)는 계층 관계
  • Stateless(무상태성): API 자체는 상태를 가지지 않음. Cookie, Session 등을 사용하지 않고 단순히 들어오는 요청 값에 의해서만 처리하여 구현이 단순해짐. 인증은 JWT를 사용하고 상태가 필요한 정보는 DB에 질의함
예외: 자원이 대상이 아닌 인증 등의 행위에 대해서는 동사를 허락하고 POST 방식을 사용(Web Form 과 동일)
# HTTP Method
GET POST PUT DELETE
SELECT INSERT UPDATE DELETE
조회 추가 수정 삭제
# HTTP 응답 코드
  • 200: 성공
  • 400: 잘못된 요청(파라미터를 잘못 보낸 경우)
  • 403: 권한 없음(유저가 어드민 API를 호출한 경우)
  • 404: 리소스 없음(존재하지 않는 리소스를 요청한 경우)
  • 500: 서버 오류(서버 내부 예외 상황)

이와 같은 형식으로 API의 이름과 응답을 정의하여 사용하는 것을 REST API라고 합니다.

# GraphQL이란?

GraphQL이란 페이스북에서 개발하여 발표한 내용으로 Graph + Query Language의 약자로 정확하게는 언어입니다. SQL(Structured Query Language)과 마찬가지로 기본적으로 데이터를 쿼리하기 위하여 만들어졌으나 SQL은 데이터베이스에 직접 질의를 하기 위해 만들어졌고 GraphQL은 서비스에 데이터를 질의하기 위해서 제작 되었습니다. 사전적 정의는 언어이나 일반적으로 GraphQL이라고 하면 GraphQL 형식의 아키텍처 전체의 의미로 사용됩니다.

# REST API 한계

GraphQL이 나온 배경이 REST API 한계 때문이기 때문에 이 부분에 대해서 알아야 합니다.

REST API는 Over-Fetching과 Under-Fetching의 문제가 있습니다.

# Over-Fetching

Over-Fetching이란 사용하지 않는 데이터까지 너무 많이 가져오는 것입니다.
REST 방식에서 하나의 Object를 대상으로 API를 요청하면 필요하든 안하든 대상의 모든 내용이 다같이 반환됩니다.

// GET /user/1 요청
{
  "name": "Roy",
  "company": "weperson",
  // 기타 사용하지 않는 필드들...
}
1
2
3
4
5
6

# Under-Fetching

Under-Fetching이란 End Point가 달라서 한 번에 데이터를 가져오지 못해 여러 번 호출 하는 것입니다.
REST 방식에서는 하나의 대상을 위해서도 하위 Object에 대해서 여러 번 호출 해야 합니다.

// GET /user/1/items 요청
{
  "items": [
    { "id": 1, "name": "knife", "price": "1000" },
    { "id": 2, "name": "shield", "price": "2000" }
  ]
}
// GET /user/1/books 요청
{
  "books": [
    { "id": 1001, "name": "Hobbit", "price": "1000" },
    { "id": 1002, "name": "Road of Ring", "price": "2000" }
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

End Point가 분리되어 있으면 items와 books를 한 번에 가져 올 수 없습니다.

# GraphQL 쿼리 및 응답

End Point 하나에 요청할 대상들과 필드들 및 액션(Mutations)까지 포함하여 한 번에 호출하고 한 번에 응답을 받습니다.

Schema 출처: apollographql

다음과 같이 user(name, company), items(id, name), book(id, name) 필드들을 한 번에 요청합니다.

// gql 요청
query {
  user {
    name,
    company,
    items {
      id,
      name
    }
    books {
      id,
      name
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

다음과 같이 정확히 요청한 대상에 대하여 요청한 필드만 한 번에 응답받습니다.

{
  "data": {
    "user": {
      "name" : "roy",
      "company": "weperson",
      "items": [
        { "id": 1, "name": "knife" },
        { "id": 2, "name": "shield" }
      ],
      "books": [
        { "id": 1001, "name": "Hobbit" },
        { "id": 1002, "name": "Road of Ring" }
      ]
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

여기서 중요한 것은 "한 번에"라는 것입니다. 요청도 응답도 한 번에 이루어집니다.

# GraphQL의 구조

GraphQL의 주요 구조는 다음과 같습니다.

# Schema

GraphQL을 정의하기 위해서는 스키마가 필요합니다. 스키마를 정의할때는 명확한 타입 또한 지정이 되야 합니다. 스키마와 타입을 미리 지정해 놓음에 따라 요청/응답 시 별도의 데이터 형을 지정하지 않아도 됩니다.

type User {
  id: Number!
  name: String!
  company: String!
  items: [Items]
  books: [Books]
}
1
2
3
4
5
6
7

# Operation

Operation에는 쿼리(query), 뮤테이션(mutation), 구독(subscription) 세 가지 종류가 있습니다.

  • query: 질의를 하기 위해 사용
  • mutation: 조작을 하기 위해 사용
  • subscription: 데이터의 변경을 감지하기 위해 사용

# Resolver

리졸버(Resolver)는 Operation으로 들어온 내용을 어떻게 해결할지를 정의하는 역할입니다. Function의 형태로 query등의 인자를 확인하고 실제 결과 값을 리턴해주는 역할을 합니다. GraphQL은 플렛폼 종속적이 아니기 때문에 Resolver에서 무엇을 하든 상관없습니다. 하드코딩 된 데이터를 넘겨주던 SQL DB에 값을 불러오든 NoSQL이나 심지어 다른 서비스를 다시 호출하여 내용을 리턴하여도 됩니다. Resolver는 실제 처리를 담당하는 역할이고 한마디로 GraphQL의 해결사 역할을 합니다.

# Instrospection

간단하게 문서화라고 표현할 수 있습니다. 대부분의 GraphQL 프레임워크들이 문서화 도구가 내장이 되어 있습니다. REST도 다양한 문서화 방식이 있지만 GraphQL은 문서화 내용을 스키마에 내장이 가능합니다. API의 핵심은 누군가 API를 사용하는 것이기 때문에 문서화는 매우 중요한 것이고 문서화와 코드가 같이 저장되고 변경된다는 것은 매우 중요한 내용입니다.

더 자세한 GraphQL 스팩은 여기를 참조하시길 바랍니다.

# REST API vs GraphQL

REST는 죽었다. - 필자

감히 REST는 죽었다고 표현해도 된다고 생각합니다. 앞으로는 GraphQL이 대세가 되어갈 것입니다.

한 번에 요청을 하고 받으니, 트레픽도 아끼고, 트레픽을 아끼니 비용도 아끼고, 병렬 처리가 되니 응답 속도도 빠르고, Subscription을 통해 실시간 통신까지 가능하니 딱히 GraphQL을 안 쓸 이유를 못찾겠습니다. 약간의 러닝커브가 있다고 하나, 시니어 기준으로 하루 이틀 정도로 무시해도 될 정도입니다. 단, 아직도 레거시(REST)가 많이 존재하므로 최소한 REST의 구축 및 사용법 정도는 알고 있어야 할 듯 합니다.

# 정리

GraphQL을 사용합니다. 사실 GraphQL을 쓰는 것이 중요한 것이 아니고 어떻게 쓰느냐가 더 중요합니다. GraphQL은 어차피 타입을 정의해야 합니다. 어차피 타입을 정의해야 한다면 TypeScript나 ORM과 궁합이 잘 맞습니다. 자세한 내용은 실 사용 예시를 포스팅 할때 정리하겠습니다.

혹시나 초단순(?) 서비스가 필요할 때나 레거시도 지원을 하기 위해서 REST를 가끔 일부에 사용하기도 합니다.

Last Updated: 10/29/2020, 3:39:34 PM