@@ -18,12 +18,42 @@ import NIOConcurrencyHelpers
1818import NIOHTTP1
1919import NIOSSL
2020
21+ /// HTTPClient class provides API for request execution.
22+ ///
23+ /// Example:
24+ ///
25+ /// ```swift
26+ /// let client = HTTPClient(eventLoopGroupProvider = .createNew)
27+ /// client.get(url: "https://swift.org", deadline: .now() + .seconds(1)).whenComplete { result in
28+ /// switch result {
29+ /// case .failure(let error):
30+ /// // process error
31+ /// case .success(let response):
32+ /// if let response.status == .ok {
33+ /// // handle response
34+ /// } else {
35+ /// // handle remote error
36+ /// }
37+ /// }
38+ /// }
39+ /// ```
40+ ///
41+ /// It is important to close the client instance, for example in a defer statement, after use to cleanly shutdown the underlying NIO `EventLoopGroup`:
42+ ///
43+ /// ```swift
44+ /// try client.syncShutdown()
45+ /// ```
2146public class HTTPClient {
2247 public let eventLoopGroup : EventLoopGroup
2348 let eventLoopGroupProvider : EventLoopGroupProvider
2449 let configuration : Configuration
2550 let isShutdown = Atomic < Bool > ( value: false )
2651
52+ /// Create an `HTTPClient` with specified `EventLoopGroup` provider and configuration.
53+ ///
54+ /// - parameters:
55+ /// - eventLoopGroupProvider: Specify how `EventLoopGroup` will be created.
56+ /// - configuration: Client configuration.
2757 public init ( eventLoopGroupProvider: EventLoopGroupProvider , configuration: Configuration = Configuration ( ) ) {
2858 self . eventLoopGroupProvider = eventLoopGroupProvider
2959 switch self . eventLoopGroupProvider {
@@ -44,6 +74,7 @@ public class HTTPClient {
4474 }
4575 }
4676
77+ /// Shuts down the client and `EventLoopGroup` if it was created by the client.
4778 public func syncShutdown( ) throws {
4879 switch self . eventLoopGroupProvider {
4980 case . shared:
@@ -58,6 +89,11 @@ public class HTTPClient {
5889 }
5990 }
6091
92+ /// Execute `GET` request using specified URL.
93+ ///
94+ /// - parameters:
95+ /// - url: Remote URL.
96+ /// - deadline: Point in time by which the request must complete.
6197 public func get( url: String , deadline: NIODeadline ? = nil ) -> EventLoopFuture < Response > {
6298 do {
6399 let request = try Request ( url: url, method: . GET)
@@ -67,6 +103,12 @@ public class HTTPClient {
67103 }
68104 }
69105
106+ /// Execute `POST` request using specified URL.
107+ ///
108+ /// - parameters:
109+ /// - url: Remote URL.
110+ /// - body: Request body.
111+ /// - deadline: Point in time by which the request must complete.
70112 public func post( url: String , body: Body ? = nil , deadline: NIODeadline ? = nil ) -> EventLoopFuture < Response > {
71113 do {
72114 let request = try HTTPClient . Request ( url: url, method: . POST, body: body)
@@ -76,6 +118,12 @@ public class HTTPClient {
76118 }
77119 }
78120
121+ /// Execute `PATCH` request using specified URL.
122+ ///
123+ /// - parameters:
124+ /// - url: Remote URL.
125+ /// - body: Request body.
126+ /// - deadline: Point in time by which the request must complete.
79127 public func patch( url: String , body: Body ? = nil , deadline: NIODeadline ? = nil ) -> EventLoopFuture < Response > {
80128 do {
81129 let request = try HTTPClient . Request ( url: url, method: . PATCH, body: body)
@@ -85,6 +133,12 @@ public class HTTPClient {
85133 }
86134 }
87135
136+ /// Execute `PUT` request using specified URL.
137+ ///
138+ /// - parameters:
139+ /// - url: Remote URL.
140+ /// - body: Request body.
141+ /// - deadline: Point in time by which the request must complete.
88142 public func put( url: String , body: Body ? = nil , deadline: NIODeadline ? = nil ) -> EventLoopFuture < Response > {
89143 do {
90144 let request = try HTTPClient . Request ( url: url, method: . PUT, body: body)
@@ -94,6 +148,11 @@ public class HTTPClient {
94148 }
95149 }
96150
151+ /// Execute `DELETE` request using specified URL.
152+ ///
153+ /// - parameters:
154+ /// - url: Remote URL.
155+ /// - deadline: The time when the request must have been completed by.
97156 public func delete( url: String , deadline: NIODeadline ? = nil ) -> EventLoopFuture < Response > {
98157 do {
99158 let request = try Request ( url: url, method: . DELETE)
@@ -103,11 +162,22 @@ public class HTTPClient {
103162 }
104163 }
105164
165+ /// Execute arbitrary HTTP request using specified URL.
166+ ///
167+ /// - parameters:
168+ /// - request: HTTP request to execute.
169+ /// - deadline: Point in time by which the request must complete.
106170 public func execute( request: Request , deadline: NIODeadline ? = nil ) -> EventLoopFuture < Response > {
107171 let accumulator = ResponseAccumulator ( request: request)
108172 return self . execute ( request: request, delegate: accumulator, deadline: deadline) . futureResult
109173 }
110174
175+ /// Execute arbitrary HTTP request and handle response processing using provided delegate.
176+ ///
177+ /// - parameters:
178+ /// - request: HTTP request to execute.
179+ /// - delegate: Delegate to process response parts.
180+ /// - deadline: Point in time by which the request must complete.
111181 public func execute< T: HTTPClientResponseDelegate > ( request: Request , delegate: T , deadline: NIODeadline ? = nil ) -> Task < T . Response > {
112182 let eventLoop = self . eventLoopGroup. next ( )
113183
@@ -187,10 +257,24 @@ public class HTTPClient {
187257 }
188258 }
189259
260+ /// `HTTPClient` configuration.
190261 public struct Configuration {
262+ /// TLS configuration, defaults to `TLSConfiguration.forClient()`.
191263 public var tlsConfiguration : TLSConfiguration ?
264+ /// Enables following 3xx redirects automatically, defaults to `false`.
265+ ///
266+ /// Following redirects are supported:
267+ /// - `301: Moved Permanently`
268+ /// - `302: Found`
269+ /// - `303: See Other`
270+ /// - `304: Not Modified`
271+ /// - `305: Use Proxy`
272+ /// - `307: Temporary Redirect`
273+ /// - `308: Permanent Redirect`
192274 public var followRedirects : Bool
275+ /// Default client timeout, defaults to no timeouts.
193276 public var timeout : Timeout
277+ /// Upstream proxy, defaults to no proxy.
194278 public var proxy : Proxy ?
195279
196280 public init ( tlsConfiguration: TLSConfiguration ? = nil , followRedirects: Bool = false , timeout: Timeout = Timeout ( ) , proxy: Proxy ? = nil ) {
@@ -208,15 +292,26 @@ public class HTTPClient {
208292 }
209293 }
210294
295+ /// Specifies how `EventLoopGroup` will be created and establishes lifecycle ownership.
211296 public enum EventLoopGroupProvider {
297+ /// `EventLoopGroup` will be provided by the user. Owner of this group is responsible for its lifecycle.
212298 case shared( EventLoopGroup )
299+ /// `EventLoopGroup` will be created by the client. When `syncShutdown` is called, created `EventLoopGroup` will be shut down as well.
213300 case createNew
214301 }
215302
303+ /// Timeout configuration
216304 public struct Timeout {
305+ /// Specifies connect timeout.
217306 public var connect : TimeAmount ?
307+ /// Specifies read timeout.
218308 public var read : TimeAmount ?
219309
310+ /// Create timeout.
311+ ///
312+ /// - parameters:
313+ /// - connect: `connect` timeout.
314+ /// - read: `read` timeout.
220315 public init ( connect: TimeAmount ? = nil , read: TimeAmount ? = nil ) {
221316 self . connect = connect
222317 self . read = read
@@ -255,6 +350,7 @@ private extension ChannelPipeline {
255350 }
256351}
257352
353+ /// Possible client errors.
258354public struct HTTPClientError : Error , Equatable , CustomStringConvertible {
259355 private enum Code : Equatable {
260356 case invalidURL
@@ -281,16 +377,28 @@ public struct HTTPClientError: Error, Equatable, CustomStringConvertible {
281377 return " HTTPClientError. \( String ( describing: self . code) ) "
282378 }
283379
380+ /// URL provided is invalid.
284381 public static let invalidURL = HTTPClientError ( code: . invalidURL)
382+ /// URL does not contain host.
285383 public static let emptyHost = HTTPClientError ( code: . emptyHost)
384+ /// Client is shutdown and cannot be used for new requests.
286385 public static let alreadyShutdown = HTTPClientError ( code: . alreadyShutdown)
386+ /// URL does not contain scheme.
287387 public static let emptyScheme = HTTPClientError ( code: . emptyScheme)
388+ /// Provided URL scheme is not supported, supported schemes are: `http` and `https`
288389 public static func unsupportedScheme( _ scheme: String ) -> HTTPClientError { return HTTPClientError ( code: . unsupportedScheme( scheme) ) }
390+ /// Request timed out.
289391 public static let readTimeout = HTTPClientError ( code: . readTimeout)
392+ /// Remote connection was closed unexpectedly.
290393 public static let remoteConnectionClosed = HTTPClientError ( code: . remoteConnectionClosed)
394+ /// Request was cancelled.
291395 public static let cancelled = HTTPClientError ( code: . cancelled)
396+ /// Request contains invalid identity encoding.
292397 public static let identityCodingIncorrectlyPresent = HTTPClientError ( code: . identityCodingIncorrectlyPresent)
398+ /// Request contains multiple chunks definitions.
293399 public static let chunkedSpecifiedMultipleTimes = HTTPClientError ( code: . chunkedSpecifiedMultipleTimes)
400+ /// Proxy response was invalid.
294401 public static let invalidProxyResponse = HTTPClientError ( code: . invalidProxyResponse)
402+ /// Request does not contain `Content-Length` header.
295403 public static let contentLengthMissing = HTTPClientError ( code: . contentLengthMissing)
296404}
0 commit comments