0
# JSON-RPC Protocol
1
2
Complete JSON-RPC protocol utilities including request/response validation, batch operations, and comprehensive type guards. These functions provide robust JSON-RPC protocol handling for Web3 applications.
3
4
## Capabilities
5
6
### Response Validation
7
8
#### Error Response Handling
9
10
```typescript { .api }
11
/**
12
* Checks if response has valid RPC error code
13
* @param rpcError - JSON-RPC response with error
14
* @returns true if error code is valid
15
*/
16
function isResponseRpcError(rpcError: JsonRpcResponseWithError): boolean;
17
```
18
19
#### Response Type Guards
20
21
```typescript { .api }
22
/**
23
* Type guard for response with result
24
* @param response - JSON-RPC response to check
25
* @returns true if response contains result
26
*/
27
function isResponseWithResult<Result, Error>(
28
response: JsonRpcResponse<Result, Error>
29
): response is JsonRpcResponseWithResult<Result>;
30
31
/**
32
* Type guard for response with error
33
* @param response - JSON-RPC response to check
34
* @returns true if response contains error
35
*/
36
function isResponseWithError<Error, Result>(
37
response: JsonRpcResponse<Result, Error>
38
): response is JsonRpcResponseWithError<Error>;
39
40
/**
41
* Type guard for notification response
42
* @param response - Response to check
43
* @returns true if response is a notification
44
*/
45
function isResponseWithNotification<Result>(
46
response: JsonRpcNotification<Result> | JsonRpcSubscriptionResult
47
): response is JsonRpcNotification<Result>;
48
49
/**
50
* Type guard for subscription result
51
* @param response - Response to check
52
* @returns true if response is a subscription result
53
*/
54
function isSubscriptionResult<Result>(
55
response: JsonRpcNotification<Result> | JsonRpcSubscriptionResult
56
): response is JsonRpcSubscriptionResult;
57
```
58
59
#### Response Validation
60
61
```typescript { .api }
62
/**
63
* Validates JSON-RPC response format
64
* @param response - JSON-RPC response to validate
65
* @returns true if response is valid
66
*/
67
function validateResponse<Result, Error>(
68
response: JsonRpcResponse<Result, Error>
69
): boolean;
70
71
/**
72
* Checks if single/batch response is valid
73
* @param response - JSON-RPC response to check
74
* @returns true if response format is valid
75
*/
76
function isValidResponse<Result, Error>(
77
response: JsonRpcResponse<Result, Error>
78
): boolean;
79
```
80
81
### Batch Operations
82
83
#### Batch Type Guards
84
85
```typescript { .api }
86
/**
87
* Type guard for batch response
88
* @param response - Response to check
89
* @returns true if response is a batch response
90
*/
91
function isBatchResponse<Result, Error>(
92
response: JsonRpcResponse<Result, Error>
93
): response is JsonRpcBatchResponse<Result, Error>;
94
95
/**
96
* Type guard for batch request
97
* @param request - Request to check
98
* @returns true if request is a batch request
99
*/
100
function isBatchRequest(
101
request: JsonRpcBatchRequest | JsonRpcRequest<unknown> | JsonRpcOptionalRequest<unknown>
102
): request is JsonRpcBatchRequest;
103
```
104
105
#### Batch Payload Creation
106
107
```typescript { .api }
108
/**
109
* Converts requests to batch payload
110
* @param requests - Array of JSON-RPC requests
111
* @returns Batch request payload
112
*/
113
function toBatchPayload(requests: JsonRpcOptionalRequest<unknown>[]): JsonRpcBatchRequest;
114
```
115
116
### Request Management
117
118
#### Request ID Management
119
120
```typescript { .api }
121
/**
122
* Sets starting number for request IDs
123
* @param start - Starting ID number (undefined for auto-increment)
124
*/
125
function setRequestIdStart(start: number | undefined): void;
126
```
127
128
#### Payload Conversion
129
130
```typescript { .api }
131
/**
132
* Converts request to payload format
133
* @param request - JSON-RPC request (with optional ID)
134
* @returns Complete JSON-RPC payload with ID
135
*/
136
function toPayload<ParamType>(
137
request: JsonRpcOptionalRequest<ParamType>
138
): JsonRpcPayload<ParamType>;
139
```
140
141
## Usage Examples
142
143
### Request/Response Handling
144
145
```typescript
146
import {
147
toPayload, validateResponse, isResponseWithResult,
148
isResponseWithError, toBatchPayload
149
} from "web3-utils";
150
151
// Create single request payload
152
const request = {
153
method: "eth_getBalance",
154
params: ["0x742E4C5b469F50A4a8b399D4915C1fc93d15651B", "latest"]
155
};
156
157
const payload = toPayload(request);
158
// Result: { jsonrpc: "2.0", id: 1, method: "eth_getBalance", params: [...] }
159
160
// Validate and handle response
161
async function handleJsonRpcResponse(response: any) {
162
if (!validateResponse(response)) {
163
throw new Error('Invalid JSON-RPC response format');
164
}
165
166
if (isResponseWithResult(response)) {
167
console.log('Success result:', response.result);
168
return response.result;
169
} else if (isResponseWithError(response)) {
170
console.error('RPC Error:', response.error);
171
throw new Error(`RPC Error ${response.error.code}: ${response.error.message}`);
172
}
173
}
174
175
// Usage with fetch
176
const response = await fetch('/rpc', {
177
method: 'POST',
178
headers: { 'Content-Type': 'application/json' },
179
body: JSON.stringify(payload)
180
});
181
182
const jsonResponse = await response.json();
183
const result = await handleJsonRpcResponse(jsonResponse);
184
```
185
186
### Batch Operations
187
188
```typescript
189
import { toBatchPayload, isBatchResponse, isValidResponse } from "web3-utils";
190
191
// Create batch request
192
const requests = [
193
{ method: "eth_getBalance", params: ["0x742E4C5b469F50A4a8b399D4915C1fc93d15651B", "latest"] },
194
{ method: "eth_getTransactionCount", params: ["0x742E4C5b469F50A4a8b399D4915C1fc93d15651B", "latest"] },
195
{ method: "eth_gasPrice", params: [] }
196
];
197
198
const batchPayload = toBatchPayload(requests);
199
// Result: Array of payloads with unique IDs
200
201
// Handle batch response
202
async function handleBatchResponse(response: any) {
203
if (!isValidResponse(response)) {
204
throw new Error('Invalid response format');
205
}
206
207
if (isBatchResponse(response)) {
208
const results = [];
209
for (const singleResponse of response) {
210
if (isResponseWithResult(singleResponse)) {
211
results.push(singleResponse.result);
212
} else if (isResponseWithError(singleResponse)) {
213
results.push({ error: singleResponse.error });
214
}
215
}
216
return results;
217
} else {
218
// Single response
219
return [await handleJsonRpcResponse(response)];
220
}
221
}
222
223
// Usage
224
const batchResponse = await fetch('/rpc', {
225
method: 'POST',
226
headers: { 'Content-Type': 'application/json' },
227
body: JSON.stringify(batchPayload)
228
});
229
230
const jsonBatchResponse = await batchResponse.json();
231
const results = await handleBatchResponse(jsonBatchResponse);
232
```
233
234
### Subscription Handling
235
236
```typescript
237
import {
238
isResponseWithNotification, isSubscriptionResult
239
} from "web3-utils";
240
241
// WebSocket message handler
242
function handleWebSocketMessage(data: any) {
243
try {
244
const message = JSON.parse(data);
245
246
if (isResponseWithNotification(message)) {
247
console.log('Received notification:', message.method, message.params);
248
// Handle notification (e.g., new block, pending transaction)
249
} else if (isSubscriptionResult(message)) {
250
console.log('Subscription data:', message.params);
251
// Handle subscription data
252
} else {
253
// Regular JSON-RPC response
254
return handleJsonRpcResponse(message);
255
}
256
} catch (error) {
257
console.error('Failed to parse WebSocket message:', error);
258
}
259
}
260
```
261
262
### Request ID Management
263
264
```typescript
265
import { setRequestIdStart, toPayload } from "web3-utils";
266
267
// Set custom starting ID
268
setRequestIdStart(1000);
269
270
const request1 = toPayload({ method: "eth_blockNumber" });
271
console.log(request1.id); // 1000
272
273
const request2 = toPayload({ method: "eth_gasPrice" });
274
console.log(request2.id); // 1001
275
276
// Reset to auto-increment
277
setRequestIdStart(undefined);
278
279
const request3 = toPayload({ method: "eth_chainId" });
280
console.log(request3.id); // Auto-generated
281
```
282
283
### Error Handling Patterns
284
285
```typescript
286
import {
287
isResponseRpcError, isResponseWithError, validateResponse
288
} from "web3-utils";
289
290
async function robustJsonRpcCall(request: any) {
291
const payload = toPayload(request);
292
293
try {
294
const response = await fetch('/rpc', {
295
method: 'POST',
296
headers: { 'Content-Type': 'application/json' },
297
body: JSON.stringify(payload)
298
});
299
300
if (!response.ok) {
301
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
302
}
303
304
const jsonResponse = await response.json();
305
306
// Validate response format
307
if (!validateResponse(jsonResponse)) {
308
throw new Error('Invalid JSON-RPC response format');
309
}
310
311
// Check for RPC errors
312
if (isResponseWithError(jsonResponse)) {
313
if (isResponseRpcError(jsonResponse)) {
314
// Standard RPC error
315
const { code, message, data } = jsonResponse.error;
316
throw new Error(`RPC Error ${code}: ${message}${data ? ` (${JSON.stringify(data)})` : ''}`);
317
} else {
318
// Non-standard error
319
throw new Error(`Invalid RPC error: ${JSON.stringify(jsonResponse.error)}`);
320
}
321
}
322
323
if (isResponseWithResult(jsonResponse)) {
324
return jsonResponse.result;
325
}
326
327
throw new Error('Response contains neither result nor error');
328
329
} catch (error) {
330
console.error('JSON-RPC call failed:', error);
331
throw error;
332
}
333
}
334
```
335
336
## Types
337
338
The JSON-RPC utilities work with standard JSON-RPC type definitions:
339
340
```typescript { .api }
341
// Basic JSON-RPC structures
342
interface JsonRpcRequest<T> {
343
jsonrpc: "2.0";
344
id: number | string;
345
method: string;
346
params?: T;
347
}
348
349
interface JsonRpcOptionalRequest<T> {
350
method: string;
351
params?: T;
352
id?: number | string;
353
}
354
355
interface JsonRpcPayload<T> {
356
jsonrpc: "2.0";
357
id: number | string;
358
method: string;
359
params?: T;
360
}
361
362
interface JsonRpcResponseWithResult<T> {
363
jsonrpc: "2.0";
364
id: number | string;
365
result: T;
366
}
367
368
interface JsonRpcResponseWithError<T = any> {
369
jsonrpc: "2.0";
370
id: number | string;
371
error: {
372
code: number;
373
message: string;
374
data?: T;
375
};
376
}
377
378
type JsonRpcResponse<Result, Error> =
379
| JsonRpcResponseWithResult<Result>
380
| JsonRpcResponseWithError<Error>;
381
382
type JsonRpcBatchRequest = JsonRpcRequest<unknown>[];
383
type JsonRpcBatchResponse<Result, Error> = JsonRpcResponse<Result, Error>[];
384
```