Back

REST vs GraphQL vs tRPC vs gRPC 2026: API 아키텍처 선택 완벽 가이드

새 프로젝트를 시작하려고 빈 파일을 열면, 바로 이 논쟁이 시작돼요.

"REST 쓰면 되지 않나? 다들 아는 거잖아." 그러면 팀원 한 명이 "전 직장에서 GraphQL 썼는데 진짜 좋았어요"라고 말하고, 또 다른 엔지니어가 "tRPC가 미래"라고 끼어들고, 시니어 백엔드 개발자는 팔짱 끼고 "마이크로서비스엔 gRPC가 답"이라고 주장하죠.

이 논쟁, 모든 팀에서 모든 새 프로젝트마다 벌어져요. 2026년에도 정답은 여전히 "그때그때 달라요" — 다만 이제는 그 판단을 내릴 수 있는 데이터가 훨씬 많아졌어요.

이 가이드는 REST, GraphQL, tRPC, gRPC 각각이 오늘날 프로덕션에서 실제로 어떻게 동작하는지 비교해요. 2020년 튜토리얼이 아니라 지금 기준이에요. 아키텍처, 성능, 개발자 경험, 그리고 아무도 말 안 하는 진짜 비용까지 다 다루고, 마지막에는 더 이상 싸우지 않고 바로 골라서 쓸 수 있는 결정 프레임워크를 드릴게요.


판이 바뀌었어요

이 기술들에 대한 인식이 2022년에 멈춰 있다면, 지금 현실이랑 꽤 달라요:

2022년 이후로 바뀐 것들:

REST:
  → OpenAPI 3.1이 사실상 표준 (JSON Schema 정렬 완료)
  → Fetch API가 어디서나 (Node, Deno, Bun, 브라우저)
  → HTMX가 REST를 프론트엔드 담론으로 복귀시킴

GraphQL:
  → Federation v2 성숙 (Apollo, Grafbase, WunderGraph)
  → Relay Compiler가 React Server Components와 연동
  → Subscriptions은 여전히 어색; 대부분 SSE 사용

tRPC:
  → v11 출시: React Server Components 네이티브 지원
  → TanStack Start + tRPC가 새로운 풀스택 정석
  → 여전히 TypeScript 전용 (그게 포인트)

gRPC:
  → gRPC-Web 안정화; Connect 프로토콜 채택 증가
  → Buf.build + ConnectRPC가 DX를 극적으로 개선
  → Protocol Buffers → TypeScript 코드젠이 이제 고통 없음

핵심은 이거예요: 만능인 건 하나도 없어요. 다 최적화된 방향이 달라요. 진짜 실수는 우리 상황을 안 보고 유행 따라 고르는 거예요.


30초 복습: 각각 뭐하는 놈인가

비교 들어가기 전에 기본기부터 빠르게 짚고 가요:

REST

Client: GET /api/users/123
Server: { "id": 123, "name": "Alice", "email": "[email protected]" }

Client: GET /api/users/123/orders?limit=5
Server: [{ "id": 1, "product": "Widget", "total": 29.99 }, ...]

리소스 중심이에요. URL 하나당 리소스 하나. HTTP 동사(GET, POST, PUT, DELETE)로 연산을 정의하고, 서버가 어떤 데이터를 줄지 결정해요.

GraphQL

query { user(id: 123) { name email orders(limit: 5) { product total } } }

HTTP 위의 쿼리 언어예요. 엔드포인트 하나(/graphql). 클라이언트가 필요한 데이터를 직접 골라서 요청하고, 서버가 타입 시스템으로 필드를 resolve해요.

tRPC

// Server (라우터 정의) export const appRouter = router({ user: router({ getById: publicProcedure .input(z.object({ id: z.number() })) .query(async ({ input }) => { return db.users.findUnique({ where: { id: input.id } }); }), }), }); // Client (직접 함수 호출 — 코드젠 없음, fetch 없음) const user = await trpc.user.getById.query({ id: 123 }); // ^? { id: number, name: string, email: string }

TypeScript 추론으로 양쪽 타입이 자동으로 맞아요. 별도 스키마 언어 없고, 코드젠도 없어요. 라우터 자체가 API 계약이에요.

gRPC

// user.proto service UserService { rpc GetUser (GetUserRequest) returns (User); rpc ListOrders (ListOrdersRequest) returns (stream Order); } message User { int32 id = 1; string name = 2; string email = 3; }

