ServerResponse.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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. /// The metadata to be sent to the client at the start of the response.
  234. public var metadata: Metadata {
  235. get {
  236. switch self.accepted {
  237. case let .success(contents):
  238. return contents.metadata
  239. case .failure(let error):
  240. return error.metadata
  241. }
  242. }
  243. set {
  244. switch self.accepted {
  245. case var .success(contents):
  246. contents.metadata = newValue
  247. self.accepted = .success(contents)
  248. case var .failure(error):
  249. error.metadata = newValue
  250. self.accepted = .failure(error)
  251. }
  252. }
  253. }
  254. /// Returns the message to send to the client.
  255. ///
  256. /// - Throws: ``RPCError`` if the request failed.
  257. public var message: Message {
  258. get throws {
  259. try self.accepted.map { $0.message }.get()
  260. }
  261. }
  262. /// Returns metadata to be sent to the client at the end of the response.
  263. ///
  264. /// Unlike ``metadata``, for rejected RPCs the metadata returned may contain values.
  265. public var trailingMetadata: Metadata {
  266. switch self.accepted {
  267. case let .success(contents):
  268. return contents.trailingMetadata
  269. case let .failure(error):
  270. return error.metadata
  271. }
  272. }
  273. }
  274. extension StreamingServerResponse {
  275. /// Creates a new accepted response.
  276. ///
  277. /// - Parameters:
  278. /// - messageType: The type of message.
  279. /// - metadata: Metadata to send to the client at the beginning of the response.
  280. /// - producer: A closure which, when called, writes messages to the client.
  281. public init(
  282. of messageType: Message.Type = Message.self,
  283. metadata: Metadata = [:],
  284. producer: @escaping @Sendable (RPCWriter<Message>) async throws -> Metadata
  285. ) {
  286. let contents = Contents(metadata: metadata, producer: producer)
  287. self.accepted = .success(contents)
  288. }
  289. /// Creates a new failed response.
  290. ///
  291. /// - Parameters:
  292. /// - messageType: The type of message.
  293. /// - error: An error describing why the RPC failed.
  294. public init(of messageType: Message.Type = Message.self, error: RPCError) {
  295. self.accepted = .failure(error)
  296. }
  297. /// The metadata to be sent to the client at the start of the response.
  298. public var metadata: Metadata {
  299. get {
  300. switch self.accepted {
  301. case let .success(contents):
  302. return contents.metadata
  303. case .failure(let error):
  304. return error.metadata
  305. }
  306. }
  307. set {
  308. switch self.accepted {
  309. case var .success(contents):
  310. contents.metadata = newValue
  311. self.accepted = .success(contents)
  312. case var .failure(error):
  313. error.metadata = newValue
  314. self.accepted = .failure(error)
  315. }
  316. }
  317. }
  318. }
  319. extension StreamingServerResponse {
  320. public init(single response: ServerResponse<Message>) {
  321. switch response.accepted {
  322. case .success(let contents):
  323. let contents = Contents(metadata: contents.metadata) {
  324. try await $0.write(contents.message)
  325. return contents.trailingMetadata
  326. }
  327. self.accepted = .success(contents)
  328. case .failure(let error):
  329. self.accepted = .failure(error)
  330. }
  331. }
  332. }