Home > Engineering > Infrastructure > bare-for-pear > avsc-rpc > Service Definition

avsc-rpc Service Definition

How protocols become services — the bridge from schema to executable boundary.


Service.forProtocol

The primary entry point. Takes an Avro protocol and returns a Service instance that can create clients and servers.

const { Service } = require('avsc-rpc')

const service = Service.forProtocol({
  protocol: 'ExecutionService',
  namespace: 'spl.mycelium.process.execute',
  messages: {
    exec: {
      request: [{ name: 'message', type: 'Message' }],
      response: 'Message'
    }
  },
  types: [
    // Type definitions used by messages
  ]
})

The protocol defines the contract. The service enforces it. Every message that crosses the boundary is validated against the protocol’s type definitions.

Options

Option Description
strictTypes Strict error type coercion

Protocol Structure

A protocol is an Avro protocol definition — types and messages scoped under a name and namespace.

{
  protocol: 'Name',           // service name
  namespace: 'spl.mycelium',  // Avro namespace
  types: [ ... ],             // shared type definitions
  messages: {
    methodName: {
      request: [ ... ],       // argument fields
      response: 'TypeName',   // return type
      errors: [ ... ],        // error types (optional)
      'one-way': false        // fire-and-forget (optional)
    }
  }
}

Messages

Each message in the protocol becomes a typed RPC method. The Message class holds the Avro types for request, response, and errors.

const msg = service.message('exec')
msg.name          // 'exec'
msg.requestType   // Avro RecordType for request args
msg.responseType  // Avro Type for response
msg.errorType     // Avro UnionType for errors
msg.oneWay        // boolean

Service Methods

Method Description
Service.forProtocol(ptcl, opts) Create service from protocol
Service.compatible(client, server) Check protocol compatibility
Service.isService(any) Type check
service.createClient(opts) Create RPC client
service.createServer(opts) Create RPC server
service.message(name) Get message by name
service.type(name) Get type by name
service.hash Protocol fingerprint
service.name Qualified service name
service.protocol Protocol schema object
service.types Frozen array of types
service.messages Frozen array of messages

Protocol Hash

The service hash is the MD5 fingerprint of the protocol’s canonical representation. Used during the RPC handshake — client and server compare hashes to determine if they share a protocol before exchanging messages.

service.hash  // Buffer — 16-byte MD5

If hashes match, the handshake succeeds immediately. If not, the server sends its protocol to the client for resolution. This is Avro’s native protocol negotiation — no external registry.

Compatibility Check

Service.compatible(clientService, serverService)
// true if client's protocol can communicate with server's

Uses Avro’s type resolution rules — the same mechanism as schema evolution. A client with fewer message types can communicate with a richer server.