JSON-RPC

JSON-RPC，是一個無狀態且輕量級的遠程過程調用（RPC）傳送協議，其傳遞內容透過 JSON 為主。相較於一般的 REST 透過網址（如 `GET /user`）呼叫遠端伺服器，JSON-RPC 直接在內容中定義了欲呼叫的函式名稱（如 `{"method": "getUser"}`），這也令開發者不會陷於該使用 PUT 或者 PATCH 的問題之中。本規範主要定義了一些數據結構及其相關的處理規則。它允許運行在基於 Socket、HTTP 等諸多不同消息傳輸環境的同一進程中。其使用 JSON（RFC 4627）作為數據格式。

## 約定

由於 JSON-RPC 使用 JSON，它具有與其相同的類型系統。JSON 可以表示四個基本類型（String、Numbers、Boolean 和 Null）和兩個結構化類型（Objects 和 Array）。任何時候文檔涉及 JSON 數據類型，第一個字母都必須大寫：Object、Array、String、Number、Boolean、Null。包括 True 和 False 也要大寫。

在客戶端與任何被匹配到的服務端之間交換的所有成員名字應是區分大小寫的。函數、方法、過程都可以認為是可以互換的。客戶端被定義為請求對象的來源及響應對象的處理程序。服務端被定義為響應對象的起源和請求對象的處理程序。

該規範的一種實現為可以輕而易舉的填補這兩個角色，即使是在同一時間，同一客戶端或其他不相同的客戶端。該規範不涉及複雜層。

## 兼容性

JSON-RPC 2.0 的請求對象和響應對象可能無法在較舊的 JSON-RPC 1.0 客戶端或服務端正常執行，然而我們可以很容易在兩個版本間區分出 2.0。因為 2.0 版本中必須夾帶一個命名為 jsonrpc 且值為 2.0 的欄位。而 1.0 版本是沒有此欄位的。大部分的 2.0 實現應該考慮嘗試兼容或者處理 1.0 的對象，即使不是對等的也應給其相關提示。

## 請求對象

發送一個請求對象至服務端代表一個 RPC 調用，一個請求對象包含下列成員：

- jsonrpc
- method
- params
- id

服務端必須回答相同的值如果包含在響應對象。這個成員用來兩個對象之間的關聯上下文。在請求對象中不建議使用 NULL 作為 id 值，因為該規範將使用空值認定為未知id的請求。另外，由於JSON-RPC 1.0 的通知使用了空值，這可能引起處理上的混淆。使用小數是不確定性的，因為許多十進位小數不能精準的表達為二進位小數。

### 通知

沒有包含 id 成員的請求對象為通知，作為通知的請求對象表明客戶端對相應的響應對象並不感興趣，本身也沒有響應對象需要返回給客戶端。服務端必須不回復一個通知，包含那些批量請求中的。

由於通知沒有返回的響應對象，所以通知不確定是否被定義。同樣，客戶端不會意識到任何錯誤（例如參數預設，內部錯誤）。

### 參數結構

RPC 調用如果存在參數則必須為基本類型或結構化類型的參數值，要麼為索引陣列，要麼為關聯數組對象。

- 索引：參數必須為陣列，並包含與服務端預期順序一致的參數值。
- 關聯名稱：參數必須為對象，並包含與服務端相匹配的參數成員名稱。沒有在預期中的成員名稱可能會引起錯誤。名稱必須完全匹配，包括方法的預期參數名以及大小寫。

## 響應對象

當發起一個 RPC 調用時，除通知之外，服務端都必須回復響應。響應表示為一個 JSON 對象，使用以下欄位：

- jsonrpc
- result
- error
- id

響應對象必須包含 result 或 error 欄位，但兩個欄位不能同時存在。

### 錯誤對象

當一個 RPC 調用遇到錯誤時，返回的響應對象必須包含錯誤成員參數，並且為帶有下列成員參數的對象：

- code
- message
- data

-32768 至 -32000 為保留的預定義錯誤代碼。在該範圍內的錯誤代碼不能被開發者自己定義，保留下列以供將來使用。錯誤代碼基本與 XML-RPC 建議 的一樣

