1. 서론

몇 달전 서점에서 “웹 API 디자인” 이라는 책을 구매해서 열심히 읽어봤다.

이 책을 읽고나서 OAS에 대해 알게 되었다.

백엔드 프로그래밍을 주로 하겠다는 사람이 아직도 이걸 몰랐다니,

역시 사람은 아는 만큼 보이나보다.

아무튼, 이번 학기 프로젝트를 진행하면서 API를 설계하는데

이 책의 내용과 내 나름대로의 원칙을 결합하여 좋은 REST API가 무엇인가를 고민해 보았다.

2. 본론

2.1 API 설계 딜레마


사실 ‘좋은 API’가 무엇인가? 를 한마디로 정의하긴 어렵다. 이 책에서도 완벽한 API 설계는 불가능하다고 말한다. API 설계는 상황에 따라 달라질 필요가 있다.

원칙을 너무 고수하면 이해하기 어려운 API가 튀어나오고, 그렇다고 원칙을 지키지 않으면 스파게티 API가 되어버린다. 적절한 타협이 필요한 것 이다.

그리고 ‘좋은 API’라는 단어는 상당히 주관적인 성격을 가진다. 내게는 좋아보이지만 상대방은 그렇지 않을 수 있다. 그러므로 나 또한 이 책에서 소개하는 API 설계 이론 모두를 동의하는 것은 아니다.

지금 소개하는 방법은 이 책의 내용을 어느정도 수용하고, 또 내가 생각하는 좋은 방법이 담겨져 있다. 이 글을 읽고난 뒤 본인에게 맞는 API 설계 원칙을 한번 세워보는 것도 좋을 것 같다. (물론 회사에 다닌다면 그 회사에 맞는 원칙을 따르라…)

2.2 RESTFUL 이해


우선 본인이 어떤 원칙을 가지고 있던 간에, API 설계라는건 다른 사람들이 당신의 API를 보고 끄덕 할 수 있도록 ‘RESTFUL’한 조건에 기반하여야 한다. 대한민국의 모든 법은 헌법에 기초하는 것과 같은 원리다.

  • 리소스(Resource)는 명사, 복수형이다.
  • GET(조회), POST(추가), PATCH(수정), DELETE(삭제) 정확히 사용하자.

리소스가 명사여야 하는 이유는 HTTP Methods가 이미 동사이기 때문이다.

의외로 아무 생각 없이 짜다보면 지키지 않는 경우가 많다!

2.3 Query String vs Path Parameter


URL을 구성할 때, Query String과 Path Parameter가 뭔지 또 어떨때 사용해야하는지 구분 못하는 사람들이 은근히 많다.

우선 Path Parameter은 가변 경로라고 보면 된다.

/students/:student_id 라는 경로는 /students/20152399 또는 students/20172499 이런 식으로 변할 수 있다. 즉, :student_id 이 부분이 가변이라는 것이다.

Query String은 path 뒤에 ? 부터 시작하여 key=value 쌍을 갖는다.

다음 API를 생각해보자.

GET /students?gender=male 이런 API가 있다면 남자인 학생들만 조회한다.

즉, QueryString은 필터링(Filtering)을 위한 용도로 활용되어야 한다.

물론 이 부분은 개인 취향일 수 있다. ‘key를 이용한 검색’에서 파라미터를 사용하지 않고 전부 쿼리로 때려버리는 경우도 아주 흔하기 때문이다.

그러나 그것은 별로 좋은 방법은 아니라고 생각한다. key라는 것은 본래 하나의 원소를 특정하기 위해 존재하는 것이 아닌가? 그렇다면 특정 리소스를 지칭할 수 있는 의미를 갖게 하는 것이 좋다.

GET /students?student_id=20152399 보다는 GET /students/20152399이 낫다는 것이다.

2.4 예제 Schema


다음과 같은 학생 Table이 있다고 가정하자.

1
2
3
4
student_id TEXT PRIMARY KEY
name TEXT
gender NUMBER
department TEXT

2.5 조회 API


조회 API는 크게 두 가지로 구현한다.

2.5.1 통함 검색


1
GET /students
  • Query String (필터링)

    • gender = male | female
    • department = 학과명
  • Return Type

    • Array<Student>
  • example

    • 컴퓨터학부 여학생 조회: GET /students?department=컴퓨터학부&gender=female

2.5.2 특정 레코드 검색


1
GET /students/:student_id
  • Path Parameter

    • :student_id 학번
  • Return Type

    • Student
  • example

    • 학번이 20152399인 학생 조회: GET /students/20152399

2.6 추가 API


POST 메소드를 사용하여 학생을 추가한다.

1
POST /students/:student_id
  • Request Bodies
1
2
3
4
5
{
name,
gender,
department
}

2.7 삭제 API


Path Parameter(primary key)를 이용해 삭제한다.

1
DELETE /students/:studnet_id

2.8 수정 API

Path Parameter(primary key)와 request body를 동시에 이용한다.

원소를 식별하기 위해, student_id를 제발 request body에 넣지말자!!


1
PATCH /students/:student_id
  • Request Bodies
1
2
3
4
5
{
name,
gender,
department
}

단, 부분 업데이트이기 때문에 모든 Request Body를 선택사항(Optional)로 구현한다.

  • example

    • 학번이 20152399인 학생의 학과를 소프트웨어학과로 변경:
    1
    2
    3
    4
    PATCH /students/20152399
    {
    "department": "소프트웨어학과"
    }

2.9 소유 관계 API

이 책에서 소유 관계는 다음과 같이 표현하라고 한다.

  • 학번이 20152399인 학생이 가지고 있는 연필: GET /students/20152399/pencils

이를 API로 나타내면 GET /students/:student_id/pencils일 것이다.

만약에 어떤 학생에게 새로운 연필을 추가한다고 하면 어떻게 해야할까?

역시 Path Parameter를 이용한 설계가 필요하다.

1
POST /students/:student_id/pencils

3. 결론


API 설계는 결코 쉽지 않다. 이해하기 쉬운 API를 설계하는 과정에서 정말 갈등되는 상황이 많기 때문이다.

API 설계에 있어 많은 경험과 확고한 원칙 그리고 유연한 사고가 필요하지 않을까.