or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

binary-io.mdcli-tools.mdcode-generation.mdindex.mdproto-loading.mdreflection.mdrpc-services.mdserialization.md

rpc-services.mddocs/

0

# RPC Services

1

2

Built-in RPC service framework for implementing and consuming protobuf-based services with support for both traditional and streaming RPC patterns.

3

4

## Capabilities

5

6

### Service Definition

7

8

Service reflection and definition management for RPC services.

9

10

```javascript { .api }

11

class Service extends Namespace {

12

/**

13

* Constructs a new service

14

* @param name - Service name

15

* @param options - Service options

16

*/

17

constructor(name: string, options?: object);

18

19

/**

20

* Creates service from JSON descriptor

21

* @param name - Service name

22

* @param json - JSON service descriptor

23

* @returns Service instance

24

*/

25

static fromJSON(name: string, json: object): Service;

26

27

/**

28

* Service methods by name

29

*/

30

methods: { [name: string]: Method };

31

32

/**

33

* Array of all methods

34

*/

35

methodsArray: Method[];

36

37

/**

38

* Creates RPC service instance

39

* @param rpcImpl - RPC implementation function

40

* @param requestDelimited - Whether requests are length-delimited

41

* @param responseDelimited - Whether responses are length-delimited

42

* @returns RPC service instance

43

*/

44

create(rpcImpl: RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): rpc.Service;

45

46

/**

47

* Adds method to service

48

* @param method - Method to add

49

* @returns This service

50

*/

51

add(method: Method): Service;

52

53

/**

54

* Removes method from service

55

* @param method - Method to remove

56

* @returns This service

57

*/

58

remove(method: Method): Service;

59

}

60

```

61

62

**Usage Examples:**

63

64

```javascript

65

const protobuf = require("protobufjs");

66

67

protobuf.load("service.proto", function(err, root) {

68

const UserService = root.lookupService("UserService");

69

70

console.log("Service methods:");

71

UserService.methodsArray.forEach(method => {

72

console.log(`${method.name}: ${method.requestType} -> ${method.responseType}`);

73

});

74

75

// Create service instance

76

const service = UserService.create(rpcImplementation);

77

});

78

```

79

80

### Method Definition

81

82

RPC method reflection and metadata.

83

84

```javascript { .api }

85

class Method extends ReflectionObject {

86

/**

87

* Constructs a new method

88

* @param name - Method name

89

* @param type - Method type (typically "rpc")

90

* @param requestType - Request message type name

91

* @param responseType - Response message type name

92

* @param requestStream - Whether request is streaming

93

* @param responseStream - Whether response is streaming

94

* @param options - Method options

95

*/

96

constructor(name: string, type: string, requestType: string, responseType: string,

97

requestStream?: boolean, responseStream?: boolean, options?: object);

98

99

/**

100

* Method type (typically "rpc")

101

*/

102

type: string;

103

104

/**

105

* Request message type name

106

*/

107

requestType: string;

108

109

/**

110

* Response message type name

111

*/

112

responseType: string;

113

114

/**

115

* Whether request is streaming

116

*/

117

requestStream: boolean;

118

119

/**

120

* Whether response is streaming

121

*/

122

responseStream: boolean;

123

124

/**

125

* Resolved request message type

126

*/

127

resolvedRequestType: Type | null;

128

129

/**

130

* Resolved response message type

131

*/

132

resolvedResponseType: Type | null;

133

}

134

```

135

136

**Usage Examples:**

137

138

```javascript

139

// Inspect method details

140

const getUserMethod = UserService.methods["getUser"];

141

console.log("Method:", getUserMethod.name);

142

console.log("Request type:", getUserMethod.requestType);

143

console.log("Response type:", getUserMethod.responseType);

144

console.log("Streaming:", {

145

request: getUserMethod.requestStream,

146

response: getUserMethod.responseStream

147

});

148

149

// Access resolved types

150

const RequestType = getUserMethod.resolvedRequestType;

151

const ResponseType = getUserMethod.resolvedResponseType;

152

```

153

154

### RPC Implementation Interface

155

156

Interface for implementing RPC transport and execution.

