この記事の要点
- サービス間通信のためのフレームワーク gRPC の Swift 実装、gRPC Swift のメジャーアップデート gRPC Swift 2 が発表されました。Swift の async/await を中心とするモダンな並行処理に対応し、より使いやすく表現力の高い API を備えています。
- 旧バージョンは async/await 登場前に開発され、SwiftNIO のイベント駆動型の並行処理モデルに基づいていたため学習コストが高い面がありました。gRPC Swift 2 は現在の Swift を前提に再設計されています。
- サービス定義(
.protoファイル)からサーバー・クライアントのコードを生成でき、Apple プラットフォームと Linux の両方で動作します。HTTP/2 transport やインプロセス transport などを差し替えられる柔軟な構成で、クライアント側のロードバランシングや自動リトライ、認証・ロギング・メトリクスを差し込める interceptor 層なども備えます。
何が発表されたのか
gRPC は、ネットワーク越しにシステム同士が効率的に通信するための、モダンで高性能なサービス API 構築フレームワークです。サービスとクライアントは別々の言語で書かれることが多いため、多くの gRPC サービスは Protocol Buffers(protobuf)を使って API とやり取りするメッセージを定義します。API の契約は、特定の実装に依存しない中立的な形式である .proto ファイルで記述します。これがサービスの土台となり、効率的なバイナリシリアライゼーションのおかげで、メッセージは JSON など他の標準形式よりも小さく高速に処理できます。
gRPC Swift は、この Protocol Buffers の契約をもとに Swift のコードを生成し、契約に沿ったクライアント・サーバーを簡単に構築できるようにするツールです。今回の gRPC Swift 2 は、Swift らしい(idiomatic)API と、cross-platform・高性能・多機能を兼ね備えたライブラリへの大きなアップデートです。
gRPC Swift が最初に開発された 2018 年当時、Swift にはまだ async/await などの並行処理機能がなく、SwiftNIO のイベント駆動型の並行処理モデルに基づいていました。これらの概念に馴染みのない開発者にとっては学習コストが高いものでしたが、Swift のモダンな並行処理モデルが定着した今、Apple での大規模サービス構築の経験を踏まえて、現在の Swift に合わせて gRPC Swift を再設計したのが gRPC Swift 2 です。
主なハイライトは次のとおりです。
- 生成コードを含め、モダンで柔軟、かつ使いやすい Swift らしい API。
- Linux と Apple プラットフォームの両方でサーバー・クライアントを構築可能。
- 差し替え可能な transport。SwiftNIO 上に構築された高性能な HTTP/2 transport や、テストに便利なインプロセス transport を選べます。
- クライアント側のロードバランシング、差し替え可能な名前解決の仕組み、自動リトライといったスマートなクライアント機能。
- 認証・ロギング・メトリクスのような横断的な処理を実装できる、柔軟な interceptor 層。
何に使えるのか
挨拶を返すだけの典型的な「hello world」サービスを例にとると、.proto ファイルでは次のように API を定義します。
syntax = "proto3";
service GreetingService {
// Returns a personalized greeting.
rpc SayHello(SayHelloRequest) returns (SayHelloResponse);
}
message SayHelloRequest {
// The name of the person to greet.
string name = 1;
}
message SayHelloResponse {
// The personalized greeting message.
string message = 1;
}
この定義から、ビジネスロジックを実装するためのサービスコードと、サービスを呼び出すためのクライアントコードを生成できます。メッセージのコードは SwiftProtobuf が生成し、gRPC が生成するコードと組み合わせて使います。
生成されたサービスコードを使う
生成されるコードには、サービス定義の rpc ごとに 1 つのメソッドを持つ Swift のプロトコルが含まれます。ビジネスロジックを実装するには、このサービス用プロトコルのいずれかを実装します。下の例で使っている SimpleServiceProtocol は最も高レベルな API で、より柔軟性が必要な場合は簡潔さと引き換えに ServiceProtocol や StreamingServiceProtocol も選べます。
サービスを起動するには、transport を設定したサーバーとサービスのインスタンスを作成します。
import GRPCCore
import GRPCNIOTransportHTTP2
struct Greeter: GreetingService.SimpleServiceProtocol {
func sayHello(
request: SayHelloRequest,
context: ServerContext
) async throws -> SayHelloResponse {
return SayHelloResponse.with {
$0.message = "Hello, \(request.name)!"
}
}
}
@main
struct GreeterServer {
static func main() async throws {
// Create a plaintext server using the SwiftNIO based HTTP/2 transport
// listening on 127.0.0.1:8080.
let server = GRPCServer(
transport: .http2NIOPosix(
address: .ipv4(host: "127.0.0.1", port: 8080),
transportSecurity: .plaintext
),
services: [Greeter()]
)
// Start serving indefinitely.
try await server.serve()
}
}
生成されたクライアントコードを使う
クライアント側では、Swift らしいクライアントが生成され、サービスの呼び出しが簡単になります。まず生のクライアントを作成し、それをサービス専用の生成クライアントでラップします。これにより、型安全な方法でサービスとやり取りできます。
import GRPCCore
import GRPCNIOTransportHTTP2
@main
struct SayHello {
static func main() async throws {
// Create a plaintext client using the SwiftNIO based HTTP/2 transport
// connecting to a service listening on 127.0.0.1:8080.
try await withGRPCClient(
transport: .http2NIOPosix(
target: .dns(host: "127.0.0.1", port: 8080),
transportSecurity: .plaintext
)
) { client in
let greeter = GreetingService.Client(wrapping: client)
let greeting = try await greeter.sayHello(.with { $0.name = "swift.org" })
print(greeting.message)
}
}
}
導入・今後の位置づけ
gRPC Swift 2 は柔軟性を重視して設計されており、複数のパッケージの集合として提供されます。必要なコンポーネントだけを選んで使えます。
- grpc/grpc-swift-2: ランタイムの抽象化と型を提供します。
- grpc/grpc-swift-nio-transport: SwiftNIO 上に構築された HTTP/2 ベースのクライアント・サーバー transport を実装します。
- grpc/grpc-swift-protobuf: SwiftProtobuf と統合し、
.protoで定義されたサービスのコードジェネレータを提供します。 - grpc/grpc-swift-extras: reflection や health サービス、Swift Service Lifecycle との統合、OpenTelemetry による RPC のトレース用 interceptor など、よく使われるアドオンを含みます。
始めるには、Swift Package Index 上のチュートリアルとドキュメントを参照するか、grpc/grpc-swift-2 リポジトリのサンプルを試すよう案内されています。機能リクエストやバグ報告、貢献は GitHub または Swift フォーラムで受け付けられています。