Skip to main content
Version: 1.2.0

gRPC Support

Fory can generate Go gRPC service companions for schemas that define services. The generated code uses grpc-go for transport and a Fory-backed CodecV2 for request and response payloads.

Use this mode when every RPC peer is generated from the same Fory IDL, protobuf IDL, or FlatBuffers IDL and you want gRPC transport semantics with Fory payload encoding. Use standard protobuf gRPC code generation when clients or tools must consume protobuf message bytes directly.

Add Dependencies

Add grpc-go to your module. Fory Go packages do not add gRPC as a hard dependency.

go get google.golang.org/grpc

Your generated code also imports the Fory Go module:

go get github.com/apache/fory/go/fory

Define a Service

Service definitions can come from Fory IDL, protobuf IDL, or FlatBuffers rpc_service definitions. A Fory IDL service looks like this:

package demo.greeter;

message HelloRequest {
string name = 1;
}

message HelloReply {
string reply = 1;
}

service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}

Generate Go model and gRPC companion code with --grpc:

foryc service.fdl --go_out=./generated/go --grpc

For this schema, the Go generator emits:

FilePurpose
greeter/demo_greeter.goFory model types and registration helpers
greeter/demo_greeter_grpc.gogrpc-go client, server interfaces, and codec

Generated Go methods use exported PascalCase names such as SayHello. The underlying gRPC method path keeps the exact schema method name, so names such as sayHello or say_hello continue to route by their schema spelling.

Implement a Server

Implement the generated GreeterServer interface, create a grpc-go server with the generated Fory codec, and register the service.

package main

import (
"context"
"log"
"net"

"google.golang.org/grpc"

"example.com/app/generated/go/greeter"
)

type greeterService struct {
greeter.UnimplementedGreeterServer
}

func (greeterService) SayHello(
ctx context.Context,
request *greeter.HelloRequest,
) (*greeter.HelloReply, error) {
return &greeter.HelloReply{Reply: "Hello, " + request.Name}, nil
}

func main() {
listener, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatal(err)
}

server := grpc.NewServer(
grpc.ForceServerCodecV2(greeter.CodecV2{}),
)
greeter.RegisterGreeterServer(server, greeterService{})

if err := server.Serve(listener); err != nil {
log.Fatal(err)
}
}

grpc.ForceServerCodecV2(...) is required so the server decodes incoming frames with the generated Fory codec instead of the default protobuf codec.

Use the zero-value generated CodecV2{} for the service schema. The generated client methods force the same codec for outgoing calls.

Create a Client

The generated client constructor accepts a grpc-go connection. Generated client methods force the generated Fory codec for each call.

package main

import (
"context"
"fmt"
"log"
"time"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

"example.com/app/generated/go/greeter"
)

func main() {
conn, err := grpc.NewClient(
"localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatal(err)
}
defer conn.Close()

client := greeter.NewGreeterClient(conn)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

reply, err := client.SayHello(ctx, &greeter.HelloRequest{Name: "Fory"})
if err != nil {
log.Fatal(err)
}
fmt.Println(reply.Reply)
}

Streaming RPCs

Fory service definitions can use unary, server-streaming, client-streaming, and bidirectional streaming RPC shapes:

service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc LotsOfReplies (HelloRequest) returns (stream HelloReply);
rpc LotsOfGreetings (stream HelloRequest) returns (HelloReply);
rpc Chat (stream HelloRequest) returns (stream HelloReply);
}

Generated Go code follows grpc-go conventions:

  • Unary methods take context.Context, a request pointer, and return a response pointer plus error.
  • Server-streaming client methods return a generated stream client.
  • Client-streaming server methods receive a generated stream server.
  • Bidirectional streaming methods use generated stream client and server interfaces.
  • The generated codec is used for every message frame, including streaming frames.

Operations

The generated service companion only supplies Fory serialization. Operational behavior remains standard grpc-go behavior:

  • Deadlines and cancellations
  • TLS and credentials
  • Unary and stream interceptors
  • Status codes and metadata
  • Name resolution and load balancing
  • Connection lifecycle and backoff

Troubleshooting

Missing google.golang.org/grpc Packages

Add grpc-go to your module:

go get google.golang.org/grpc

grpc: error while marshaling

Confirm that both the client and server use the generated CodecV2{} and that the generated model file is compiled into the same package as the gRPC companion.

UNIMPLEMENTED

Confirm that the generated service was registered with RegisterGreeterServer(...), and that the client and server were generated from the same package, service, and method names.

Protobuf Clients Cannot Decode the Service

Fory gRPC companions do not use protobuf wire encoding for messages. Use a Fory-generated client for Fory-generated services, or provide a separate protobuf service endpoint for generic protobuf clients.