錯誤碼｜訊息｜解釋

-32700｜Parse error - 語法解析錯誤｜服務端接收到無效的 JSON。該錯誤發送於伺服器嘗試解析 JSON 文本

-32600｜Invalid Request - 無效請求｜發送的 JSON 內容不是一個有效的請求對象。

-32601｜Method not found - 找不到方法｜該方法不存在或無效。

-32602｜Invalid params - 無效的參數｜無效的方法參數。

-32603｜Internal error - 內部錯誤｜JSON-RPC 內部錯誤。

-32000 to -32099｜Server error - 服務端錯誤｜預留用於自定義的伺服器錯誤。

除此之外剩餘的錯誤類型代碼可供應用程式作為自定義錯誤。

## 批量調用

當需要同時發送多個請求對象時，客戶端可以發送一個包含所有請求對象的陣列。

當批量調用的所有請求對象處理完成時，服務端則需要返回一個包含相對應的響應對象陣列。每個響應對象都應對應每個請求對象，除非是通知的請求對象。服務端可以並發的，以任意順序和任意寬度的並行性來處理這些批量調用。

這些相應的響應對象可以任意順序的包含在返回的陣列中，而客戶端應該是基於各個響應對象中的 id 成員來匹配對應的請求對象。

若批量調用的 RPC 操作本身非一個有效 JSON 或一個至少包含一個值的陣列，則服務端返回的將單單是一個響應對象而非陣列。若批量調用沒有需要返回的響應對象，則服務端不需要返回任何結果且必須不能返回一個空陣列給客戶端。

## 示例

在以下的例子裡，`-->`表示資料傳送至伺服器，`<--`表示資料傳送至使用者端。

帶索引陣列參數的rpc調用：

```javascript
 --> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}
 <-- {"jsonrpc": "2.0", "result": 19, "id": 1}
```

```javascript
 --> {"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2}
 <-- {"jsonrpc": "2.0", "result": -19, "id": 2}
```

帶關聯數組參數的 RPC 調用：

```javascript
 --> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}
 <-- {"jsonrpc": "2.0", "result": 19, "id": 3}

 --> {"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}
 <-- {"jsonrpc": "2.0", "result": 19, "id": 4}
```

通知：

```javascript
 --> {"jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]}
 --> {"jsonrpc": "2.0", "method": "foobar"}
```

包含無法找到的方法調用的 RPC 調用：

```javascript
 --> {"jsonrpc": "2.0", "method": "foobar", "id": "1"}
 <-- {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}
```

包含無效 JSON 的 RPC 調用：

```javascript
 --> {"jsonrpc": "2.0", "method": "foobar", "params": "bar", "baz]
 <-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}
```

包含無效請求對象的 RPC 調用：

```javascript
 --> {"jsonrpc": "2.0", "method": 1, "params": "bar"}
 <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
```

包含無效 JSON 的 RPC 批量調用：

```javascript
 --> [
         {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
         {"jsonrpc": "2.0", "method"
     ]
 <-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}
```

包含空陣列的 RPC 調用：

```javascript
 --> []
 <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
```

非空且無效的 RPC 批量調用：

```javascript
 --> [1]
 <-- [
     {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
     ]
```

無效的 RPC 批量調用：

```javascript
 --> [1,2,3]
 <-- [
     {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
     {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
     {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
     ]
```

RPC 批量調用：

```javascript
 --> [
     {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
     {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
     {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
     {"foo": "boo"},
     {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
     {"jsonrpc": "2.0", "method": "get_data", "id": "9"}
     ]
 <-- [
     {"jsonrpc": "2.0", "result": 7, "id": "1"},
     {"jsonrpc": "2.0", "result": 19, "id": "2"},
     {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
     {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
     {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
     ]
```

所有都為通知的 RPC 批量調用：

```javascript
 --> [
     {"jsonrpc": "2.0", "method": "notify_sum", "params": [1,2,4]},
     {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}
 ]
```

## 擴展

以 RPC 開頭的方法名預留作為系統擴展，且必須不能用於其他地方。每個系統擴展都應該有相關規範文檔，所有系統擴展都應是可選的。