blob: c5d87e947db2f96f845f37678672fb6e3485dab3 [file] [view]
---
title: C++ gRPC
sidebar_position: 6
id: cpp
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
Fory can generate C++ gRPC service companions for schemas that define services.
The generated code uses gRPC C++ for transport and Fory for request and
response payload serialization. It requires gRPC C++ 1.39.0 or later.
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
With Bazel, use the Fory label that is visible from your workspace.
The example below is for a project that consumes Fory as an external module named `fory`:
```bazel
load("@rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "greeter_generated",
srcs = ["generated/demo_greeter.service.grpc.cc"],
hdrs = glob(["generated/*.h"]),
includes = ["generated"],
deps = [
"@fory//cpp/fory/serialization:fory_serialization",
"@grpc//:grpc++",
],
)
```
Inside the Fory repository, use `//cpp/fory/serialization:fory_serialization`
instead of `@fory//cpp/fory/serialization:fory_serialization`.
With CMake, make the Fory C++ target visible first. For an installed Fory
package, use `find_package(Fory CONFIG REQUIRED)`, then add the generated source
and link both libraries explicitly:
```cmake
find_package(Fory CONFIG REQUIRED)
find_package(gRPC 1.39.0 CONFIG REQUIRED)
add_library(greeter_generated
generated/demo_greeter.service.grpc.cc
)
target_compile_features(greeter_generated PUBLIC cxx_std_17)
target_include_directories(greeter_generated PUBLIC generated)
target_link_libraries(greeter_generated PUBLIC
fory::serialization
gRPC::grpc++
)
```
If your project brings Fory in with `FetchContent` or `add_subdirectory`, call
that before linking `fory::serialization`.
Use dependency versions that are compatible with the rest of your service
stack.
## Define a Service
Service definitions can come from Fory IDL, protobuf IDL, or FlatBuffers
`rpc_service` definitions. A Fory IDL service looks like this:
```protobuf
package demo.greeter;
message HelloRequest {
string name = 1;
}
message HelloReply {
string reply = 1;
}
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
```
Generate C++ model and gRPC companion code with `--grpc`:
```bash
foryc service.fdl --cpp_out=./generated/cpp --grpc
```
For this schema, the C++ generator emits:
| File | Purpose |
| ------------------------------ | -------------------------------------------------- |
| `demo_greeter.h` | Fory model types and registration helpers |
| `demo_greeter.service.h` | Synchronous service interface and path constants |
| `demo_greeter.service.grpc.h` | Synchronous client, server adapter, and Fory codec |
| `demo_greeter.service.grpc.cc` | Stub calls and server route implementations |
Include the generated gRPC header from application code and compile
`demo_greeter.service.grpc.cc` once in your build target. The codec is generated
directly in the gRPC header; there is no separate Fory gRPC support source file.
## Implement a Server
Implement the generated synchronous interface and register the generated server
adapter with a normal gRPC C++ server.
```cpp
#include "demo_greeter.service.grpc.h"
#include <memory>
#include <grpcpp/server_builder.h>
#include <grpcpp/security/server_credentials.h>
class MyGreeter final : public demo::greeter::service::Greeter {
public:
::grpc::Status SayHello(::grpc::ServerContext* context,
const ::demo::greeter::HelloRequest* request,
::demo::greeter::HelloReply* response) override {
(void)context;
response->set_reply("Hello, " + request->name());
return ::grpc::Status::OK;
}
};
MyGreeter implementation;
demo::greeter::service::grpc::GreeterServiceGrpc service(&implementation);
::grpc::ServerBuilder builder;
builder.AddListeningPort("0.0.0.0:50051", ::grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<::grpc::Server> server = builder.BuildAndStart();
server->Wait();
```
Generated request and response types are serialized by the generated service
code, so service implementations do not perform manual Fory registration.
## Create a Client
Use the generated synchronous client stub:
```cpp
#include "demo_greeter.service.grpc.h"
#include <iostream>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>
auto channel =
::grpc::CreateChannel("localhost:50051", ::grpc::InsecureChannelCredentials());
auto stub = demo::greeter::service::grpc::GreeterStub::NewStub(channel);
demo::greeter::HelloRequest request;
request.set_name("Fory");
demo::greeter::HelloReply response;
::grpc::ClientContext context;
::grpc::Status status = stub->SayHello(&context, request, &response);
if (status.ok()) {
std::cout << response.reply() << std::endl;
}
```
gRPC C++ still owns channel configuration, credentials, deadlines, metadata,
cancellation, retry policy, and transport lifecycle.
## Streaming RPCs
Fory service definitions can use unary, server-streaming, client-streaming, and
bidirectional streaming RPC shapes:
```protobuf
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 C++ code follows synchronous gRPC C++ conventions:
- Unary methods return `grpc::Status` and use request and response pointers.
- Server-streaming methods return `std::unique_ptr<grpc::ClientReader<U>>` on
clients and receive `grpc::ServerWriter<U>*` on servers.
- Client-streaming methods return `std::unique_ptr<grpc::ClientWriter<T>>` on
clients and receive `grpc::ServerReader<T>*` on servers.
- Bidirectional methods return
`std::unique_ptr<grpc::ClientReaderWriter<T, U>>` on clients and receive
`grpc::ServerReaderWriter<U, T>*` on servers.
- The generated codec is used for every message frame, including streaming
frames.
Use the generated method signatures as the source of truth for concrete request
and response types in your service implementation:
```cpp
::grpc::Status LotsOfReplies(
::grpc::ServerContext* context,
const ::demo::greeter::HelloRequest* request,
::grpc::ServerWriter<::demo::greeter::HelloReply>* writer) override {
(void)context;
::demo::greeter::HelloReply reply;
reply.set_reply("Hello, " + request->name());
writer->Write(reply);
reply.set_reply("Welcome, " + request->name());
writer->Write(reply);
return ::grpc::Status::OK;
}
```
Generated clients return standard gRPC C++ streaming helpers:
```cpp
demo::greeter::HelloRequest request;
request.set_name("Fory");
::grpc::ClientContext context;
auto reader = stub->LotsOfReplies(&context, request);
demo::greeter::HelloReply reply;
while (reader->Read(&reply)) {
std::cout << reply.reply() << std::endl;
}
::grpc::Status status = reader->Finish();
```
Complete client streams with `WritesDone()` and always call `Finish()` to obtain
the final status.
The generated descriptors preserve the exact IDL service and method names for
the gRPC path.
## gRPC Stack Behavior
The generated service companion only supplies Fory serialization and gRPC C++
bindings. Operational behavior remains standard gRPC C++ behavior:
- Deadlines and cancellations
- TLS and authentication
- Status codes and metadata
- Channel and server lifecycle
- Synchronous streaming backpressure
## Troubleshooting
### Missing gRPC C++ Headers or Symbols
Add the gRPC C++ dependency shown above to the target that compiles the
generated service files, and compile the generated `.service.grpc.cc` file
exactly once.
### `UNIMPLEMENTED`
Confirm that the generated server adapter was registered with
`ServerBuilder::RegisterService(...)`, 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.