v1.3.0
Highlights
- Python gRPC code generation now defaults to the
grpc.aioAsyncIO API, while synchronousgrpciooutput remains available through--grpc-python-mode=sync. - Dart joins the generated gRPC service surface:
foryc --dart_out=... --grpcnow emitspackage:grpcclients, service bases, method descriptors, and Fory-backed payload serialization. - Compiler gRPC documentation was refined across languages, including clearer guidance for generated service dependencies and transport behavior.
- Runtime hardening continued with remote schema metadata limits and Java aligned-varint/type-checker fixes.
Python Async gRPC Mode
Python gRPC generation now targets AsyncIO by default. Generated companions use
grpc.aio: servicer bases expose async def methods, stubs are used with
grpc.aio.Channel instances, and streaming RPCs use async iterables. This keeps
the generated code aligned with modern Python async services while preserving
the same Fory-backed request and response encoding used by the existing gRPC
support.
Generate the default async companion with:
foryc service.fdl --python_out=./generated/python --grpcFor a simple unary service, the generated async server shape is:
import asyncio
import grpc.aio
import demo_greeter
import demo_greeter_grpc
class Greeter(demo_greeter_grpc.GreeterServicer):
async def say_hello(self, request, context):
return demo_greeter.HelloReply(reply=f"Hello, {request.name}")
async def serve():
server = grpc.aio.server()
demo_greeter_grpc.add_servicer(Greeter(), server)
server.add_insecure_port("[::]:50051")
await server.start()
await server.wait_for_termination()
asyncio.run(serve())Clients use a grpc.aio channel and await generated stub methods:
import grpc
import grpc.aio
import demo_greeter
import demo_greeter_grpc
credentials = grpc.ssl_channel_credentials()
async with grpc.aio.secure_channel("api.example.com:443", credentials) as channel:
stub = demo_greeter_grpc.GreeterStub(channel)
reply = await stub.say_hello(demo_greeter.HelloRequest(name="Fory"))Existing synchronous applications can still request sync companions explicitly:
foryc service.fdl --python_out=./generated/python --grpc --grpc-python-mode=syncIn sync mode the generated public names and <module>_grpc.py filename stay the
same, but applications use grpc.server(...), standard grpc.Channel
instances, and regular def servicer methods.
Dart gRPC Code Generation
Fory 1.3.0 adds Dart gRPC service generation for schemas with service
definitions. Service definitions can come from Fory IDL, protobuf IDL, or
FlatBuffers rpc_service definitions. The generated code uses normal
grpc-dart APIs for clients, service bases, method descriptors, call options,
deadlines, cancellations, metadata, and status codes, while each request and
response object is serialized with Fory instead of protobuf message bytes.
Add grpc and build_runner alongside the Fory package in the Dart
application:
dependencies:
fory: ^1.3.0
grpc: ^4.0.0
dev_dependencies:
build_runner: ^2.4.0Generate Dart models and the gRPC companion with:
foryc service.fdl --dart_out=./lib/generated --grpc
dart run build_runner build --delete-conflicting-outputsFor a demo.greeter package, the generator emits the model file, the
build_runner serializer part, and a <stem>_grpc.dart companion with
GreeterServiceBase and GreeterClient. The generated client and service base
install the schema's Fory module automatically on first use, so service
implementations do not need a separate manual registration step for the
generated message types.
A unary Dart server uses grpc-dart's Server and the generated service base:
import 'dart:io';
import 'package:grpc/grpc.dart';
import 'demo/greeter/greeter.dart';
import 'demo/greeter/greeter_grpc.dart';
class GreeterService extends GreeterServiceBase {
@override
Future<HelloReply> sayHello(ServiceCall call, HelloRequest request) async {
return HelloReply()..reply = 'Hello, ${request.name}';
}
}
Future<void> main() async {
final server = Server.create(services: [GreeterService()]);
await server.serve(address: InternetAddress.loopbackIPv4, port: 50051);
}Generated Dart clients use standard ClientChannel values and return the
grpc-dart call types:
import 'package:grpc/grpc.dart';
import 'demo/greeter/greeter.dart';
import 'demo/greeter/greeter_grpc.dart';
final channel = ClientChannel(
'localhost',
port: 50051,
options: const ChannelOptions(credentials: ChannelCredentials.insecure()),
);
final client = GreeterClient(channel);
final reply = await client.sayHello(HelloRequest()..name = 'Fory');
await channel.shutdown();Dart generation covers unary, server-streaming, client-streaming, and
bidirectional streaming RPC shapes following grpc-dart conventions.
Features
- feat(python): add async grpc mode for python by @chaokunyang in #3768
- feat: limit remote schema metadata by @chaokunyang in #3770
- feat(compiler): add dart gRPC codegen by @yash-agarwa-l in #3723
Bug Fix
- fix(java): guard aligned varint unsafe read by @chaokunyang in #3772
- fix(java): cache accepted type checker classes by @chaokunyang in #3773
Other Improvements
- docs: refine gRPC support guides by @chaokunyang in #3767
- docs: add threat model + SECURITY.md/AGENTS.md discoverability by @potiuk in #3734
- chore(release): enforce OpenJDK 25 for JVM publishing by @chaokunyang in #3775
New Contributors
Full Changelog: v1.2.0...v1.3.0