Skip to Content

gRPC Realtime API

This guide is exclusively for the gRPC realtime interface.

Glossary

  • Inbound adapter — accepts external protocol calls and translates them into use-case calls.

Responsibility in context

  • Stack layer: adapter / realtime
  • Owns: framework-specific wiring for this technology
  • Used with: backend-template composition, persistence/SDK packages as needed, matching delivery guide
  • Not responsible for: domain rules, OpenAPI authoring, or browser offline storage

Why it exists

Framework choice should stay at the edge. This adapter keeps Express/Fastify/DB/realtime details replaceable.

What it is

Grpc Api adapter for Jumentix realtime interfaces — mounts application use-cases without leaking framework types into the domain.

Scope

  • Transport: gRPC
  • Server implementation: apps/backend-template/src/interface/gRPC/gRPCAPI.ts
  • Canonical proto contract: spec/asyncapi/async-api.proto
  • SDK client: sdk-clients/grpc/GrpcApiClient.ts
  • AsyncAPI source: spec/asyncapi/1.0.0.grpc.yml

Contract References

Service Contract

  • Service name: realtime.AsyncApiGateway
  • RPC methods:
    • Request(AsyncApiRequest) returns (AsyncApiResponse) (unary)
    • Exchange(stream AsyncApiRequest) returns (stream AsyncApiResponse) (bi-directional stream)

Runtime Flow

Deep Example: Unary Request

import { GrpcApiClient } from '../sdk-clients/grpc/GrpcApiClient';

const client = new GrpcApiClient('localhost:3002');

const response = await client.request({
  version: '1.0.0',
  operationId: 'createOrganization',
  authorization: 'Bearer <jwt>',
  input: {
    name: 'Acme Group',
    address: [],
    phone: [],
    email: []
  },
  metadata: {
    requestId: 'req-grpc-001',
    correlationId: 'corr-tenant-42'
  }
});

if (!response.ok) {
  console.error(response.error);
} else {
  console.log(response.result);
}

Deep Example: Native gRPC Bi-directional Stream

import grpc from '@grpc/grpc-js';
import protoLoader from '@grpc/proto-loader';
import { resolveGrpcProtoPath } from '@jumentix/sdk-grpc-client';

const protoPath = resolveGrpcProtoPath();
const packageDefinition = protoLoader.loadSync(protoPath, {
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
});
const grpcObject = grpc.loadPackageDefinition(packageDefinition) as any;
const client = new grpcObject.realtime.AsyncApiGateway(
  'localhost:3002',
  grpc.credentials.createInsecure()
);

const stream = client.exchange();

stream.on('data', (msg: any) => {
  const result = msg.resultJson ? JSON.parse(msg.resultJson) : null;
  console.log('stream response', msg.operationId, result, msg.errorMessage);
});

stream.on('error', (err: Error) => {
  console.error('stream error', err);
});

stream.write({
  version: '1.0.0',
  operationId: 'getAllOrganizations',
  authorization: 'Bearer <jwt>',
  inputJson: JSON.stringify({}),
  paramsJson: JSON.stringify({}),
  queryStringJson: JSON.stringify({ page: 1, size: 20 }),
  metadataJson: JSON.stringify({ requestId: 'stream-1' })
});

stream.end();

Payload Serialization Rules

  1. Transport fields inputJson, paramsJson, queryStringJson, metadataJson are JSON strings.
  2. Server maps transport payload into the internal async request envelope.
  3. resultJson in response must be parsed by client consumers.
  4. errorName and errorMessage provide normalized failure metadata.

Operational Guidance

  1. Keep one client per service host/port for connection reuse.
  2. Prefer unary RPC for independent operations.
  3. Use stream exchange for high-frequency operation batches.
  4. Enforce per-request correlation with metadataJson.requestId.

Junior checklist (“I can …”)

  • I know when to pick this adapter
  • I can start it from the documented script
  • I know the next guide/package to read

Next step

Return to Getting started or the matching delivery guide.