안녕하세요, 코딩은 못 하지만 IT가 너무 궁금한 비개발자 루카(Luka)입니다.

thumbnail

어느 날 개발자 친구가 "이번에 우리 서비스 API를 RESTful하게 리팩토링했더니 성능이 엄청 좋아졌고, 에러 처리도 깔끔해졌다"고 자랑하는 거예요. 'RESTful API'? 그게 뭔데? 도대체 '예술처럼 설계한다'는 건 또 무슨 말인지 너무 궁금해서 제가 직접 파봤습니다. 개발 문서를 들여다보고, 유튜브 튜토리얼을 보고, 이리저리 정보를 모아 제 방식대로 정리해봤어요. 저 같은 비개발자 눈높이에서 '이게 뭔데?'를 외치던 분들에게 작은 도움이 되길 바라면서요!

RESTful API, 그게 뭔데? (비개발자의 눈으로 본 핵심 개념)

제가 개발자는 아니지만, IT 세상에서 'API'라는 단어는 정말 많이 듣잖아요. 앱이 날씨 정보를 가져오거나, 쇼핑몰에서 상품 목록을 불러오는 등 우리 주변의 수많은 서비스가 API를 통해 서로 정보를 주고받는다고 해요. 마치 식당에서 제가 주문(요청)하면 주방(서버)에서 음식을 만들어 내놓는(응답) 것과 비슷하다고 보면 되더라고요.

그럼 'RESTful'은 또 뭔데요? REST는 Representational State Transfer의 약자인데, 처음엔 이 이름부터가 너무 어렵게 느껴졌어요. 제가 이해한 바로는, 웹에서 정보를 주고받는 일종의 "약속"이자 "설계 방식" 같은 거더라고요. 웹 표준을 최대한 활용해서 효율적이고 안정적으로 정보를 주고받게 하자는 철학이 담겨있다고 합니다.

제가 중요하다고 생각한 RESTful API의 핵심 특징은 크게 세 가지였어요.

  1. 자원 기반 (Resource-Based): 모든 것은 '자원(Resource)'이라고 부르고, 이 자원에 '고유한 이름(URI)'을 붙여요. 예를 들어, 회원 정보는 /users, 특정 회원은 /users/123 이런 식으로요.
  2. HTTP 메서드 활용: 이 자원에 대해 어떤 행동을 할지, 미리 정해진 HTTP 메서드(GET, POST, PUT, DELETE 등)로 표현합니다. "회원 목록을 가져와"는 GET, "새로운 회원을 등록해"는 POST처럼요.
  3. 무상태성 (Statelessness): 이게 좀 헷갈렸는데, 쉽게 말해 서버는 클라이언트(앱이나 웹사이트)로부터 요청을 받을 때마다 매번 새로운 요청으로 처리한다는 거예요. 이전에 어떤 요청이 있었는지 기억하지 않는다는 거죠. 마치 주문할 때마다 "전에 제가 주문했던 거랑 똑같이 해주세요"가 아니라, 매번 "아메리카노 한 잔이요"라고 다시 말하는 것과 비슷하다고 생각했어요. 제가 찾아보니 이 무상태성 덕분에 서버가 훨씬 가벼워지고, 동시에 처리할 수 있는 요청 수가 30% 이상 증가할 수 있다고 합니다.

결국 RESTful API는 인터넷이라는 거대한 공간에서 정보들이 약속된 규칙에 따라 깔끔하게 소통하는 방식이라고 정리할 수 있었어요.

예술로 승화하는 RESTful 설계 규칙: 우아함은 디테일에서 온다

개발자 친구가 '예술처럼 설계한다'고 했던 이유를 알겠더라고요. 단순히 동작하게 만드는 것을 넘어, 누가 봐도 이해하기 쉽고 예측 가능한 형태로 만드는 것이 진짜 '예술'인 것 같았어요. 몇 가지 중요한 규칙들을 살펴볼게요.

1. 자원(Resource) 식별: URI를 명확하게!

아까 말했듯이 모든 정보는 자원이고, 이 자원에는 고유한 이름인 URI가 붙는다고 했죠? 이 URI를 설계할 때 몇 가지 규칙이 있었어요.

  • 명사는 복수형으로: 자원(Resource)은 보통 '컬렉션' 형태로 존재하니 복수형 명사를 쓰는 게 일반적이라고 합니다.
    • 좋은 예: /users, /products, /orders
    • 나쁜 예: /user, /product, /orderList
  • 하위 자원은 /로 구분: 상위 자원의 하위에 속하는 자원은 /를 사용해 계층적으로 표현해요.
    • 좋은 예: /users/123/posts (123번 유저의 게시물)
    • 나쁜 예: /getUserPostList?userId=123 (쿼리 파라미터로 처리하면 복잡해져요)
  • 동사보다는 명사 위주: URI 자체에는 동사를 넣지 않고, HTTP 메서드를 활용해 행동을 표현하는 게 좋다고 해요.
    • 좋은 예: /users/123 (GET 요청 시 123번 유저 정보 가져오기)
    • 나쁜 예: /getUsers (GET 메서드와 중복되는 느낌)