157

158

```javascript { .api }

159

/**

160

* RPC implementation function

161

* @param method - Method being called

162

* @param requestData - Encoded request data

163

* @param callback - Callback for response

164

*/

165

interface RPCImpl {

166

(method: Method, requestData: Uint8Array, callback: RPCImplCallback): void;

167

}

168

169

/**

170

* RPC implementation callback

171

* @param error - Error if call failed, null on success

172

* @param response - Encoded response data if successful

173

*/

174

interface RPCImplCallback {

175

(error: Error | null, response?: Uint8Array): void;

176

}

177

```

178

179

**Usage Examples:**

180

181

```javascript

182

// HTTP-based RPC implementation

183

function httpRpcImpl(method, requestData, callback) {

184

const xhr = new XMLHttpRequest();

185

xhr.open("POST", `/rpc/${method.name}`);

186

xhr.responseType = "arraybuffer";

187

188

xhr.onload = function() {

189

if (xhr.status === 200) {

190

const responseBuffer = new Uint8Array(xhr.response);

191

callback(null, responseBuffer);

192

} else {

193

callback(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`));

194

}

195

};

196

197

xhr.onerror = function() {

198

callback(new Error("Network error"));

199

};

200

201

xhr.send(requestData);

202

}

203

204

// WebSocket-based RPC implementation

205

function websocketRpcImpl(method, requestData, callback) {

206

const message = {

207

method: method.name,

208

data: Array.from(requestData)

209

};

210

211

websocket.send(JSON.stringify(message));

212

213

// Store callback for response matching

214

pendingCalls[generateId()] = callback;

215

}

216

217

// Node.js HTTP client implementation

218

function nodeHttpRpcImpl(method, requestData, callback) {

219

const options = {

220

hostname: 'localhost',

221

port: 8080,

222

path: `/rpc/${method.name}`,

223

method: 'POST',

224

headers: {

225

'Content-Type': 'application/x-protobuf',

226

'Content-Length': requestData.length

227

}

228

};

229

230

const req = require('http').request(options, (res) => {

231

const chunks = [];

232

res.on('data', chunk => chunks.push(chunk));

233

res.on('end', () => {

234

const responseBuffer = Buffer.concat(chunks);

235

callback(null, new Uint8Array(responseBuffer));

236

});

237

});

238

239

req.on('error', callback);

240

req.write(requestData);

241

req.end();

242

}

243

```

244

245

### Service Instance

246

247

Runtime service instance for making RPC calls.

248

249

```javascript { .api }

250

namespace rpc {

251

class Service {

252

/**

253

* RPC implementation

254

*/

255

rpcImpl: RPCImpl;

256

257

/**

258

* Whether requests are length-delimited

259

*/

260

requestDelimited: boolean;

261

262

/**

263

* Whether responses are length-delimited

264

*/

265

responseDelimited: boolean;

266

267

/**

268

* Creates service method wrapper

269

* @param method - Method definition

270

* @param requestCtor - Request message constructor

271

* @param responseCtor - Response message constructor

272

* @returns Method wrapper function

273

*/

274

rpcCall<TRequest, TResponse>(

275

method: Method,

276

requestCtor: Constructor<TRequest>,

277

responseCtor: Constructor<TResponse>

278

): (request: TRequest, callback: ServiceMethodCallback<TResponse>) => void;

279

}

280

}

281

282

/**

283

* Service method callback

284

* @param error - Error if call failed

285

* @param response - Response message if successful

286

*/

287

interface ServiceMethodCallback<TResponse> {

288

(error: Error | null, response?: TResponse): void;

289

}

290

```

291

292

**Usage Examples:**

293

294

```javascript

295

// Create and use service instance

296

const userService = UserService.create(httpRpcImpl);

297

298

// Make RPC calls

299

const getUserRequest = { userId: 123 };

300

userService.getUser(getUserRequest, function(err, response) {

301

if (err) {

302

console.error("RPC error:", err);

303

return;

304

}

305

306

console.log("User:", response.name, response.email);

307

});

308

309

// Promise-based wrapper

310

