커뮤니티실 API Design-First 접근방식 정착기

Heidi
당근 테크 블로그
11 min readMay 13, 2024

안녕하세요! 커뮤니티실 그룹 플랫폼팀의 서버 개발자 하이디(Heidi)예요🌼 저는 동네에서 일어나는 다양한 온·오프라인 활동을 연결하는 ‘모임’ 서비스를 만들어 나가고 있어요.

커뮤니티실은 사용자에게 연결의 가치를 전하기 위해 도전적이고 다양한 기능들을 빠르게 테스트하는 조직이에요.

이 과정에서 서버와 클라이언트 간의 API 인터페이스 조율이 자주 발생하게 되어 팀원 모두가 JSON 관리의 달인이 되고 있단 생각을 하곤 해요🌞. 그렇다 보니 API 라는 소통 수단은, 구현하는 것 뿐만 아니라 설계하는 것 또한 매우 중요하다는 점을 깨닫게 됐어요. 효율적인 API 설계야말로 원활한 데이터 교환을 위한 초석이 되기 때문이에요.

그런 의미에서, 오늘은 커뮤니티실 개발자들이 어떤 방식으로 API를 만들어왔고, 현재는 어떻게 만들고 있는지 소개하는 시간을 가져볼까 해요. 어려운 내용은 아니니, 가벼운 마음으로 재밌게 읽어주세요 🌱

Design-First

커뮤니티실에서 만들고 있는 서비스는 사용자 경험을 중요하게 여기고 있는 만큼 다양한 화면과 기능으로 이루어져 있어요. 따라서 클라이언트 관점에서의 API 설계가 매우 중요해요. 사용자가 어떤 방식으로 서비스를 경험하게 될지를 고려해 API를 설계해야 하니까요.

이런 이유로, 커뮤니티실에서는 API를 설계할 때 자연스럽게 “Design-First” API 접근 방식을 택하게 됐어요.

Design-First 접근 방식이란, API 설계 시에 명세를 먼저 작성하는 접근법을 뜻해요.

서버 구현에 앞서, 클라이언트와 함께 양쪽의 의견이 잘 버무려진 API 명세를 정의한 다음, 이를 기반으로 클라이언트와 서버를 동시에 구현하는 방식으로 API를 만들고 있다고 이해해주시면 되어요. (아마 많은 분께 익숙한 방식일 것 같아요 🤗)

커뮤니티실 API 설계 방식 변천사

과거 API 설계 방식, 노션

2022년 초에는 주로 노션을 통해 API 명세를 작성했어요. 노션은 누구나 쉽게 접근 및 수정을 할 수 있기에, 서버와 클라이언트가 API 명세에 대해 빠르게 논의할 수 있었기 때문이에요.

노션을 이용해 API 를 만드는 과정은 아래와 같아요.

  1. API 명세를 작성한다.
  2. 위의 명세에 기반해

2–1. 클라이언트에서 Mocking API를 작성하고, 임시로 사용한다.

2–2. 서버에서 API를 작성한다.

3. 서버에서 API가 완성되면, 클라이언트에서 해당 API를 사용한다.

노션을 이용한 API 작성 과정

노션은 구성원이 적은 상황에서 서로 가볍고 빠르게 소통하고 수정할 수 있다는 장점이 있었어요. 하지만 점차 동료들이 늘어나고 서비스의 크기가 커지면서 여러 가지 문제점에 직면하게 되었죠. 😭

~ 노션으로 API 명세를 논의해봤다면 왠지 모르게 익숙할 문제점들 ~

1️⃣ 노션 API 명세를 보고, 요청/응답 모델을 수동으로 작성해요. ⇒ “개발 속도의 저하”

2️⃣ 유사한 구조를 가진 API가 늘어날수록, 그에 따른 비효율은 더 커졌어요. ⇒ “비효율적인 개발”

3️⃣ API 명세를 만드는 사람마다 방식이 달라요 ⇒ “표준이 없음”

4️⃣ 게시글 조회 API 말고, 사용자 정보 조회 API 명세는 어디서 찾아야 해요? ⇒ “명세의 파편화”

5️⃣ 이 명세 최신 맞아요? ⇒ “API 명세 신뢰도 부족”

이러한 문제점들을 하나씩 겪게 되면서, 우리 팀에 더 잘 맞는 API 설계 방법은 없을지 고민하기 시작했어요. 그러다가 기존 문제점들을 보완할 수 있는 새로운 방식을 찾게 되었죠. 그건 바로 API 명세 작성을 위한 IDL인 **OpenAPI Specification** 이었어요.