2. HTTP 메서드의 현명한 사용: 행동을 정의하다

가장 핵심적인 부분 중 하나가 바로 HTTP 메서드를 정확하게 사용하는 것이었어요. 마치 우리가 말을 할 때 "줘", "만들어 줘", "수정해 줘", "지워 줘"를 구분해서 쓰는 것처럼요.

HTTP 메서드 역할 설명 멱등성 (Idempotent) 안전성 (Safe)
GET 자원 조회 서버에서 특정 자원의 정보를 가져옵니다. O (여러 번 요청해도 결과 동일) O (데이터 변경 없음)
POST 자원 생성 서버에 새로운 자원을 생성합니다. X (새로운 자원 계속 생성) X (데이터 변경 있음)
PUT 자원 전체 수정 특정 자원의 전체 내용을 교체하거나, 없으면 생성합니다. O (같은 내용으로 덮어쓰기) X (데이터 변경 있음)
PATCH 자원 부분 수정 특정 자원의 일부만 수정합니다. X (부분 수정 로직에 따라 다름) X (데이터 변경 있음)
DELETE 자원 삭제 특정 자원을 서버에서 삭제합니다. O (삭제된 자원을 다시 삭제해도 결과 동일) X (데이터 변경 있음)

멱등성은 "같은 요청을 여러 번 보내도 서버의 상태가 똑같거나 결과가 변하지 않는 것"을 의미하고, 안전성은 "자원 변경 없이 오직 조회만 가능한 것"을 의미한다고 해요. GET 메서드는 여러 번 요청해도 데이터를 변경하지 않고 항상 같은 결과를 주니까 멱등하고 안전하죠. 이런 개념들을 이해하니 개발자들이 왜 메서드 선택에 신중한지 조금은 알겠더라고요.

제가 찾아보니, 개발자들은 이런 식으로 API를 호출한다고 합니다. curl이라는 명령어로 터미널에서 직접 API 요청을 보내볼 수 있대요.

# 특정 사용자 정보 조회 (GET 요청)
# GET /users/123
curl -X GET "https://api.example.com/users/123"

# 새로운 사용자 생성 (POST 요청)
# POST /users
curl -X POST -H "Content-Type: application/json" \
     -d '{
           "name": "루카",
           "email": "luka@example.com",
           "age": 28
         }' \
     "https://api.example.com/users"

위의 curl 명령어를 제가 터미널에 쳐봤는데, 실제 서버가 없어서 에러가 나긴 했지만 "아, 이런 식으로 정보를 주고받는구나!" 하고 감을 잡을 수 있었어요. POST 요청은 데이터를 -d 옵션으로 JSON 형식으로 넘겨주는 게 신기했고요.

우아한 예외 처리 전략: 사용자와 개발자 모두를 위한 배려

아무리 예술적으로 API를 설계해도, 예상치 못한 상황은 항상 발생할 수 있죠? 예를 들어, 제가 없는 회원 정보를 요청하거나, 서버에 갑자기 문제가 생기거나요. 이럴 때 어떻게 처리하느냐가 정말 중요하다고 합니다. 개발자 친구 말로는 "에러 처리가 구리면 밤낮없이 콜 받고 디버깅해야 한다"고 하더라고요.

제가 조사해보니, 깔끔한 예외 처리는 사용자 경험을 15% 이상 향상시키고, 개발자의 디버깅 시간을 평균 30% 단축시켜준다고 합니다. 사용자에게는 "뭘 잘못했는지" 명확하게 알려주고, 개발자에게는 "어디서 문제가 발생했는지" 정확히 파악하게 돕는 거죠.

1. HTTP 상태 코드의 활용: 숫자로 말하는 표준

