JSON 포맷을 μ‚¬μš©ν•˜λŠ” 원격 ν”„λ‘œμ‹œμ € 호좜(RPC) ν”„λ‘œν† μ½œμ΄λ‹€. ν΄λΌμ΄μ–ΈνŠΈκ°€# μ„œλ²„μ˜ λ©”μ„œλ“œλ₯Ό 마치 둜컬 ν•¨μˆ˜μ²˜λŸΌ ν˜ΈμΆœν•  수 있게 ν•΄μ£ΌλŠ” κ²½λŸ‰ 톡신 κ·œμ•½μ΄λ‹€.

핡심 νŠΉμ§•: Transport-independent (전솑 계측 독립적) - HTTP, TCP, WebSocket λ“± μ–΄λ–€ 전솑 ν”„λ‘œν† μ½œ μœ„μ—μ„œλ„ λ™μž‘ κ°€λŠ₯ν•˜λ‹€.

ν•΄λ‹Ή κ°œλ…μ΄ ν•„μš”ν•œ 이유

  • 원격 ν•¨μˆ˜ 호좜 ν‘œμ€€ν™”: μ„œλ‘œ λ‹€λ₯Έ μ‹œμŠ€ν…œ κ°„ ν•¨μˆ˜ ν˜ΈμΆœμ„ μΌκ΄€λœ λ°©μ‹μœΌλ‘œ 처리
  • κ²½λŸ‰ ν”„λ‘œν† μ½œ: XML-RPC에 λΉ„ν•΄ κ°„κ²°ν•œ JSON 포맷으둜 μ˜€λ²„ν—€λ“œ κ°μ†Œ
  • 비동기 처리 지원: μ—¬λŸ¬ μš”μ²­μ„ λ™μ‹œμ— 보내고 λΉ„λ™κΈ°λ‘œ 응닡 λ°›κΈ° κ°€λŠ₯
  • μ•Œλ¦Ό κΈ°λŠ₯: 응닡이 ν•„μš” μ—†λŠ” 일방ν–₯ 톡신 지원 (Notification)

AS-IS

전톡적인 REST APIλŠ” λ¦¬μ†ŒμŠ€ 쀑심이며, 각 λ™μž‘λ§ˆλ‹€ URL μ—”λ“œν¬μΈνŠΈκ°€ ν•„μš”ν•˜λ‹€.

// REST API 방식: μ—”λ“œν¬μΈνŠΈλ§ˆλ‹€ 별도 URL
POST /api/users/create
POST /api/users/update
POST /api/users/delete
GET  /api/users/list
GET  /api/products/calculate-price

문제점:

  • URL 관리 λ³΅μž‘λ„ 증가
  • ν•¨μˆ˜ 호좜 μ˜λ―Έκ°€ URL에 뢄산됨
  • λ©”μ„œλ“œ 이름과 URL λ§€ν•‘ 뢈일치 κ°€λŠ₯

TO-BE

JSON-RPCλŠ” 단일 μ—”λ“œν¬μΈνŠΈμ—μ„œ λ©”μ„œλ“œ μ΄λ¦„μœΌλ‘œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œλ‹€.

// JSON-RPC 방식: 단일 μ—”λ“œν¬μΈνŠΈμ—μ„œ λ©”μ„œλ“œ ꡬ뢄
POST /api/rpc
 
// λͺ¨λ“  호좜이 λ™μΌν•œ ꡬ쑰
{"jsonrpc": "2.0", "method": "user.create", "params": {...}, "id": 1}
{"jsonrpc": "2.0", "method": "user.update", "params": {...}, "id": 2}
{"jsonrpc": "2.0", "method": "user.delete", "params": {...}, "id": 3}
{"jsonrpc": "2.0", "method": "product.calculatePrice", "params": {...}, "id": 4}

κ°œμ„ μ :

  • 단일 μ—”λ“œν¬μΈνŠΈλ‘œ λͺ¨λ“  ν•¨μˆ˜ 호좜 처리
  • λ©”μ„œλ“œ 이름이 λͺ…μ‹œμ μœΌλ‘œ λ“œλŸ¬λ‚¨
  • μΌκ΄€λœ μš”μ²­/응닡 ꡬ쑰

JSON-RPC λ©”μ‹œμ§€ 3κ°€μ§€ νƒ€μž…

1. Request (μš”μ²­)

ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„μ˜ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œ μ‚¬μš©ν•œλ‹€.