function promisifyService(service) {

311

const promisified = {};

312

313

Object.keys(service).forEach(methodName => {

314

if (typeof service[methodName] === 'function') {

315

promisified[methodName] = function(request) {

316

return new Promise((resolve, reject) => {

317

service[methodName](request, (err, response) => {

318

if (err) reject(err);

319

else resolve(response);

320

});

321

});

322

};

323

}

324

});

325

326

return promisified;

327

}

328

329

// Use promisified service

330

const promisedUserService = promisifyService(userService);

331

promisedUserService.getUser({ userId: 123 })

332

.then(user => console.log("User:", user))

333

.catch(err => console.error("Error:", err));

334

```

335

336

### Streaming RPC Support

337

338

Support for streaming RPC patterns (client streaming, server streaming, bidirectional streaming).

339

340

```javascript { .api }

341

interface StreamingPatterns {

342

/**

343

* Unary RPC (single request, single response)

344

*/

345

unary: {

346

requestStream: false;

347

responseStream: false;

348

};

349

350

/**

351

* Client streaming (multiple requests, single response)

352

*/

353

clientStreaming: {

354

requestStream: true;

355

responseStream: false;

356

};

357

358

/**

359

* Server streaming (single request, multiple responses)

360

*/

361

serverStreaming: {

362

requestStream: false;

363

responseStream: true;

364

};

365

366

/**

367

* Bidirectional streaming (multiple requests, multiple responses)

368

*/

369

bidirectionalStreaming: {

370

requestStream: true;

371

responseStream: true;

372

};

373

}

374

```

375

376

**Usage Examples:**

377

378

```javascript

379

// Server streaming implementation

380

function serverStreamingRpcImpl(method, requestData, callback) {

381

if (method.responseStream) {

382

// Set up streaming response handler

383

const stream = new EventEmitter();

384

385

stream.on('data', (responseData) => {

386

// Each response chunk

387

callback(null, responseData);

388

});

389

390

stream.on('end', () => {

391

// Signal end of stream

392

callback(null, null);

393

});

394

395

stream.on('error', (err) => {

396

callback(err);

397

});

398

399

// Initiate streaming call

400

initiateStreamingCall(method.name, requestData, stream);

401

} else {

402

// Regular unary call

403

regularRpcImpl(method, requestData, callback);

404

}

405

}

406

407

// Client streaming implementation

408

function clientStreamingService(method, requestStream) {

409

return new Promise((resolve, reject) => {

410

const chunks = [];

411

412

requestStream.on('data', (requestData) => {

413

chunks.push(requestData);

414

});

415

416

requestStream.on('end', () => {

417

// Combine all request chunks

418

const combinedRequest = Buffer.concat(chunks);

419

420

// Make single RPC call with combined data

421

rpcImpl(method, combinedRequest, (err, response) => {

422

if (err) reject(err);

423

else resolve(response);

424

});

425

});

426

});

427

}

428

```

429

430

### Service Registration

431

432

Utilities for registering and discovering RPC services.

433

434

```javascript { .api }

435

interface ServiceRegistry {

436

/**

437

* Registers service implementation

438

* @param serviceName - Service name

439

* @param implementation - Service implementation

440

*/

441

register(serviceName: string, implementation: object): void;

442

443

/**

444

* Gets registered service

445

* @param serviceName - Service name

446

* @returns Service implementation

447

*/

448

get(serviceName: string): object | null;

449

450

/**

451

* Lists all registered services

452

* @returns Array of service names

453

*/

454

list(): string[];

455

}

456

```

457

458

**Usage Examples:**

459

460

```javascript

461

// Service implementation

462

const userServiceImpl = {

463

getUser: function(request, callback) {

464

// Implementation logic

465

const user = database.findUser(request.userId);

466

const response = UserResponse.create({

467

id: user.id,

468

name: user.name,

469

email: user.email

470

});

471

callback(null, response);

472

},

473

474

createUser: function(request, callback) {

475

// Implementation logic

476

const newUser = database.createUser(request);

477

const response = UserResponse.create(newUser);

478

callback(null, response);

479

}

480

};

481

482

// Register service

483

