Skip to main content

Fory v1.3.0 Released

· 4 min read
Shawn Yang
Apache Fory PMC Chair

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.aio AsyncIO API, while synchronous grpcio output remains available through --grpc-python-mode=sync.
  • Dart joins the generated gRPC service surface: foryc --dart_out=... --grpc now emits package:grpc clients, 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

Bug Fix

Other Improvements

New Contributors

Full Changelog: https://github.com/apache/fory/compare/v1.2.0...v1.3.0