{
  "jsonrpc": "2.0",
  "method": "subtract",
  "params": {"minuend": 42, "subtrahend": 23},
  "id": 3
}

ν•„μˆ˜ ν•„λ“œ:

  • method: ν˜ΈμΆœν•  λ©”μ„œλ“œ 이름 (λ¬Έμžμ—΄)
  • id: μš”μ²­-응닡 맀칭을 μœ„ν•œ μ‹λ³„μž (λ¬Έμžμ—΄ λ˜λŠ” μ •μˆ˜)

선택 ν•„λ“œ:

  • params: νŒŒλΌλ―Έν„° (객체 λ˜λŠ” λ°°μ—΄, μƒλž΅ κ°€λŠ₯)
  • jsonrpc: ν”„λ‘œν† μ½œ 버전 (2.0μ—μ„œ ν•„μˆ˜)

2. Response (응닡)

μ„œλ²„κ°€ μš”μ²­μ— λŒ€ν•œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

{
  "jsonrpc": "2.0",
  "result": 19,
  "id": 3
}

성곡 μ‹œ:

  • result: λ©”μ„œλ“œ μ‹€ν–‰ κ²°κ³Ό
  • id: μ›λž˜ μš”μ²­μ˜ id

μ‹€νŒ¨ μ‹œ:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32600,
    "message": "Invalid Request"
  },
  "id": null
}
  • error: 였λ₯˜ 객체 (code, message ν•„μˆ˜)
  • id: μ›λž˜ μš”μ²­μ˜ id (νŒŒμ‹± μ‹€νŒ¨ μ‹œ null)

3. Notification (μ•Œλ¦Ό)

응닡이 ν•„μš” μ—†λŠ” 일방ν–₯ λ©”μ‹œμ§€λ‹€. id ν•„λ“œλ₯Ό μƒλž΅ν•˜λ©΄ μ„œλ²„λŠ” μ‘λ‹΅ν•˜μ§€ μ•ŠλŠ”λ‹€.

{
  "jsonrpc": "2.0",
  "method": "update",
  "params": [1, 2, 3, 4, 5]
}

μš©λ„:

  • 둜그 전솑
  • 이벀트 μ•Œλ¦Ό
  • λ°±κ·ΈλΌμš΄λ“œ μž‘μ—… 트리거

JSON-RPC 톡신 흐름

sequenceDiagram
    autonumber
    participant Client as Client
    participant Server as Server

    Note over Client,Server: 1. 일반 μš”μ²­/응닡
    Client->>Server: Request<br/>{"method": "add", "params": [2, 3], "id": 1}
    Server->>Server: add(2, 3) μ‹€ν–‰
    Server->>Client: Response<br/>{"result": 5, "id": 1}

    Note over Client,Server: 2. μ•Œλ¦Ό (응닡 μ—†μŒ)
    Client->>Server: Notification<br/>{"method": "log", "params": ["info"]}
    Note over Server: log μ‹€ν–‰, 응닡 μ—†μŒ

    Note over Client,Server: 3. 배치 μš”μ²­ (비동기)
    Client->>Server: Batch Request<br/>[{"method": "sum", "id": 1},<br/>{"method": "multiply", "id": 2}]
    Server->>Server: 병렬 처리
    Server->>Client: Batch Response<br/>[{"result": 10, "id": 1},<br/>{"result": 20, "id": 2}]

핡심 흐름:

  1. ν΄λΌμ΄μ–ΈνŠΈκ°€ id와 ν•¨κ»˜ μš”μ²­ 전솑
  2. μ„œλ²„κ°€ λ©”μ„œλ“œ μ‹€ν–‰ ν›„ λ™μΌν•œ id둜 응닡 λ°˜ν™˜
  3. μ•Œλ¦Όμ€ id 없이 μ „μ†‘λ˜μ–΄ 응닡 μ—†μŒ
  4. 배치 μš”μ²­μ€ μ—¬λŸ¬ ν˜ΈμΆœμ„ λ°°μ—΄λ‘œ λ¬Άμ–΄ 전솑 κ°€λŠ₯

버전별 μ£Όμš” 차이점

Version 1.0 (2005)

// Request
{"method": "echo", "params": ["Hello"], "id": 1}
 
// Response
{"result": "Hello", "error": null, "id": 1}

νŠΉμ§•:

  • error ν•„λ“œκ°€ 항상 쑴재 (null κ°€λŠ₯)
  • jsonrpc 버전 ν•„λ“œ μ—†μŒ