OpenAPI Specification, OAS

OpenAPI Specification, 줄여서 OAS라고 불리는 이 인터페이스 언어는 HTTP API를 정의하고 문서화하기 위한 규격이에요. API의 엔드포인트, 매개변수, 입출력 데이터 형식을 JSON 이나 YAML 형태로 표현할 수 있어요.

또한, OAS의 규격에 맞는 API 명세를 작성하면 openapi-generator라는 도구를 통해 API 문서와 다양한 프로그래밍 언어의 클라이언트/서버 코드를 자동으로 생성해줄 수 있어요.

OAS API 명세를 기반으로 생성된 API 문서, 각 언어별 서버/클라이언트 코드

OAS를 사용하면 노션을 이용한 기존 API 명세 설계 방식의 문제점들이 이렇게 해결돼요.

1️⃣ , 2️⃣ 노션 API 명세를 보고, 요청/응답 모델을 수동으로 작성해요. / 유사한 구조를 가진 API가 늘어날수록, 그에 따른 비효율이 커져요.

⇒ YAML 이나 JSON으로 API 명세를 작성하면 각 요청과 응답에 대한 코드를 생성할 수 있으므로, 수동으로 작성하지 않아도 돼요.

3️⃣ API 명세를 만드는 사람마다 방식이 달라요.

⇒ OAS에서 제안하는 규격대로 API 명세를 작성해야하기 때문에 API를 일관된 형식으로 작성할 수 있어요.

4️⃣ 게시글 조회 API 말고, 사용자 정보 조회 API 명세는 어디서 찾아야 해요?

⇒ 모든 API 명세를 별도 저장소에서 관리하면, 각 명세를 쉽게 찾을 수 있어요.

5️⃣ 이 명세 최신 맞아요?

⇒ API 명세를 통해 코드로 만들어진 요청/응답 모델을 사용하면, 코드와 명세와 강결합되어 항상 최신성이 보장돼요.

그뿐만 아니라 OAS는 누구나 쉽게 이해할 수 있는 YAML 이나 JSON으로 API를 정의할 수 있어요. 그래서 누구나(심지어 개발자가 아니더라도) API 명세에 기여할 수 있죠. 이런 점은 클라이언트 중심 API 설계를 중요하게 여기는 커뮤니티실의 개발 방향성과도 잘 맞아떨어진다고 생각했어요.

그래서!(두둥) 커뮤니티실은 OAS로 API 명세를 관리하기로 했어요. 🤟

현재 API 설계 방식, OAS

새로이 OAS를 도입한 결과, API 명세를 만들어가는 과정은 이렇게 달라졌어요.

  1. API 명세를 관리할 전용 저장소(GitHub Repository)를 만든다.
  2. 해당 저장소에 Pull Request 를 열어 API 명세를 정의하고 검토한다.
  3. 명세가 main 브랜치에 머지되면, GitHub Actions 워크플로우에서 openapi-generator를 실행해 클라이언트/서버 코드를 자동으로 생성한다.
  4. 클라이언트/서버는 생성된 코드를 사용한다.
OAS를 이용한 API 작성 과정

이렇게 API 명세를 논의하는 공간(노션 → Github Repository), 명세에 사용되는 언어(JSON 포맷 → OAS), API 요청/응답을 만드는 방식(수동 작성 → openapi-generator) 등에서 기존 방식과 차이가 있어요.

이처럼 OAS를 이용해 API를 만들면서 기존에 경험한 몇 가지 문제점들을 해결할 수 있었는데요.

다음으론 OAS와 함께한 1.5년의 경험을 바탕으로 좋았던 점뿐만 아니라, 고려해야 할 점들을 솔직하게 공유해 드려보도록 할게요! 😎

OAS 사용 후기

좋았던 점

앞서 말씀드린 것처럼, OAS를 사용하면서 여러 장점을 얻게 되었는데요. 다시 한번 간단하게 짚고 넘어가 볼게요.

  • 별도의 저장소에 API 명세를 관리함으로써 명세를 좀 더 체계적으로 다룰 수 있게 되었어요.
  • 서버와 클라이언트의 API 인터페이스 코드는 이 명세로부터 만들어지기 때문에, 각자가 직접 코드를 작성할 필요성이 줄어들었어요.
  • 게다가 항상 최신 명세를 기반으로 코드가 만들어지니 일관성도 보장받을 수 있게 되었어요.
  • 이와 더불어, Pull Request 를 통해 API 명세를 생성하거나 수정하다 보니, 누가 · 언제 · 왜 · 무엇을 변경했는지에 대한 내역을 쉽게 파악할 수 있었어요.