serviceRegistry.register("UserService", userServiceImpl);

484

485

// Generic RPC handler

486

function handleRpcCall(serviceName, methodName, requestData, callback) {

487

const service = serviceRegistry.get(serviceName);

488

if (!service) {

489

return callback(new Error(`Service not found: ${serviceName}`));

490

}

491

492

const method = service[methodName];

493

if (!method) {

494

return callback(new Error(`Method not found: ${methodName}`));

495

}

496

497

// Decode request and call method

498

const ServiceDef = root.lookupService(serviceName);

499

const MethodDef = ServiceDef.methods[methodName];

500

const RequestType = MethodDef.resolvedRequestType;

501

502

const request = RequestType.decode(requestData);

503

method(request, callback);

504

}

505

```

506

507

### Error Handling

508

509

Comprehensive error handling for RPC operations.

510

511

```javascript { .api }

512

interface RPCError extends Error {

513

name: string; // Error type

514

message: string; // Error description

515

code?: number; // Error code

516

details?: any; // Additional error details

517

method?: string; // Method that failed

518

}

519

520

interface RPCErrorCodes {

521

OK: 0;

522

CANCELLED: 1;

523

UNKNOWN: 2;

524

INVALID_ARGUMENT: 3;

525

DEADLINE_EXCEEDED: 4;

526

NOT_FOUND: 5;

527

ALREADY_EXISTS: 6;

528

PERMISSION_DENIED: 7;

529

UNAUTHENTICATED: 16;

530

RESOURCE_EXHAUSTED: 8;

531

FAILED_PRECONDITION: 9;

532

ABORTED: 10;

533

OUT_OF_RANGE: 11;

534

UNIMPLEMENTED: 12;

535

INTERNAL: 13;

536

UNAVAILABLE: 14;

537

DATA_LOSS: 15;

538

}

539

```

540

541

**Usage Examples:**

542

543

```javascript

544

// Enhanced error handling in RPC implementation

545

function robustRpcImpl(method, requestData, callback) {

546

try {

547

// Validate method

548

if (!method) {

549

const error = new Error("Method not specified");

550

error.code = RPCErrorCodes.INVALID_ARGUMENT;

551

return callback(error);

552

}

553

554

// Make RPC call with timeout

555

const timeoutId = setTimeout(() => {

556

const error = new Error("RPC call timed out");

557

error.code = RPCErrorCodes.DEADLINE_EXCEEDED;

558

error.method = method.name;

559

callback(error);

560

}, 30000);

561

562

makeRpcCall(method, requestData, (err, response) => {

563

clearTimeout(timeoutId);

564

565

if (err) {

566

// Enhance error with context

567

err.method = method.name;

568

err.code = err.code || RPCErrorCodes.UNKNOWN;

569

}

570

571

callback(err, response);

572

});

573

574

} catch (err) {

575

err.code = RPCErrorCodes.INTERNAL;

576

err.method = method.name;

577

callback(err);

578

}

579

}

580

581

// Error handling in service calls

582

userService.getUser(request, function(err, response) {

583

if (err) {

584

switch (err.code) {

585

case RPCErrorCodes.NOT_FOUND:

586

console.log("User not found");

587

break;

588

case RPCErrorCodes.PERMISSION_DENIED:

589

console.log("Access denied");

590

break;

591

case RPCErrorCodes.UNAVAILABLE:

592

console.log("Service unavailable, retrying...");

593

// Implement retry logic

594

break;

595

default:

596

console.error("RPC error:", err.message);

597

}

598

return;

599

}

600

601

// Success

602

console.log("User retrieved:", response);

603

});

604

```

605

606

## Types

607

608

```javascript { .api }

609

interface RPCImpl {

610

(method: Method, requestData: Uint8Array, callback: RPCImplCallback): void;

611

}

612

613

interface RPCImplCallback {

614

(error: Error | null, response?: Uint8Array): void;

615

}

616

617

interface ServiceMethodCallback<TResponse> {

618

(error: Error | null, response?: TResponse): void;

619

}

620

621

interface Constructor<T> extends Function {

622

new (...args: any[]): T;

623

}

624

```