Skip to content

Commit 0c617a4

Browse files
artemredkinYasumoto
authored andcommitted
document public API (#62)
Co-Authored-By: Joe Smith <yasumoto7@gmail.com>
1 parent 8fa6c6f commit 0c617a4

File tree

4 files changed

+269
-11
lines changed

4 files changed

+269
-11
lines changed

Sources/AsyncHTTPClient/HTTPClient+HTTPCookie.swift

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,33 @@ import Foundation
1616
import NIOHTTP1
1717

1818
extension HTTPClient {
19+
/// A representation of an HTTP cookie.
1920
public struct Cookie {
21+
/// The name of the cookie.
2022
public var name: String
23+
/// The cookie's string value.
2124
public var value: String
25+
/// The cookie's path.
2226
public var path: String
27+
/// The domain of the cookie.
2328
public var domain: String?
29+
/// The cookie's expiration date.
2430
public var expires: Date?
31+
/// The cookie's age in seconds.
2532
public var maxAge: Int?
33+
/// Whether the cookie should only be sent to HTTP servers.
2634
public var httpOnly: Bool
35+
/// Whether the cookie should only be sent over secure channels.
2736
public var secure: Bool
2837

29-
public init?(from string: String, defaultDomain: String) {
30-
let components = string.components(separatedBy: ";").map {
38+
/// Create a Cookie by parsing a `Set-Cookie` header.
39+
///
40+
/// - parameters:
41+
/// - header: String representation of the `Set-Cookie` response header.
42+
/// - defaultDomain: Default domain to use if cookie was sent without one.
43+
/// - returns: nil if the header is invalid.
44+
public init?(header: String, defaultDomain: String) {
45+
let components = header.components(separatedBy: ";").map {
3146
$0.trimmingCharacters(in: .whitespaces)
3247
}
3348

@@ -90,6 +105,17 @@ extension HTTPClient {
90105
}
91106
}
92107

108+
/// Create HTTP cookie.
109+
///
110+
/// - parameters:
111+
/// - name: The name of the cookie.
112+
/// - value: The cookie's string value.
113+
/// - path: The cookie's path.
114+
/// - domain: The domain of the cookie, defaults to nil.
115+
/// - expires: The cookie's expiration date, defaults to nil.
116+
/// - maxAge: The cookie's age in seconds, defaults to nil.
117+
/// - httpOnly: Whether this cookie should be used by HTTP servers only, defaults to false.
118+
/// - secure: Whether this cookie should only be sent using secure channels, defaults to false.
93119
public init(name: String, value: String, path: String = "/", domain: String? = nil, expires: Date? = nil, maxAge: Int? = nil, httpOnly: Bool = false, secure: Bool = false) {
94120
self.name = name
95121
self.value = value
@@ -112,12 +138,13 @@ extension HTTPClient {
112138
}
113139
}
114140

115-
public extension HTTPClient.Response {
116-
internal var cookieHeaders: [HTTPHeaders.Element] {
141+
extension HTTPClient.Response {
142+
var cookieHeaders: [HTTPHeaders.Element] {
117143
return headers.filter { $0.name.lowercased() == "set-cookie" }
118144
}
119145

120-
var cookies: [HTTPClient.Cookie] {
121-
return self.cookieHeaders.compactMap { HTTPClient.Cookie(from: $0.value, defaultDomain: self.host) }
146+
/// List of HTTP cookies returned by the server.
147+
public var cookies: [HTTPClient.Cookie] {
148+
return self.cookieHeaders.compactMap { HTTPClient.Cookie(header: $0.value, defaultDomain: self.host) }
122149
}
123150
}

Sources/AsyncHTTPClient/HTTPClient.swift

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,42 @@ import NIOConcurrencyHelpers
1818
import NIOHTTP1
1919
import 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+
/// ```
2146
public 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.
258354
public 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

Comments
 (0)