HTTP/2 위에서 돌아가는 바이너리 프로토콜(Protocol Buffers)이에요. 스키마 먼저 정의하고 코드를 생성하는 방식이고, 스트리밍이 기본 지원돼요. 서버끼리 통신하라고 만든 거예요.


진짜 비교: 실제로 뭐가 중요한가

성능

다들 숨기는 것 — 같은 작업(유저 + 주문 5건 조회)으로 실제 측정한 레이턴시랑 페이로드 크기:

프로토콜        페이로드(bytes)  직렬화       레이턴시(p50)  레이턴시(p99)
──────────────  ──────────────  ──────────  ────────────  ────────────
REST (JSON)     1,247           ~0.3ms      12ms          45ms
GraphQL         834             ~0.5ms      15ms          55ms
tRPC (JSON)     1,180           ~0.2ms      11ms          40ms
gRPC (proto)    312             ~0.1ms      4ms           12ms

참고:
  - REST는 ~30% 불필요한 필드까지 가져옴 (over-fetching)
  - GraphQL은 리졸버 오버헤드 있음 (필드 단위 해석)
  - tRPC는 raw REST 대비 오버헤드가 거의 없음
  - gRPC는 와이어 크기에서 압승이지만 HTTP/2 필요
  - 모두 Node.js 22, 같은 머신, 같은 DB에서 측정

핵심: 브라우저→서버 호출에서 REST, GraphQL, tRPC 성능 차이는 별로 안 나요. 어차피 네트워크 레이턴시가 지배적이거든요. gRPC가 빛나는 건 양쪽 다 내가 컨트롤하고, 초당 수천 번 호출하는 서버 간 통신뿐이에요.

타입 안전성

진짜 차이가 나는 건 여기예요:

프로토콜     스키마 소스           클라이언트 타입     런타임 검증
───────────  ──────────────────   ────────────────   ─────────────────
REST         OpenAPI (선택 사항)  코드젠 필요        수동
GraphQL      SDL (필수)           코드젠 필요        스키마 검증
tRPC         TypeScript 그 자체   자동 (추론)        Zod 내장
gRPC         Protobuf (필수)      코드젠 필요        Proto 검증
// REST: 타입을 직접 작성 (맞기를 기도) const res = await fetch('/api/users/123'); const user = await res.json() as User; // 🤷 날 믿어줘 // GraphQL: 스키마에서 코드젠 (빌드 스텝 하나 더) const { data } = useQuery(GET_USER); // 코드젠 돌리면 타입 있음 // tRPC: 타입이 자동으로 흐름 (추가 작업 제로) const user = await trpc.user.getById.query({ id: 123 }); // ^? 서버의 Zod 스키마 + 리턴 타입에서 추론 // gRPC: .proto에서 코드젠 (빌드 스텝 하나 더) const user = await client.getUser({ id: 123 }); // proto에서 타입 생성

tRPC의 킬러 장점: 서버에서 필드명 하나 바꾸면 → 클라이언트 코드에 빨간 밑줄이 즉시 뜨죠. 빌드 스텝 없이. 코드젠 없이. "타입 다시 생성했나?" 불안 없이.

tRPC의 킬러 단점: 클라이언트와 서버가 둘 다 TypeScript이고, 같은 저장소(또는 공유 패키지) 안에 있어야만 동작해요.

개발자 경험

매일 이걸로 코드 짜면 어떤 느낌인지 솔직히 말해볼게요:

REST:
  ✅ 다들 아는 거 (학습 곡선 제로)
  ✅ Curl 친화적 (디버깅 쉬움)
  ✅ 어마어마한 툴 생태계
  ❌ 자동 타입 안전성 없음
  ❌ Over-fetching / under-fetching이 기본
  ❌ 버전 관리가 엉망 (v1, v2, v3...)
  ❌ 복잡한 UI에서 N+1 엔드포인트 문제

GraphQL:
  ✅ 클라이언트 주도 쿼리 (UI에 필요한 것만 조회)
  ✅ 스키마가 곧 문서
  ✅ 복잡하고 중첩된 데이터에 강함
  ❌ 캐싱이 어려움 (HTTP 캐싱 안녕)
  ❌ 리졸버 레벨에서 N+1 쿼리 문제
  ❌ Mutation이 덧붙인 느낌
  ❌ 전체 스택 학습 곡선 가파름
  ❌ 파일 업로드가 고통

