Browse Source

Allow users to fulfill status promises with `GRPCStatusTransformable` errors. (#422)

* Allow users to fulfill status promises with `GRPCStatusTransformable` errors.

We then take care of converting these to `GRPCStatus`.

* PR fixes.

* Make asGRPCStatus() return a non-optional result again.
Daniel Alm 6 years ago
parent
commit
da1a59c919

+ 4 - 4
Package.resolved

@@ -33,8 +33,8 @@
         "repositoryURL": "https://github.com/apple/swift-nio-http2.git",
         "state": {
           "branch": null,
-          "revision": "a9fc7c17dda4cd72ae9ec5848d1c30b230f2b1ed",
-          "version": "1.0.0"
+          "revision": "a92923bcb7d884e6977b7cb131705703936af956",
+          "version": "1.0.1"
         }
       },
       {
@@ -42,8 +42,8 @@
         "repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
         "state": {
           "branch": null,
-          "revision": "a41d0643866c5128ef0d5b2f14368db820312380",
-          "version": "2.0.0"
+          "revision": "47d971e1367f6df8ddf06c284ad266df39c31024",
+          "version": "2.0.1"
         }
       },
       {

+ 1 - 1
Sources/SwiftGRPCNIO/ClientCalls/ClientCall.swift

@@ -36,7 +36,7 @@ public protocol ClientCall {
   ///
   /// The client may populate the status if, for example, it was not possible to connect to the service.
   ///
-  /// Note: despite `GRPCStatus` being an `Error`, the value will be __always__ delivered as a __success__
+  /// Note: despite `GRPCStatus` conforming to `Error`, the value will be __always__ delivered as a __success__
   /// result even if the status represents a __negative__ outcome. This future will __never__ be fulfilled
   /// with an error.
   var status: EventLoopFuture<GRPCStatus> { get }

+ 3 - 3
Sources/SwiftGRPCNIO/GRPCClientChannelHandler.swift

@@ -27,8 +27,8 @@ import SwiftProtobuf
 ///
 /// Errors are also handled by the channel handler. Promises for the initial metadata and
 /// response (if applicable) are failed with first error received. The status promise is __succeeded__
-/// with the error as a `GRPCStatus`. The stream is also closed and any inbound or outbound messages
-/// are ignored.
+/// with the error as the result of `GRPCStatusTransformable.asGRPCStatus()`, if available.
+/// The stream is also closed and any inbound or outbound messages are ignored.
 internal class GRPCClientChannelHandler<RequestMessage: Message, ResponseMessage: Message> {
   internal let initialMetadataPromise: EventLoopPromise<HTTPHeaders>
   internal let statusPromise: EventLoopPromise<GRPCStatus>
@@ -85,7 +85,7 @@ internal class GRPCClientChannelHandler<RequestMessage: Message, ResponseMessage
 
   /// Observe the given status.
   ///
-  /// The `status` promise is __succeeded__ with the given status despite `GRPCStatus` being an
+  /// The `status` promise is __succeeded__ with the given status despite `GRPCStatus` conforming to
   /// `Error`. If `status.code != .ok` then the initial metadata and response promises (if applicable)
   /// are failed with the given status.
   ///

+ 1 - 1
Sources/SwiftGRPCNIO/GRPCError.swift

@@ -33,7 +33,7 @@ public struct GRPCError: Error, GRPCStatusTransformable {
   public let line: Int
 
   public func asGRPCStatus() -> GRPCStatus {
-    return (error as? GRPCStatusTransformable)?.asGRPCStatus() ?? GRPCStatus.processingError
+    return (error as? GRPCStatusTransformable)?.asGRPCStatus() ?? .processingError
   }
 
   private init(_ error: Error, origin: Origin, file: StaticString, line: Int) {

+ 5 - 4
Sources/SwiftGRPCNIO/ServerCallContexts/StreamingResponseCallContext.swift

@@ -6,8 +6,9 @@ import NIOHTTP1
 /// Abstract base class exposing a method to send multiple messages over the wire and a promise for the final RPC status.
 ///
 /// - When `statusPromise` is fulfilled, the call is closed and the provided status transmitted.
-/// - If `statusPromise` is failed and the error is of type `GRPCStatus`, that error will be returned to the client.
-/// - For other errors, `GRPCStatus.processingError` is returned to the client.
+/// - If `statusPromise` is failed and the error is of type `GRPCStatusTransformable`,
+///   the result of `error.asGRPCStatus()` will be returned to the client.
+/// - If `error.asGRPCStatus()` is not available, `GRPCStatus.processingError` is returned to the client.
 open class StreamingResponseCallContext<ResponseMessage: Message>: ServerCallContextBase {
   public typealias WrappedResponse = GRPCServerResponsePart<ResponseMessage>
 
@@ -33,9 +34,9 @@ open class StreamingResponseCallContextImpl<ResponseMessage: Message>: Streaming
     super.init(eventLoop: channel.eventLoop, request: request)
 
     statusPromise.futureResult
-      // Ensure that any error provided is of type `GRPCStatus`, using "internal server error" as a fallback.
+      // Ensure that any error provided can be transformed to `GRPCStatus`, using "internal server error" as a fallback.
       .recover { error in
-        (error as? GRPCStatus) ?? .processingError
+        (error as? GRPCStatusTransformable)?.asGRPCStatus() ?? .processingError
       }
       // Finish the call by returning the final status.
       .whenSuccess {

+ 5 - 4
Sources/SwiftGRPCNIO/ServerCallContexts/UnaryResponseCallContext.swift

@@ -6,8 +6,9 @@ import NIOHTTP1
 /// Abstract base class exposing a method that exposes a promise for the RPC response.
 ///
 /// - When `responsePromise` is fulfilled, the call is closed and the provided response transmitted with status `responseStatus` (`.ok` by default).
-/// - If `statusPromise` is failed and the error is of type `GRPCStatus`, that error will be returned to the client.
-/// - For other errors, `GRPCStatus.processingError` is returned to the client.
+/// - If `statusPromise` is failed and the error is of type `GRPCStatusTransformable`,
+///   the result of `error.asGRPCStatus()` will be returned to the client.
+/// - If `error.asGRPCStatus()` is not available, `GRPCStatus.processingError` is returned to the client.
 ///
 /// For unary calls, the response is not actually provided by fulfilling `responsePromise`, but instead by completing
 /// the future returned by `UnaryCallHandler.EventObserver`.
@@ -53,9 +54,9 @@ open class UnaryResponseCallContextImpl<ResponseMessage: Message>: UnaryResponse
       .map { _ in
         self.responseStatus
       }
-      // Ensure that any error provided is of type `GRPCStatus`, using "internal server error" as a fallback.
+      // Ensure that any error provided can be transformed to `GRPCStatus`, using "internal server error" as a fallback.
       .recover { error in
-        (error as? GRPCStatus) ?? .processingError
+        (error as? GRPCStatusTransformable)?.asGRPCStatus() ?? .processingError
       }
       // Finish the call by returning the final status.
       .whenSuccess { status in