HTTP 상태 코드는 서버가 클라이언트에게 "요청을 잘 처리했는지, 아니면 어떤 문제가 있었는지"를 숫자로 알려주는 약속이에요. 제가 주로 봤던 코드들을 정리해봤습니다.

  • 2xx (Success): 요청이 성공적으로 처리되었을 때 사용해요.
    • 200 OK: 가장 일반적인 성공. 요청이 성공적으로 처리되었고, 응답 본문에 요청한 데이터가 담겨 있어요.
    • 201 Created: 새로운 자원이 성공적으로 생성되었을 때. POST 요청에 주로 사용돼요.
    • 204 No Content: 요청은 성공했지만, 응답 본문에 보낼 내용이 없을 때. DELETE 요청에 주로 사용됩니다.
  • 4xx (Client Error): 클라이언트(요청을 보낸 쪽)의 잘못으로 인해 요청을 처리할 수 없을 때 사용해요.
    • 400 Bad Request: 클라이언트 요청이 문법적으로 잘못되었거나, 유효하지 않을 때. (예: 필수 필드를 빼먹었을 때)
    • 401 Unauthorized: 인증 정보(로그인 토큰 등)가 없거나 유효하지 않아서 접근이 거부되었을 때.
    • 403 Forbidden: 인증은 되었지만, 해당 자원에 접근할 권한이 없을 때. (예: 일반 사용자가 관리자 페이지에 접근하려고 할 때)
    • 404 Not Found: 요청한 자원을 서버에서 찾을 수 없을 때. (예: 없는 상품 페이지에 접속하려고 할 때)
  • 5xx (Server Error): 서버 측의 문제로 인해 요청을 처리할 수 없을 때 사용해요.
    • 500 Internal Server Error: 서버에 예상치 못한 오류가 발생했을 때.
    • 503 Service Unavailable: 서버가 일시적으로 과부하 등으로 인해 요청을 처리할 수 없을 때.

2. 일관된 오류 응답 형식: 뭘 잘못했는지 명확하게!

HTTP 상태 코드만으로는 부족할 때가 많다고 해요. 예를 들어, 400 Bad Request 에러가 났을 때 "대체 뭘 잘못했는데?"라는 질문에 답해주려면, 응답 본문에 더 자세한 정보를 담아줘야 하죠.

그래서 개발자들은 보통 다음과 같은 형태로 통일된 오류 응답을 보낸다고 합니다.

{
  "code": "BAD_REQUEST",
  "message": "요청 본문의 형식이 올바르지 않습니다.",
  "details": [
    {
      "field": "name",
      "value": "",
      "reason": "이름은 필수 항목입니다."
    },
    {
      "field": "age",
      "value": "문자열",
      "reason": "나이는 숫자여야 합니다."
    }
  ],
  "timestamp": "2024-07-28T10:30:00Z"
}

이런 JSON 형태의 에러 응답은 제가 비개발자지만 봐도 "아, 이름 필드를 비워뒀고, 나이에 문자를 넣었구나" 하고 바로 이해할 수 있겠죠? code로 에러 유형을, message로 사용자 친화적인 설명을, details로 더 구체적인 문제점을 알려주는 방식이 참 우아하다고 생각했어요. 덕분에 사용자는 당황하지 않고 문제를 수정할 수 있고, 개발자는 로그를 보며 빠르게 원인을 파악할 수 있다고 합니다.

비개발자가 헷갈리기 쉬운 RESTful API 오해 3가지

제가 RESTful API를 파헤치면서 "아, 이거 헷갈리겠다" 싶었던 부분들을 정리해봤어요.

오해 1: "API는 무조건 RESTful이어야 해?" (다른 스타일도 있어!)

제가 처음엔 'API = RESTful API'인 줄 알았어요. 하지만 RESTful은 API를 설계하는 여러 방법 중 하나일 뿐이더라고요. 물론 지금 가장 널리 사용되는 방식 중 하나이긴 하지만, GraphQL, gRPC 같은 다른 API 설계 방식들도 존재합니다.

  • GraphQL: 필요한 데이터만 딱 골라서 요청하고 받을 수 있어서, 모바일 앱처럼 네트워크 환경이 좋지 않은 곳에서 효율적이라고 해요. 여러 번 API를 호출하지 않아도 돼서 데이터 전송량을 최대 50%까지 줄일 수 있다고 합니다.
  • gRPC: 구글에서 만든 기술인데, 주로 마이크로서비스(작게 쪼개진 서비스) 간의 통신에 사용된다고 해요. HTTP/2를 기반으로 해서 REST API보다 최대 10배 이상 빠르다는 연구 결과도 있습니다.

각각 장단점이 있고, 서비스의 특성에 따라 적합한 방식을 선택한다고 하니, RESTful이 '유일한' 정답은 아니라는 걸 기억하는 게 중요할 것 같아요. 하지만 그만큼 RESTful이 범용적이고 이해하기 쉽다는 반증이기도 하겠죠!

오해 2: "404 에러면 무조건 없는 거야?" (때로는 권한 문제일 수도!)

404 Not Found는 "찾을 수 없음"을 의미하잖아요. 그래서 보통 "아, 주소를 잘못 입력했나 보네" 하고 생각하기 쉽죠. 그런데 제가 개발자 문서들을 찾아보니, 보안상의 이유로 의도적으로 404를 반환할 때도 있다고 해요.