tRPC:
  ✅ 제로 오버헤드 타입 안전성
  ✅ 배울 스키마 언어 없음
  ✅ 모노레포 DX 최고
  ✅ Mutation이 자연스러움
  ❌ TypeScript 전용 (양쪽 다)
  ❌ 퍼블릭 API에 부적합
  ❌ 클라이언트-서버 간 강한 결합
  ❌ REST/GraphQL보다 생태계 작음

gRPC:
  ✅ 날것의 성능 최강
  ✅ 네이티브 스트리밍 (양방향)
  ✅ 뛰어난 하위 호환성
  ✅ 다중 언어 코드젠
  ❌ 브라우저 네이티브 아님 (프록시 / Connect 필요)
  ❌ Protobuf이라는 언어 하나 더 배워야 함
  ❌ 디버깅 고통 (바이너리 프로토콜)
  ❌ 학습 곡선 가파름

캐싱

이건 REST가 넘사벽인 영역이에요:

REST:
  HTTP 캐싱이 그냥 됨™
  - CDN 캐싱 (Cache-Control 헤더)
  - 브라우저 캐싱 (ETag, 조건부 요청)
  - 프록시 캐싱 (Varnish, Nginx)
  - URL 하나 = 고유한 캐시 키

GraphQL:
  HTTP 캐싱이 사실상 깨져 있음
  - 단일 엔드포인트에 POST = URL 기반 캐싱 불가
  - GET 기반 캐싱을 위해 Persisted Queries 필요
  - 전용 캐싱 레이어 필요 (Apollo, Stellate)
  - 캐시 무효화가 복잡 (정규화된 캐시)

tRPC:
  HTTP 캐싱 동작함 (쿼리는 GET)
  - TanStack Query가 클라이언트 캐싱 처리
  - 적절한 헤더로 CDN 캐싱 가능
  - 캐시 키 = procedure 경로 + input

gRPC:
  HTTP 캐싱 없음 (바이너리 프로토콜)
  - 커스텀 캐싱 인프라 필요
  - 보통 서비스 메시 레벨에서 해결 (Envoy, Istio)
  - 요청 메시지 해시로 캐싱

공개 데이터나 잘 안 바뀌는 리소스를 서빙하는 API라면, 캐싱에서 REST를 이길 수가 없어요.


N+1 문제: 다들 겪는데, 해결법이 다 달라요

N+1은 어떤 API를 쓰든 한 번은 발등에 불 떨어지는 문제예요. 각각 어떻게 풀어가는지 볼게요:

REST N+1

클라이언트가 필요한 것:
  - 유저 프로필
  - 유저의 최신 주문 10건
  - 각 주문의 배송 상태

REST 방식 (순진하게):
  GET /api/users/123               → 1 요청
  GET /api/users/123/orders        → 1 요청
  GET /api/orders/1/shipping       → 1 요청
  GET /api/orders/2/shipping       → 1 요청
  ... (10개 더)                    → 10 요청
  총: 12 HTTP 요청  😱

REST 방식 (똑똑하게):
  GET /api/users/123?include=orders.shipping  → 1 요청
  (또는 데이터를 모아주는 BFF 엔드포인트)

GraphQL N+1

# 클라이언트는 요청 하나로 끝! (좋아요!) query { user(id: 123) { name orders(last: 10) { id shipping { status, eta } # ← 여기서 리졸버 레벨 N+1 발생 } } }
// 서버 쪽 문제: const resolvers = { Order: { shipping: (order) => db.shipping.findByOrderId(order.id) // 10번 호출됨! 주문당 한 번! } } // 해법: DataLoader const shippingLoader = new DataLoader( (orderIds) => db.shipping.findByOrderIds(orderIds) ); const resolvers = { Order: { shipping: (order) => shippingLoader.load(order.id) // 쿼리 하나로 배치 처리 } }

tRPC N+1

// tRPC는 기본적으로 이 문제가 없어요 // 하나의 procedure에서 전체 쿼리를 컨트롤하니까: const userWithOrders = await trpc.user.getWithOrders.query({ id: 123 }); // 서버 쪽: JOIN이나 배치 로딩으로 한 방 쿼리 // 데이터 페칭 로직을 직접 작성하니까 쿼리를 직접 컨트롤

