C.W.K.
Stream
Lesson 02 of 04 · published

REST 안 쓸 때 — gRPC, GraphQL, 맞는 도구 질문

~10 min · epilogue, grpc, graphql, alternatives

Level 0HTTP Newbie
0 XP0/46 lessons0/12 achievements
0/120 XP to next level120 XP to go0% complete
"REST 가 하나 architectural style. 대부분 경우에 충분히 좋고 infrastructure-friendly 라서 지배. 근데 작업 카테고리 셋이 더 좋은 대안 있고, 아닌 척하는 게 낭비 노력."

REST 가 잘못된 경우들

1. Typed 내부 service-to-service 트래픽 → gRPC. Control 하는 두 service 가 높은 볼륨으로 서로 말하면 typed 계약, generated stub (손수 만든 client 없음), JSON overhead 없는 HTTP/2 multiplexing 원함. gRPC + Protobuf 가 이거 깔끔히 함. Kubernetes, 모든 주요 cloud provider 의 내부 mesh, microservice estate — 다 안에 gRPC.

2. Rich client 가 깊은 schema 에서 필드 고름 → GraphQL. 여러 client type (web, mobile, partner 앱) 이 관련 데이터의 다른 조각 원함 — 제품 + 리뷰 + 저자 + 유사 제품, 근데 각 client 가 다른 부분집합 원함 — REST endpoint 가 확산하거나 너무 많이 돌려줌. GraphQL 이 client 가 query 쓰게.

3. 자연 procedural operation → RPC-over-HTTP. 일부 operation 이 resource 에 자연 매핑 안 됨. "이 코드 컴파일," "이 비디오 transcode," "이 prompt 완료" — verb, 명사 아님. Rich payload 가진 action endpoint POST (OpenAI 의 /v1/chat/completions) 가 정직히 RPC. REST 인 척이 강제됨.

gRPC — Typed, Binary, HTTP/2

gRPC 가 service 를 Protobuf .proto 파일로 정의; tool 이 10+ 언어의 typed client 와 server 생성. Wire format 이 HTTP/2 위 binary Protobuf. 승리:

  • Typed 모든 거. "그 필드가 string 인지 number 인지?" 없음 — .proto 가 말함.
  • Generated stub. Go, Python, Java, TypeScript 의 client — 다 같은 .proto 에서, 다 type-checked.
  • HTTP/2 multiplexing 내장. 한 연결에 여러 동시 호출.
  • 양방향 streaming. 양 측이 stream 가능; WebSocket framing 보다 훨씬 단순.

비용: binary wire 가 브라우저 DevTools 에서 못 읽음; CDN 지원 제한 (gRPC-Web 이 우회); proto 진화가 규율 필요. 내부 service mesh 엔 가치; 소비자 다양한 공개 API 엔 가치 거의 없음.

GraphQL — Client-Chosen Shape

GraphQL 이 client 가 원하는 정확한 필드 묘사하는 GraphQL 문법의 query 보내는 단일 endpoint (보통 POST /graphql) 노출:

{
  user(id: "u_42") {
    name
    email
    orders(limit: 3) {
      id
      total
      items { name }
    }
  }
}

Server 가 각 필드 독립 resolve. Client 가 요청한 거 정확히 받음. 승리:

  • Over-fetch / under-fetch 해결. Mobile 이 작은 payload; web admin 이 큰 거 — 같은 endpoint.
  • 관련 데이터 위한 round trip 하나. Client-쪽 N+1 없음.
  • 강한 typing GraphQL schema 통해.

비용: caching 어려움 (모든 query 다름); 복잡 query 가 resolver 조심히 안 쓰면 DB 두드림; request shape 호출 당 다양해서 intermediary (CDN, proxy) 최적화 어려움.

RPC — Operation 에 명사 없을 때

진짜 procedural operation 엔 RPC-over-HTTP (JSON payload 가진 action endpoint 에 POST) 가 정직. POST /complete, POST /transcode, POST /sign. OpenAI Chat Completions API 가 정확히 이거 — 그리고 REST 인 척이 charade.

현대 RPC 패턴: tRPC (TypeScript-only, end-to-end typed), JSON-RPC 2.0, plain POST-with-JSON. 맞는 operation 에 RPC 선택이 'REST 포기' 아님; protocol 을 트래픽 shape 에 매칭.

Architectural style 이 선택, 미덕 아님. REST 가 API 트래픽 80% 이긴 이유 트래픽 shape 80% 에 맞아서 — caching, intermediary, browser-friendly, statelessly retryable. 20% 가 더 좋은 도구. 트래픽 shape 으로 선택; 두 문장으로 선택 변호; 그것에 대해 철학적이 되지 마.