이런 장점들과 더불어, OAS를 사용하면서 무엇보다 좋았던 점 하나는 서버와 클라이언트 간 API 명세에 대해 커뮤니케이션할 때 OAS에 정의된 모델을 중심으로 대화할 수 있다는 점이에요.

간단한 예시를 하나 들어드릴게요!

우리는 API의 전체적인 응답 구조를 일관성 있게 가져가고 싶은 멋진 개발자들이에요. 이때 여러 API에서 동일 혹은 비슷하게 사용되던 응답 프로퍼티를 하나 수정해야 하는 상황이라고 가정해볼게요.

이런 경우, 기존 방식에서는 이렇게 말해야 했어요.

Heidi : 사용자 정보 조회 API 의 user.isDaangnuser.isKarrot 으로 바꾸는 게 어때요? 아, 게시글이나 댓글 API 안에 사용자 정보가 들어있었던 것 같은데, 거기에도 반영하면 좋을 것 같아요!

이렇게 하나하나 API 별로 언급해야 하는 방식은 수정해야 할 API가 많아질수록 고통스러워져요. 아무래도 사람의 기억에 의존해야 하는 부분이 있으니까요.

OAS를 사용하면서 이렇게 말할 수 있게 되었어요.

(행복한) Heidi : 저희 User 모델에 isDaangnisKarrot 으로 바꾸시죠! PR 작성해둘게요~

OAS는 아래 예시와 같이 모델(Schema)을 정의하고 이를 API 명세에 활용할 수 있어요. 간단한 User 모델(Schema)을 정의하고, 사용자 정보 조회 API 명세를 작성해볼게요.

paths:
/user/{id}:
get:
summary: 사용자 정보
parameters:
- name: id
in: path
schema:
type: integer
format: int64
responses:
200:
content:
application/json:
schema:
$ref: "#/components/schemas/User"
components:
schemas:
User:
type: object
properties:
id:
type: integer
format: int64
isDaangn:
type: boolean

위와 같이 정의한 User 모델을 여러 API 명세에서 공유해서 사용할 수도 있어요. 만약 User 모델을 수정하면, 그 모델을 참조하고 있던 모든 API에 자동으로 반영되어요. 하나하나 별도로 찾아가며 수정할 필요가 없어져요.

이렇게 API 수정 작업의 비효율성을 줄일 수 있을 뿐만 아니라, API 서버와 클라이언트 간 소통 수단이라는 점에서도 도움이 되는 부분이 있어요. 서버와 클라이언트 개발자들이 동일한 용어로 대화할 수 있게 되거든요.

모두가 같은 모델을 바라보며 대화하니까 API 명세 작업 전반에 걸쳐 협업이 한결 수월해졌다고 생각해요. ^-^/

OAS 모델 이름으로 소통하는 멋진 우리 😎

고려할 점

휴가 중인 동료에게 API 수정사항을 알리는 건에 대하여.. 🙏
  • 명세로 문서와 코드를 만들다 보니, 명세 정의에 실수가 생기면 (당연하게도) 문서와 코드에도 반영돼요. 이에 따라 명세를 정의할 때 부담이 생기는 부분이 있어요.
  • API 명세 저장소를 별도로 관리하다 보니, 이 저장소에 대한 오너십의 경계가 모호해질 수 있어요. 관리를 소홀히 하지 않도록 주의해야 해요.
  • 서버와 클라이언트 개발자들이 함께 API 명세를 논의하다 보니, 이 명세를 확정하는 데 꽤 오랜 시간이 소요되기도 했어요. (이런 점은 Design-First 접근법을 사용하는 모두가 겪는 부분이겠죠? ㅎㅎ)

글을 마치며

이처럼 저희는 OAS라는 인터페이스 언어를 사용해 Design-First 접근 방식으로 API를 디자인하고 있어요.

“우리가 더 잘 일하는 방법”에 대해 고민하고 개선해나간 결과물이죠.

커뮤니티실엔 “진심”인 사람들만 모여있어요. 일에도 진심이지만, 특히 프로덕트에 진심인 편이에요😎 사용자가 동네에서 이웃과 가치 있는 연결을 할 수 있도록 최선을 다하고 있죠.

저희가 프로덕트에는 얼마나 진심인지, 궁금하지 않으신가요?

🌼 커뮤니티실에서는 현재, 진심 가득한 동료를 기다리고 있답니다 🌼 지.금.바.로.지.원.고 ! 😘

--

--