Version 2.0 (2010, ν˜„μž¬ ν‘œμ€€)

// Request
{"jsonrpc": "2.0", "method": "echo", "params": ["Hello"], "id": 1}
 
// Response (성곡)
{"jsonrpc": "2.0", "result": "Hello", "id": 1}
 
// Response (μ‹€νŒ¨)
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid"}, "id": 1}

κ°œμ„ μ :

  • jsonrpc: "2.0" ν•„λ“œλ‘œ 버전 λͺ…μ‹œ
  • result와 error 쀑 ν•˜λ‚˜λ§Œ 쑴재 (배타적)
  • Named parameters 지원 (paramsλ₯Ό 객체둜 전달)
  • 배치 μš”μ²­ 곡식 지원

사전 μ •μ˜λœ 였λ₯˜ μ½”λ“œ

CodeMessage의미
-32700Parse errorJSON νŒŒμ‹± μ‹€νŒ¨
-32600Invalid Requestμš”μ²­ ꡬ쑰가 잘λͺ»λ¨
-32601Method not foundλ©”μ„œλ“œκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŒ
-32602Invalid paramsνŒŒλΌλ―Έν„°κ°€ 잘λͺ»λ¨
-32603Internal errorμ„œλ²„ λ‚΄λΆ€ 였λ₯˜

μ„œλ²„λ³„ 였λ₯˜: -32000 ~ -32099 λ²”μœ„λŠ” μ„œλ²„κ°€ 자유둭게 μ •μ˜ κ°€λŠ₯

Transport-Independent νŠΉμ„±

JSON-RPCλŠ” 전솑 계측에 독립적이닀. λ‹€μ–‘ν•œ ν”„λ‘œν† μ½œ μœ„μ—μ„œ λ™μž‘ν•œλ‹€.

graph TB
    subgraph "JSON-RPC Protocol Layer"
        JSONRPC[JSON-RPC<br/>λ©”μ‹œμ§€ ꡬ쑰]
    end

    subgraph "Transport Layer (선택 κ°€λŠ₯)"
        HTTP[HTTP/HTTPS]
        WS[WebSocket]
        TCP[TCP Socket]
        IPC[IPC/Unix Socket]
    end

    JSONRPC --> HTTP
    JSONRPC --> WS
    JSONRPC --> TCP
    JSONRPC --> IPC

    HTTP --> Network[λ„€νŠΈμ›Œν¬ 전솑]
    WS --> Network
    TCP --> Network
    IPC --> Local[둜컬 ν”„λ‘œμ„ΈμŠ€]

μ˜ˆμ‹œ:

  • HTTP: μ›Ή API둜 μ‚¬μš© (κ°€μž₯ 일반적)
  • WebSocket: μ‹€μ‹œκ°„ μ–‘λ°©ν–₯ 톡신
  • TCP: κ³ μ„±λŠ₯ λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€ κ°„ 톡신
  • IPC: 둜컬 ν”„λ‘œμ„ΈμŠ€ κ°„ 톡신

JSON-RPC vs REST API

νŠΉμ„±JSON-RPCREST API
쀑심 κ°œλ…λ©”μ„œλ“œ(ν•¨μˆ˜)λ¦¬μ†ŒμŠ€
μ—”λ“œν¬μΈνŠΈλ‹¨μΌ URLλ¦¬μ†ŒμŠ€λ³„ URL
HTTP λ©”μ„œλ“œμ£Όλ‘œ POSTGET, POST, PUT, DELETE
캐싱어렀움HTTP 캐싱 ν™œμš© κ°€λŠ₯
배치 μš”μ²­κΈ°λ³Έ μ§€μ›λΉ„ν‘œμ€€
μ•Œλ¦ΌκΈ°λ³Έ μ§€μ›μ—†μŒ

JSON-RPCλ₯Ό μ„ νƒν•˜λŠ” 경우:

  • RPC μŠ€νƒ€μΌμ˜ APIκ°€ μžμ—°μŠ€λŸ¬μš΄ 경우
  • 배치 μš”μ²­μ΄ ν•„μš”ν•œ 경우
  • λ‚΄λΆ€ λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€ 톡신
  • LSP 같은 ν”„λ‘œν† μ½œ 계측이 ν•„μš”ν•œ 경우

μ°Έκ³  λ¬Έμ„œ