결정 heuristic

  • 내부 service mesh, 양 측 typed → gRPC.
  • 다른 필드 부분집합 원하는 많은 다양 client → GraphQL.
  • 명백한 명사 없는 operation-shaped 트래픽 → HTTP 위 RPC.
  • 공개 CRUD, 통합, 브라우저 앱 → REST.
  • Real-time 양방향 → WebSocket (혹은 내부엔 gRPC streaming).
  • Server-push 된 event, one-way → SSE.

대부분 production system 이 이 중 2-3 씀. cwkPippa 가 REST + SSE + WebSocket. 전형적 SaaS 가 REST + GraphQL + gRPC (공개엔 REST, rich web app 엔 GraphQL, 내부엔 gRPC). 하이브리드가 정상; mono-style 이 드묾.

cwkPippa 의 선택, 재방문

cwkPippa 가 REST + SSE + WebSocket. gRPC 없음 (단일 service, typed-contract overhead 가치 있는 내부 mesh 없음). GraphQL 없음 (단일 web client, REST endpoint 가 필요한 모든 shape 커버). Operation 이 resource 아닌 RPC-flavored action endpoint (POST /api/council/{id}/finalize). Mix 가 의도적; 한 style 로 모든 거 시도가 엔지니어링 위 ideology.

Code

gRPC: typed service 정의 + 다언어 stub·protobuf
// gRPC service 정의 — users.proto
syntax = 'proto3';

package users.v1;

service UsersService {
  rpc ReadUser    (ReadUserRequest)   returns (User);
  rpc CreateUser  (CreateUserRequest) returns (User);
  rpc ListUsers   (ListUsersRequest)  returns (stream User);  // server streaming
  rpc Chat        (stream ChatMsg)    returns (stream ChatMsg);  // 양방향 streaming
}

message User {
  string id    = 1;
  string name  = 2;
  string email = 3;
}

message ReadUserRequest  { string id = 1; }
message CreateUserRequest { string name = 1; string email = 2; }
message ListUsersRequest { int32 limit = 1; }
message ChatMsg { string text = 1; }

// 어느 언어든 client 생성:
//   protoc --python_out=. --grpc_python_out=. users.proto
//   protoc --go_out=. --go-grpc_out=. users.proto
//   protoc --ts_out=. users.proto
// 같은 계약, 모든 언어; HTTP/2 multiplexed; bidi streaming 내장.
GraphQL: typed schema + client-chosen query shape·graphql
# GraphQL query — client 가 shape 선택
query GetUserWithOrders($userId: ID!) {
  user(id: $userId) {
    name
    email
    orders(limit: 3, status: ACTIVE) {
      id
      total
      items {
        name
        price
      }
    }
  }
}

# Server 가 각 필드 resolve; client 가 요청한 거 정확히 받음.
# Mobile 이 더 작은 query 보냄; web admin 이 더 풍부한 거. 같은 endpoint.

# Schema (server-defined)
type User {
  id: ID!
  name: String!
  email: String
  orders(limit: Int = 10, status: OrderStatus): [Order!]!
}

type Order {
  id: ID!
  total: Float!
  items: [Item!]!
}
RPC-over-HTTP: rich JSON payload 가진 operation-named URL·python
# RPC-over-HTTP — rich JSON 가진 action 에 POST
# 이게 정직히 OpenAI 의 Chat Completions API
import httpx

resp = httpx.post(
    'https://api.openai.com/v1/chat/completions',
    headers={'Authorization': 'Bearer sk-...'},
    json={
        'model': 'gpt-4o',
        'messages': [{'role': 'user', 'content': 'Hi'}],
        'temperature': 0.7,
        'stream': True,
    },
)
# /v1/chat/completions 가 OPERATION (이 prompt 완료), resource 아님.
# URL 이 verb-named; body 가 procedure call. RPC-over-HTTP.
# 정직한 framing: 'API.' 부정직한 framing: 'REST API.'

External links

Exercise

일의 한 기능이나 service 골라 (혹은 발명). 설계 중심 셋 걸어: (1) REST 로 어떻게 만들, (2) GraphQL 로, (3) gRPC/RPC 로. 각각에 구체 ONE 승리와 구체 ONE 비용 나열. 그 다음 선택에 commit 하고 이 트래픽 shape 가 왜 이 style 가 다른 것보다 더 맞는지 두 문장으로 articulate. 보너스: 공개 gRPC .proto 파일 (Envoy, Kubernetes, Etcd 다 자기 발행) 읽고 typed 계약이 손으로 쓴 OpenAPI 와 어떻게 다르게 느껴지는지 느껴.
Hint
REST 가 cacheability + browser-friendliness + intermediary 지원 에서 이김. GraphQL 이 client 유연성 + over-fetch 예방 에서 이김. gRPC 가 typed 계약 + HTTP/2 multiplexing + streaming 에서 이김. 비용 뒤집힘: client 가 다양하면 REST 가 endpoint 확산; GraphQL 이 캐시 어려움; gRPC 가 브라우저 도구에 opaque. Articulation 연습 — 두 문장으로 선택 변호 — 가 규율.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.