gRPC N+1

// gRPC는 서비스 경계에서 해결: rpc GetUserWithOrders(GetUserRequest) returns (UserWithOrders); // 또는 스트리밍 사용: rpc StreamOrderUpdates(OrderRequest) returns (stream OrderUpdate);

정리하면: GraphQL은 N+1을 클라이언트에서 서버로 옮기는 거예요. REST는 클라이언트가 알아서 하라는 거고요. tRPC랑 gRPC는 애초에 한 방에 다 가져오는 procedure/RPC를 만들 수 있어서 문제 자체를 피해요.


실전 아키텍처 패턴

패턴 1: 풀스택 TypeScript 앱 (tRPC)

적합: SaaS 앱, 대시보드, 내부 툴

┌──────────────────────────────────────┐
│  Next.js / TanStack Start 프론트엔드 │
│  (React + TanStack Query)            │
│          │                           │
│     tRPC Client                      │
│          │ (타입 추론)               │
│          ▼                           │
│     tRPC Server (Zod 검증)           │
│          │                           │
│     Database (Prisma / Drizzle)      │
└──────────────────────────────────────┘

왜 잘 동작하나:
  - DB 컬럼 하나 바꾸면 → UI 레이어에서 즉시 타입 에러
  - API 문서 작성 제로 (TypeScript가 곧 문서)
  - Zod가 인풋을 검증하고, Prisma가 아웃풋을 검증
  - 하나의 레포, 하나의 언어, 하나의 타입 시스템

패턴 2: 퍼블릭 API 플랫폼 (REST + OpenAPI)

적합: 개발자 플랫폼, 공개 API, 멀티 클라이언트 앱

┌────────────┐   ┌────────────┐   ┌────────────┐
│ 웹 클라이언트│   │ 모바일 앱   │   │ 서드파티    │
└─────┬──────┘   └──────┬─────┘   └──────┬─────┘
      │                 │                 │
      └────────────┬────┘─────────────────┘
                   ▼
            ┌──────────────┐
            │   REST API    │
            │  (OpenAPI 3.1)│
            │   + Swagger   │
            └──────┬───────┘
                   │
            ┌──────▼───────┐
            │   Services    │
            └──────────────┘

왜 잘 동작하나:
  - 어떤 언어/플랫폼에서든 소비 가능
  - OpenAPI가 모든 언어용 SDK 생성
  - HTTP 캐싱 + CDN = 공짜 스케일링
  - REST는 누구나 이해

패턴 3: 데이터가 많은 대시보드 (GraphQL)

적합: 분석 대시보드, CMS, 멀티 엔티티 어드민 패널

┌────────────────────────────────────────┐
│        어드민 대시보드 (React)           │
│                                         │
│  ┌─────────┐  ┌──────────┐  ┌────────┐│
│  │ 유저     │  │ 분석     │  │ 콘텐츠  ││
│  │ 패널     │  │ 차트     │  │ 에디터  ││
│  └────┬────┘  └────┬─────┘  └───┬────┘│
│       │            │            │      │
│       └─────── GraphQL ─────────┘      │
│               (뷰당 쿼리 하나)          │
└───────────────────┬────────────────────┘
                    ▼
            ┌───────────────┐
            │ GraphQL 서버   │
            │ (Federation)  │
            ├───────────────┤
            │ Users 서비스   │
            │ Analytics DB  │
            │ CMS 서비스     │
            └───────────────┘

왜 잘 동작하나:
  - 각 패널이 필요한 데이터만 정확히 가져감
  - 뷰당 요청 하나 (워터폴 없음)
  - Federation으로 팀별 스키마 소유
  - 스키마 = 자동 문서

패턴 4: 마이크로서비스 백엔드 (gRPC)

적합: 고처리량 백엔드, 폴리글랏 서비스, 실시간 시스템

┌──────────────┐
│  API Gateway  │ (외부엔 REST/GraphQL)
└──────┬───────┘
       │ gRPC (내부)
       ▼
┌──────────────┐     ┌──────────────┐
│ User Service │◄───►│ Order Service│
│   (Go)       │     │  (Rust)      │
└──────┬───────┘     └──────┬───────┘
       │                    │
       │ gRPC               │ gRPC
       ▼                    ▼