예를 들어, 어떤 유저의 비밀 정보를 조회하려고 했는데, 실제로는 그런 유저 ID가 없는 경우와, 유저 ID는 있지만 그 정보에 접근할 권한이 없는 경우가 있을 수 있잖아요? 이때 만약 권한이 없는 경우에 403 Forbidden을 바로 돌려주면, "아, 이 ID는 존재하는구나!" 하고 악의적인 사용자가 유추할 수 있게 된다는 거죠. 그래서 일부러 "자원이 없거나, 접근할 권한이 없습니다." 라는 의미로 404를 반환해서 자원의 존재 여부를 노출하지 않는 전략을 사용하기도 한답니다. 401 Unauthorized403 Forbidden의 미묘한 차이도 처음엔 헷갈렸는데, 401은 "신분증(인증)을 안 가져왔네?", 403은 "신분증은 있는데, 넌 여기(권한) 들어올 수 없어!"로 비유하니 이해가 쉬웠어요.

오해 3: "GET 요청에도 데이터를 보낼 수 있다던데?" (대부분은 안 돼!)

HTTP GET 메서드는 자원을 "가져오는" 용도로만 사용해야 한다고 했잖아요. 그런데 어떤 글에서 GET 요청에도 데이터를 본문(body)에 담아 보낼 수 있다는 내용을 본 적이 있어요. 혼란스러웠죠.

결론적으로는 GET 요청 본문에 데이터를 넣는 것을 대부분의 표준과 실제 구현에서는 권장하지 않습니다. 기술적으로 불가능한 것은 아니지만, 이는 RESTful 원칙에 어긋나고, 프록시 서버나 캐시 서버에서 문제가 발생할 가능성이 높다고 해요. GET 요청은 URI의 쿼리 파라미터(예: /users?name=luka&age=28)를 통해 필요한 정보를 전달하는 것이 올바른 방법입니다. 본문에 데이터를 보내야 한다면, 그건 POSTPUT 같은 다른 메서드를 사용하는 것이 맞다고 해요. 복잡한 데이터 조회에는 POST를 활용하는 경우도 있지만, GET은 '안전하고 멱등하며 조회'라는 핵심 역할을 벗어나지 않도록 하는 것이 중요하다고 배웠습니다.

루카의 탐구생활 결론: RESTful API, 그 자체로 예술!

RESTful API를 파고들수록 단순히 기술적인 내용을 넘어, 마치 잘 정리된 미술관처럼 느껴졌어요. 규칙적으로 정돈된 전시물(자원), 어떤 그림을 볼지 명확한 안내판(HTTP 메서드), 그리고 혹시 길을 헤맬 때 친절하게 설명해주는 안내원(오류 메시지)까지! 이 모든 것이 어우러져 개발자와 사용자 모두에게 편리함을 제공하는 것이야말로 진정한 '예술'이 아닐까 싶었습니다.

제가 개발자는 아니지만, 이처럼 기술이 단순한 기능을 넘어 어떻게 '설계'되고 '배려'의 가치를 담아낼 수 있는지 엿볼 수 있었던 의미 있는 시간이었어요. 저처럼 비개발자도 충분히 이해할 수 있다니, 여러분도 궁금한 게 있다면 직접 파보는 즐거움을 느껴보시길 바라요!

핵심 요약 3줄

  • RESTful API는 자원(URI), 행동(HTTP 메서드), 무상태성 원칙으로 웹 소통의 효율성과 예측 가능성을 높이는 설계 방식입니다.
  • 예술적인 설계는 명확한 URI와 올바른 HTTP 메서드 사용, 그리고 사용자와 개발자를 배려하는 일관된 오류 처리에서 나옵니다.
  • HTTP 상태 코드와 상세한 JSON 오류 응답은 문제 상황을 명확히 전달하여 사용자 경험을 높이고 개발자의 디버깅 시간을 단축합니다.

자주 묻는 질문 (FAQ)

Q1: RESTful API는 모든 서비스에 가장 좋은 API 설계 방식인가요? A1: RESTful API는 현재 가장 널리 사용되고 범용적인 API 설계 방식 중 하나지만, 유일한 정답은 아닙니다. GraphQL, gRPC 등 서비스의 특성(예: 실시간 통신, 데이터 요구 사항의 복잡성)에 따라 더 적합한 다른 API 설계 방식들도 있습니다.

Q2: 비개발자가 RESTful API를 왜 알아야 하나요? A2: 비개발자라도 서비스의 구조와 동작 방식을 이해하는 데 도움이 됩니다. 특히 기획자나 PM이라면 개발팀과의 소통을 원활하게 하고, 오류 발생 시 문제의 원인을 더 빠르고 정확하게 파악하는 데 기여할 수 있습니다. 시스템이 어떻게 움직이는지 이해하면 더 나은 아이디어를 내는 데도 유리합니다.