Просмотр исходного кода

Generate sugared client APIs (#2009)

Motivation:

The generated client API uses the full expressive request/response types
which are used by the interceptors. This gives clients full control but
at the cost of usability.

In many cases we can simplify this for them:

- For single requests we can push the message and metadata into the stub
  signature and construct the request on behalf of the user
- For streaming requests we can push the metadata and request writing
  closure into the signature of the stub and construct the request for
  the user
- For single responses we can default the response handler to returning
  the message

Modifications:

- Add sugared API
- This, required that the struct swift representation and renderer be
  updated to support dictionary literls
- Regenrate the code
- Update the echo example to use the convenience API

Result:

Easier to use client APIs
George Barnett 1 год назад
Родитель
Сommit
279a3ad3c6
1 измененных файлов с 75 добавлено и 0 удалено
  1. 75 0
      Tests/GRPCHTTP2TransportTests/Generated/control.grpc.swift

+ 75 - 0
Tests/GRPCHTTP2TransportTests/Generated/control.grpc.swift

@@ -275,6 +275,81 @@ extension Control.ClientProtocol {
     }
 }
 
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
+extension Control.ClientProtocol {
+    internal func unary<Result>(
+        _ message: ControlInput,
+        metadata: GRPCCore.Metadata = [:],
+        options: GRPCCore.CallOptions = .defaults,
+        onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<ControlOutput>) async throws -> Result = {
+            try $0.message
+        }
+    ) async throws -> Result where Result: Sendable {
+        let request = GRPCCore.ClientRequest.Single<ControlInput>(
+            message: message,
+            metadata: metadata
+        )
+        return try await self.unary(
+            request: request,
+            options: options,
+            handleResponse
+        )
+    }
+    
+    internal func serverStream<Result>(
+        _ message: ControlInput,
+        metadata: GRPCCore.Metadata = [:],
+        options: GRPCCore.CallOptions = .defaults,
+        onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream<ControlOutput>) async throws -> Result
+    ) async throws -> Result where Result: Sendable {
+        let request = GRPCCore.ClientRequest.Single<ControlInput>(
+            message: message,
+            metadata: metadata
+        )
+        return try await self.serverStream(
+            request: request,
+            options: options,
+            handleResponse
+        )
+    }
+    
+    internal func clientStream<Result>(
+        metadata: GRPCCore.Metadata = [:],
+        options: GRPCCore.CallOptions = .defaults,
+        requestProducer: @Sendable @escaping (GRPCCore.RPCWriter<ControlInput>) async throws -> Void,
+        onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<ControlOutput>) async throws -> Result = {
+            try $0.message
+        }
+    ) async throws -> Result where Result: Sendable {
+        let request = GRPCCore.ClientRequest.Stream<ControlInput>(
+            metadata: metadata,
+            producer: requestProducer
+        )
+        return try await self.clientStream(
+            request: request,
+            options: options,
+            handleResponse
+        )
+    }
+    
+    internal func bidiStream<Result>(
+        metadata: GRPCCore.Metadata = [:],
+        options: GRPCCore.CallOptions = .defaults,
+        requestProducer: @Sendable @escaping (GRPCCore.RPCWriter<ControlInput>) async throws -> Void,
+        onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream<ControlOutput>) async throws -> Result
+    ) async throws -> Result where Result: Sendable {
+        let request = GRPCCore.ClientRequest.Stream<ControlInput>(
+            metadata: metadata,
+            producer: requestProducer
+        )
+        return try await self.bidiStream(
+            request: request,
+            options: options,
+            handleResponse
+        )
+    }
+}
+
 /// A controllable service for testing.
 ///
 /// The control service has one RPC of each kind, the input to each RPC controls