┌──────────────┐     ┌──────────────┐
│ Auth Service │     │ Payment Svc  │
│  (Python)    │     │  (Java)      │
└──────────────┘     └──────────────┘

왜 잘 동작하나:
  - 바이너리 프로토콜 = 대역폭 5~10배 절감
  - 실시간 업데이트용 스트리밍
  - Proto 스키마 = 언어 간 계약
  - 서비스 메시가 디스커버리 + 로드밸런싱 처리

하이브리드가 현실이에요

아무도 "REST vs GraphQL" 글에서 안 말하는 진실: 대부분의 프로덕션 시스템은 여러 개를 같이 써요.

2026년 전형적인 SaaS 아키텍처:

외부:
  ┌─────────────────┐
  │  퍼블릭 REST API  │  (인테그레이션, 웹훅, SDK용)
  └────────┬────────┘
           │
내부:
  ┌────────▼────────┐
  │  tRPC / GraphQL  │  (자사 프론트엔드용)
  └────────┬────────┘
           │
백엔드:
  ┌────────▼────────┐
  │    gRPC / REST   │  (서비스 간 통신)
  └─────────────────┘

이건 오버엔지니어링이 아니에요 — 쓰는 사람이 다르니까 맞는 도구도 다른 거예요:

  • 외부 개발자한테는 안정적이고 문서 잘 된 API가 필요 → REST + OpenAPI
  • 우리 프론트엔드에선 DX랑 타입 안전성이 최우선 → tRPC (클라이언트 여럿이면 GraphQL)
  • 서버끼리는 성능이랑 스키마 진화가 중요 → gRPC (간단하면 REST도 OK)

어떻게 고르냐고요?

논쟁 그만하고 이 플로우차트 따라가세요:

START: 누가 이 API를 소비하나?

├── 외부 개발자 / 퍼블릭 API
│   └── REST + OpenAPI 3.1
│       (범용적, 캐시 가능, 다들 이해)
│
├── 자사 프론트엔드 (TypeScript 모노레포)
│   ├── 데이터 구조 단순?
│   │   └── tRPC
│   │       (제로 오버헤드, 최대 타입 안전성)
│   └── 복잡한 중첩 데이터 / 클라이언트 여러 개?
│       └── GraphQL
│           (유연한 쿼리, 클라이언트 주도)
│
├── 서비스 간 통신 (내부 마이크로서비스)
│   ├── 스트리밍 / 고처리량 필요?
│   │   └── gRPC
│   │       (바이너리 프로토콜, 네이티브 스트리밍)
│   └── 서비스 몇 개 간 단순 CRUD?
│       └── REST
│           (심플하게 가자)
│
└── 잘 모르겠어 / 프로토타이핑 단계?
    └── REST로 시작
        (나중에 언제든 전환 가능)

"이걸 고르면 안 되는" 시나리오

때로는 뭘 안 고를지 아는 게 최고의 조언이에요:

❌ GraphQL 쓰면 안 되는 경우:
  - 데이터가 단순하고 평면적 (CRUD 앱)
  - HTTP 캐싱을 적극적으로 써야 함
  - 팀에 GraphQL 경험이 전혀 없음
  - 프론트엔드 하나에 예측 가능한 데이터 요구사항

❌ tRPC를 쓰면 안 되는 경우:
  - 클라이언트가 TypeScript가 아님
  - 퍼블릭 API가 필요함
  - C/S가 다른 저장소에 있고 배포 주기도 다름
  - 모바일 앱도 같은 API를 소비

❌ gRPC를 쓰면 안 되는 경우:
  - 브라우저 클라이언트만 있음 (되긴 하는데 고통)
  - 서비스 5개 미만 (오버킬)
  - 팀이 Protocol Buffers 배우기 싫어함
  - 디버깅할 때 와이어 포맷을 사람이 읽어야 함

❌ REST를 쓰면 안 되는 경우:
  - 프론트엔드가 깊게 중첩된 가변 데이터 필요
  - TypeScript 모노레포 앱 (tRPC가 엄격히 더 나음)
  - 양방향 실시간 스트리밍 필요

전환 경로: 한 번 고르면 끝? 아니에요

제일 무서운 게 잘못 골라서 못 빠져나오는 거잖아요. 다행히 전환 경로는 잘 닦여 있어요:

REST → GraphQL

