ServerResponse.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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 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 streaming 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. public struct StreamingServerResponse<Message: Sendable>: Sendable {
  165. /// The contents of a response to a request which has been accepted for processing.
  166. public struct Contents: Sendable {
  167. /// Metadata to send to the client at the beginning of the response stream.
  168. public var metadata: Metadata
  169. /// A closure which, when called, writes values into the provided writer and returns trailing
  170. /// metadata indicating the end of the response stream.
  171. ///
  172. /// Returning metadata indicates a successful response and gRPC will terminate the RPC with
  173. /// an ``Status/Code-swift.struct/ok`` status code. Throwing an error will terminate the RPC
  174. /// with an appropriate status code. You can control the status code, message and metadata
  175. /// returned to the client by throwing an ``RPCError``. If the error thrown is a type other
  176. /// than ``RPCError`` then a status with code ``Status/Code-swift.struct/unknown`` will
  177. /// be returned to the client.
  178. ///
  179. /// gRPC will invoke this function at most once therefore it isn't required to be idempotent.
  180. public var producer: @Sendable (RPCWriter<Message>) async throws -> Metadata
  181. /// Create a ``Contents``.
  182. ///
  183. /// - Parameters:
  184. /// - metadata: Metadata to send to the client at the start of the response.
  185. /// - producer: A function which produces values
  186. public init(
  187. metadata: Metadata,
  188. producer: @escaping @Sendable (RPCWriter<Message>) async throws -> Metadata
  189. ) {
  190. self.metadata = metadata
  191. self.producer = producer
  192. }
  193. }
  194. /// Whether the RPC was accepted or rejected.
  195. ///
  196. /// The `success` case indicates that the service accepted the RPC for processing and will
  197. /// send initial metadata back to the client before producing response messages. The RPC may
  198. /// still result in failure by later throwing an error.
  199. ///
  200. /// The `failure` case indicates that the server rejected the RPC and will not process it. Only
  201. /// the status and trailing metadata will be sent to the client.
  202. public var accepted: Result<Contents, RPCError>
  203. /// Creates a response.
  204. ///
  205. /// - Parameter accepted: Whether the RPC was accepted or rejected.
  206. public init(accepted: Result<Contents, RPCError>) {
  207. self.accepted = accepted
  208. }
  209. }
  210. extension ServerResponse {
  211. /// Creates a new accepted response.
  212. ///
  213. /// - Parameters:
  214. /// - metadata: Metadata to send to the client at the beginning of the response.
  215. /// - message: The response message to send to the client.
  216. /// - trailingMetadata: Metadata to send to the client at the end of the response.
  217. public init(message: Message, metadata: Metadata = [:], trailingMetadata: Metadata = [:]) {
  218. let contents = Contents(
  219. message: message,
  220. metadata: metadata,
  221. trailingMetadata: trailingMetadata
  222. )
  223. self.accepted = .success(contents)
  224. }
  225. /// Creates a new failed response.
  226. ///
  227. /// - Parameters:
  228. /// - messageType: The type of message.
  229. /// - error: An error describing why the RPC failed.
  230. public init(of messageType: Message.Type = Message.self, error: RPCError) {
  231. self.accepted = .failure(error)
  232. }
  233. /// Returns the metadata to be sent to the client at the start of the response.
  234. ///
  235. /// For rejected RPCs (in other words, where ``accepted`` is `failure`) the metadata is empty.
  236. public var metadata: Metadata {
  237. switch self.accepted {
  238. case let .success(contents):
  239. return contents.metadata
  240. case .failure:
  241. return [:]
  242. }
  243. }
  244. /// Returns the message to send to the client.
  245. ///
  246. /// - Throws: ``RPCError`` if the request failed.
  247. public var message: Message {
  248. get throws {
  249. try self.accepted.map { $0.message }.get()
  250. }
  251. }
  252. /// Returns metadata to be sent to the client at the end of the response.
  253. ///
  254. /// Unlike ``metadata``, for rejected RPCs the metadata returned may contain values.
  255. public var trailingMetadata: Metadata {
  256. switch self.accepted {
  257. case let .success(contents):
  258. return contents.trailingMetadata
  259. case let .failure(error):
  260. return error.metadata
  261. }
  262. }
  263. }
  264. extension StreamingServerResponse {
  265. /// Creates a new accepted response.
  266. ///
  267. /// - Parameters:
  268. /// - messageType: The type of message.
  269. /// - metadata: Metadata to send to the client at the beginning of the response.
  270. /// - producer: A closure which, when called, writes messages to the client.
  271. public init(
  272. of messageType: Message.Type = Message.self,
  273. metadata: Metadata = [:],
  274. producer: @escaping @Sendable (RPCWriter<Message>) async throws -> Metadata
  275. ) {
  276. let contents = Contents(metadata: metadata, producer: producer)
  277. self.accepted = .success(contents)
  278. }
  279. /// Creates a new failed response.
  280. ///
  281. /// - Parameters:
  282. /// - messageType: The type of message.
  283. /// - error: An error describing why the RPC failed.
  284. public init(of messageType: Message.Type = Message.self, error: RPCError) {
  285. self.accepted = .failure(error)
  286. }
  287. /// Returns metadata received from the server at the start of the response.
  288. ///
  289. /// For rejected RPCs (in other words, where ``accepted`` is `failure`) the metadata is empty.
  290. public var metadata: Metadata {
  291. switch self.accepted {
  292. case let .success(contents):
  293. return contents.metadata
  294. case .failure:
  295. return [:]
  296. }
  297. }
  298. }
  299. extension StreamingServerResponse {
  300. public init(single response: ServerResponse<Message>) {
  301. switch response.accepted {
  302. case .success(let contents):
  303. let contents = Contents(metadata: contents.metadata) {
  304. try await $0.write(contents.message)
  305. return contents.trailingMetadata
  306. }
  307. self.accepted = .success(contents)
  308. case .failure(let error):
  309. self.accepted = .failure(error)
  310. }
  311. }
  312. }