ServerResponse.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * Copyright 2023, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /// A response for a single message sent by a server.
  17. ///
  18. /// Single responses are used for unary and client-streaming RPCs. For streaming responses
  19. /// see ``StreamingServerResponse``.
  20. ///
  21. /// A single response captures every part of the response stream and distinguishes successful
  22. /// and unsuccessful responses via the ``accepted`` property. The value for the `success` case
  23. /// contains the initial metadata, response message, and the trailing metadata and implicitly
  24. /// has an ``Status/Code-swift.struct/ok`` status code.
  25. ///
  26. /// The `failure` case indicates that the server chose not to process the RPC, or the processing
  27. /// of the RPC failed. The failure case contains an ``RPCError`` describing why the RPC failed,
  28. /// including an error code, error message and any metadata sent by the server.
  29. ///
  30. /// ### Using ``Single`` responses
  31. ///
  32. /// Each response has an ``accepted`` property which contains all RPC information. You can create
  33. /// one by calling ``init(accepted:)`` or one of the two convenience initializers:
  34. /// - ``init(message:metadata:trailingMetadata:)`` to create a successful response, or
  35. /// - ``init(of:error:)`` to create a failed response.
  36. ///
  37. /// You can interrogate a response by inspecting the ``accepted`` property directly or by using
  38. /// its convenience properties:
  39. /// - ``metadata`` extracts the initial metadata,
  40. /// - ``message`` extracts the message, or throws if the response failed, and
  41. /// - ``trailingMetadata`` extracts the trailing metadata.
  42. ///
  43. /// The following example demonstrates how you can use the API:
  44. ///
  45. /// ```swift
  46. /// // Create a successful response
  47. /// let response = ServerResponse<String>(
  48. /// message: "Hello, World!",
  49. /// metadata: ["hello": "initial metadata"],
  50. /// trailingMetadata: ["goodbye": "trailing metadata"]
  51. /// )
  52. ///
  53. /// // The explicit API:
  54. /// switch response {
  55. /// case .success(let contents):
  56. /// print("Received response with message '\(contents.message)'")
  57. /// case .failure(let error):
  58. /// print("RPC failed with code '\(error.code)'")
  59. /// }
  60. ///
  61. /// // The convenience API:
  62. /// do {
  63. /// print("Received response with message '\(try response.message)'")
  64. /// } catch let error as RPCError {
  65. /// print("RPC failed with code '\(error.code)'")
  66. /// }
  67. /// ```
  68. public struct ServerResponse<Message: Sendable>: Sendable {
  69. /// An accepted RPC with a successful outcome.
  70. public struct Contents: Sendable {
  71. /// Caller-specified metadata to send to the client at the start of the response.
  72. ///
  73. /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with
  74. /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert
  75. /// their own metadata, you should avoid using key names which may clash with transport
  76. /// specific metadata. Note that transports may also impose limits in the amount of metadata
  77. /// which may be sent.
  78. public var metadata: Metadata
  79. /// The message to send to the client.
  80. public var message: Message
  81. /// Caller-specified metadata to send to the client at the end of the response.
  82. ///
  83. /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with
  84. /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert
  85. /// their own metadata, you should avoid using key names which may clash with transport
  86. /// specific metadata. Note that transports may also impose limits in the amount of metadata
  87. /// which may be sent.
  88. public var trailingMetadata: Metadata
  89. /// Create a new single client request.
  90. ///
  91. /// - Parameters:
  92. /// - message: The message to send to the server.
  93. /// - metadata: Metadata to send to the client at the start of the response. Defaults to
  94. /// empty.
  95. /// - trailingMetadata: Metadata to send to the client at the end of the response. Defaults
  96. /// to empty.
  97. public init(
  98. message: Message,
  99. metadata: Metadata = [:],
  100. trailingMetadata: Metadata = [:]
  101. ) {
  102. self.metadata = metadata
  103. self.message = message
  104. self.trailingMetadata = trailingMetadata
  105. }
  106. }
  107. /// Whether the RPC was accepted or rejected.
  108. ///
  109. /// The `success` indicates the server accepted the RPC for processing and the RPC completed
  110. /// successfully and implies the RPC succeeded with the ``Status/Code-swift.struct/ok`` status
  111. /// code. The `failure` case indicates that the service rejected the RPC without processing it
  112. /// or could not process it successfully.
  113. public var accepted: Result<Contents, RPCError>
  114. /// Creates a response.
  115. ///
  116. /// - Parameter accepted: Whether the RPC was accepted or rejected.
  117. public init(accepted: Result<Contents, RPCError>) {
  118. self.accepted = accepted
  119. }
  120. }
  121. /// A response for a stream of messages sent by a server.
  122. ///
  123. /// Stream responses are used for server-streaming and bidirectional-streaming RPCs. For single
  124. /// responses see ``ServerResponse``.
  125. ///
  126. /// A stream response captures every part of the response stream and distinguishes whether the
  127. /// request was processed by the server via the ``accepted`` property. The value for the `success`
  128. /// case contains the initial metadata and a closure which is provided with a message write and
  129. /// returns trailing metadata. If the closure returns without error then the response implicitly
  130. /// has an ``Status/Code-swift.struct/ok`` status code. You can throw an error from the producer
  131. /// to indicate that the request couldn't be handled successfully. If an ``RPCError`` is thrown
  132. /// then the client will receive an equivalent error populated with the same code and message. If
  133. /// an error of any other type is thrown then the client will receive an error with the
  134. /// ``Status/Code-swift.struct/unknown`` status code.
  135. ///
  136. /// The `failure` case indicates that the server chose not to process the RPC. The failure case
  137. /// contains an ``RPCError`` describing why the RPC failed, including an error code, error
  138. /// message and any metadata to send to the client.
  139. ///
  140. /// ### Using ``Stream`` responses
  141. ///
  142. /// Each response has an ``accepted`` property which contains all RPC information. You can create
  143. /// one by calling ``init(accepted:)`` or one of the two convenience initializers:
  144. /// - ``init(of:metadata:producer:)`` to create a successful response, or
  145. /// - ``init(of:error:)`` to create a failed response.
  146. ///
  147. /// You can interrogate a response by inspecting the ``accepted`` property directly. The following
  148. /// example demonstrates how you can use the API:
  149. ///
  150. /// ```swift
  151. /// // Create a successful response
  152. /// let response = StreamingServerResponse(
  153. /// of: String.self,
  154. /// metadata: ["hello": "initial metadata"]
  155. /// ) { writer in
  156. /// // Write a few messages.
  157. /// try await writer.write("Hello")
  158. /// try await writer.write("World")
  159. ///
  160. /// // Send trailing metadata to the client.
  161. /// return ["goodbye": "trailing metadata"]
  162. /// }
  163. /// ```
  164. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  165. public struct StreamingServerResponse<Message: Sendable>: Sendable {
  166. /// The contents of a response to a request which has been accepted for processing.
  167. public struct Contents: Sendable {
  168. /// Metadata to send to the client at the beginning of the response stream.
  169. public var metadata: Metadata
  170. /// A closure which, when called, writes values into the provided writer and returns trailing
  171. /// metadata indicating the end of the response stream.
  172. ///
  173. /// Returning metadata indicates a successful response and gRPC will terminate the RPC with
  174. /// an ``Status/Code-swift.struct/ok`` status code. Throwing an error will terminate the RPC
  175. /// with an appropriate status code. You can control the status code, message and metadata
  176. /// returned to the client by throwing an ``RPCError``. If the error thrown is a type other
  177. /// than ``RPCError`` then a status with code ``Status/Code-swift.struct/unknown`` will
  178. /// be returned to the client.
  179. ///
  180. /// gRPC will invoke this function at most once therefore it isn't required to be idempotent.
  181. public var producer: @Sendable (RPCWriter<Message>) async throws -> Metadata
  182. /// Create a ``Contents``.
  183. ///
  184. /// - Parameters:
  185. /// - metadata: Metadata to send to the client at the start of the response.
  186. /// - producer: A function which produces values
  187. public init(
  188. metadata: Metadata,
  189. producer: @escaping @Sendable (RPCWriter<Message>) async throws -> Metadata
  190. ) {
  191. self.metadata = metadata
  192. self.producer = producer
  193. }
  194. }
  195. /// Whether the RPC was accepted or rejected.
  196. ///
  197. /// The `success` case indicates that the service accepted the RPC for processing and will
  198. /// send initial metadata back to the client before producing response messages. The RPC may
  199. /// still result in failure by later throwing an error.
  200. ///
  201. /// The `failure` case indicates that the server rejected the RPC and will not process it. Only
  202. /// the status and trailing metadata will be sent to the client.
  203. public var accepted: Result<Contents, RPCError>
  204. /// Creates a response.
  205. ///
  206. /// - Parameter accepted: Whether the RPC was accepted or rejected.
  207. public init(accepted: Result<Contents, RPCError>) {
  208. self.accepted = accepted
  209. }
  210. }
  211. extension ServerResponse {
  212. /// Creates a new accepted response.
  213. ///
  214. /// - Parameters:
  215. /// - metadata: Metadata to send to the client at the beginning of the response.
  216. /// - message: The response message to send to the client.
  217. /// - trailingMetadata: Metadata to send to the client at the end of the response.
  218. public init(message: Message, metadata: Metadata = [:], trailingMetadata: Metadata = [:]) {
  219. let contents = Contents(
  220. message: message,
  221. metadata: metadata,
  222. trailingMetadata: trailingMetadata
  223. )
  224. self.accepted = .success(contents)
  225. }
  226. /// Creates a new failed response.
  227. ///
  228. /// - Parameters:
  229. /// - messageType: The type of message.
  230. /// - error: An error describing why the RPC failed.
  231. public init(of messageType: Message.Type = Message.self, error: RPCError) {
  232. self.accepted = .failure(error)
  233. }
  234. /// Returns the metadata to be sent to the client at the start of the response.
  235. ///
  236. /// For rejected RPCs (in other words, where ``accepted`` is `failure`) the metadata is empty.
  237. public var metadata: Metadata {
  238. switch self.accepted {
  239. case let .success(contents):
  240. return contents.metadata
  241. case .failure:
  242. return [:]
  243. }
  244. }
  245. /// Returns the message to send to the client.
  246. ///
  247. /// - Throws: ``RPCError`` if the request failed.
  248. public var message: Message {
  249. get throws {
  250. try self.accepted.map { $0.message }.get()
  251. }
  252. }
  253. /// Returns metadata to be sent to the client at the end of the response.
  254. ///
  255. /// Unlike ``metadata``, for rejected RPCs the metadata returned may contain values.
  256. public var trailingMetadata: Metadata {
  257. switch self.accepted {
  258. case let .success(contents):
  259. return contents.trailingMetadata
  260. case let .failure(error):
  261. return error.metadata
  262. }
  263. }
  264. }
  265. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  266. extension StreamingServerResponse {
  267. /// Creates a new accepted response.
  268. ///
  269. /// - Parameters:
  270. /// - messageType: The type of message.
  271. /// - metadata: Metadata to send to the client at the beginning of the response.
  272. /// - producer: A closure which, when called, writes messages to the client.
  273. public init(
  274. of messageType: Message.Type = Message.self,
  275. metadata: Metadata = [:],
  276. producer: @escaping @Sendable (RPCWriter<Message>) async throws -> Metadata
  277. ) {
  278. let contents = Contents(metadata: metadata, producer: producer)
  279. self.accepted = .success(contents)
  280. }
  281. /// Creates a new failed response.
  282. ///
  283. /// - Parameters:
  284. /// - messageType: The type of message.
  285. /// - error: An error describing why the RPC failed.
  286. public init(of messageType: Message.Type = Message.self, error: RPCError) {
  287. self.accepted = .failure(error)
  288. }
  289. /// Returns metadata received from the server at the start of the response.
  290. ///
  291. /// For rejected RPCs (in other words, where ``accepted`` is `failure`) the metadata is empty.
  292. public var metadata: Metadata {
  293. switch self.accepted {
  294. case let .success(contents):
  295. return contents.metadata
  296. case .failure:
  297. return [:]
  298. }
  299. }
  300. }
  301. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  302. extension StreamingServerResponse {
  303. public init(single response: ServerResponse<Message>) {
  304. switch response.accepted {
  305. case .success(let contents):
  306. let contents = Contents(metadata: contents.metadata) {
  307. try await $0.write(contents.message)
  308. return contents.trailingMetadata
  309. }
  310. self.accepted = .success(contents)
  311. case .failure(let error):
  312. self.accepted = .failure(error)
  313. }
  314. }
  315. }