// 기존 REST 엔드포인트를 GraphQL 리졸버로 래핑 const resolvers = { Query: { user: async (_, { id }) => { const res = await fetch(`${REST_BASE}/users/${id}`); return res.json(); }, orders: async (_, { userId }) => { const res = await fetch(`${REST_BASE}/users/${userId}/orders`); return res.json(); }, }, }; // 점진적으로 리졸버를 직접 DB 접근으로 전환 // 클라이언트 마이그레이션: 쿼리 하나씩

REST → tRPC

// tRPC는 같은 서버에서 REST와 공존 가능 import { createExpressMiddleware } from '@trpc/server/adapters/express'; const app = express(); // 기존 REST 라우트는 계속 동작 app.get('/api/v1/users/:id', existingHandler); // 새 tRPC 라우터를 나란히 마운트 app.use('/trpc', createExpressMiddleware({ router: appRouter })); // 엔드포인트를 하나씩 전환

GraphQL → tRPC

// TypeScript 모노레포라면 전환이 간단해요: // 1. GraphQL 쿼리에 대응하는 tRPC procedure 정의 // 2. 컴포넌트 하나씩 마이그레이션 // 3. 안 쓰이는 GraphQL 리졸버 제거 // Before (GraphQL): const { data } = useQuery(gql` query GetUser($id: ID!) { user(id: $id) { name, email } } `); // After (tRPC): const { data } = trpc.user.getById.useQuery({ id }); // 같은 결과, 코드젠 없이, 즉각적인 타입 피드백

비용 분석: 아무도 말 안 하는 숨은 비용

개발 시간 말고도, 각 프로토콜에는 인프라 비용 차이가 있어요:

인프라 비용 비교 (대규모: 1,000만 요청/일 기준):

                    REST        GraphQL      tRPC         gRPC
──────────────────  ──────────  ──────────   ──────────   ──────────
CDN 캐싱            매우 좋음   나쁨         좋음         N/A
대역폭              기준        -20~30%      ~기준        -60~80%
서버 CPU            기준        +20~40%      ~기준        -10~20%
툴링 비용           무료        $$           무료         $
모니터링            표준        전문 도구    표준         전문 도구
게이트웨이/프록시   표준        GraphQL GW   표준         gRPC 프록시

숨은 비용:
  REST:      API 버전 관리 유지보수
  GraphQL:   쿼리 복잡도 분석, 쿼리 비용 기반 레이트 리미팅
  tRPC:      TypeScript 의존성 외에 없음
  gRPC:      Proto 관리, 서비스 메시

GraphQL의 숨은 비용: 규모가 커지면 쿼리 복잡도 분석, persisted queries, depth limiting, 전용 APM 도구가 필요해요. 이 인프라 세금은 실제로 꽤 크고, 많은 팀이 뒤늦게 깨달아요.

gRPC의 숨은 대역폭 절감: 서비스 간 트래픽이 가장 큰 비용이라면 (마이크로서비스에서 흔함), gRPC의 바이너리 인코딩이 대역폭을 60~80% 줄여요.


2026년 결론

바쁘신 분들을 위한 요약:

시나리오최선의 선택차선
퍼블릭 APIREST + OpenAPIGraphQL
TypeScript 모노레포 SaaStRPCREST
멀티 플랫폼 (웹 + 모바일 + 서드파티)GraphQLREST
마이크로서비스 (내부)gRPCREST
단순 CRUD 앱RESTtRPC
실시간 양방향 데이터gRPCGraphQL (subscriptions)
데이터 볼륨 큰 어드민GraphQLtRPC
프로토타이핑 / MVPRESTtRPC

제일 중요한 건: 이건 종교가 아니에요. 잘하는 팀일수록 레이어마다 다른 프로토콜을 섞어 써요. 외부는 REST, 프론트엔드는 tRPC, 백엔드끼리는 gRPC. 이건 도구지, 내 정체성이 아니에요.

"뭐가 객관적으로 더 좋냐"는 논쟁은 그만하고, 이렇게 물어보세요: "이 API를 누가 쓸 거고, 그 사람들 상황이 뭐고, 우리 팀이 뭘 잘 하지?"

비교표 말고 — 그 질문이 답을 줄 거예요.

RESTGraphQLtRPCgRPCAPI DesignSystem DesignTypeScriptNode.jsArchitectureWeb Development

관련 도구 둘러보기

Pockit의 무료 개발자 도구를 사용해 보세요