The Apache Fory team is pleased to announce the 1.3.0 release. This release includes 8 PRs from 3 distinct contributors and continues to improve the cross-language runtime across supported languages. See the Install page to get the libraries for your platform.
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 --grpc
For 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=sync
In 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.0
Generate Dart models and the gRPC companion with:
foryc service.fdl --dart_out=./lib/generated --grpc
dart run build_runner build --delete-conflicting-outputs
For 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 {
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 https://github.com/apache/fory/pull/3768
- feat: limit remote schema metadata by @chaokunyang in https://github.com/apache/fory/pull/3770
- feat(compiler): add dart gRPC codegen by @yash-agarwa-l in https://github.com/apache/fory/pull/3723
Bug Fix
- fix(java): guard aligned varint unsafe read by @chaokunyang in https://github.com/apache/fory/pull/3772
- fix(java): cache accepted type checker classes by @chaokunyang in https://github.com/apache/fory/pull/3773
Other Improvements
- docs: refine gRPC support guides by @chaokunyang in https://github.com/apache/fory/pull/3767
- docs: add threat model + SECURITY.md/AGENTS.md discoverability by @potiuk in https://github.com/apache/fory/pull/3734
- chore(release): enforce OpenJDK 25 for JVM publishing by @chaokunyang in https://github.com/apache/fory/pull/3775
New Contributors
- @potiuk made their first contribution in https://github.com/apache/fory/pull/3734
Full Changelog: https://github.com/apache/fory/compare/v1.2.0...v1.3.0
