Skip to content

Commit 5ead318

Browse files
authored
Add async/await examples (#553)
1 parent c4a63c1 commit 5ead318

File tree

5 files changed

+227
-0
lines changed

5 files changed

+227
-0
lines changed

Examples/GetHTML/GetHTML.swift

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import AsyncHTTPClient
16+
import NIOCore
17+
18+
@main
19+
struct GetHTML {
20+
static func main() async throws {
21+
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
22+
do {
23+
let request = HTTPClientRequest(url: "https://apple.com")
24+
let response = try await httpClient.execute(request, timeout: .seconds(30))
25+
print("HTTP head", response)
26+
let body = try await response.body.collect(upTo: 1024 * 1024) // 1 MB
27+
print(String(buffer: body))
28+
} catch {
29+
print("request failed:", error)
30+
}
31+
// it is important to shutdown the httpClient after all requests are done, even if one failed
32+
try await httpClient.shutdown()
33+
}
34+
}

Examples/GetJSON/GetJSON.swift

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import AsyncHTTPClient
16+
import Foundation
17+
import NIOCore
18+
import NIOFoundationCompat
19+
20+
struct Comic: Codable {
21+
var num: Int
22+
var title: String
23+
var day: String
24+
var month: String
25+
var year: String
26+
var img: String
27+
var alt: String
28+
var news: String
29+
var link: String
30+
var transcript: String
31+
}
32+
33+
@main
34+
struct GetJSON {
35+
static func main() async throws {
36+
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
37+
do {
38+
let request = HTTPClientRequest(url: "https://xkcd.com/info.0.json")
39+
let response = try await httpClient.execute(request, timeout: .seconds(30))
40+
print("HTTP head", response)
41+
let body = try await response.body.collect(upTo: 1024 * 1024) // 1 MB
42+
// we use an overload defined in `NIOFoundationCompat` for `decode(_:from:)` to
43+
// efficiently decode from a `ByteBuffer`
44+
let comic = try JSONDecoder().decode(Comic.self, from: body)
45+
dump(comic)
46+
} catch {
47+
print("request failed:", error)
48+
}
49+
// it is important to shutdown the httpClient after all requests are done, even if one failed
50+
try await httpClient.shutdown()
51+
}
52+
}

Examples/Package.swift

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// swift-tools-version:5.5
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// This source file is part of the AsyncHTTPClient open source project
5+
//
6+
// Copyright (c) 2018-2022 Apple Inc. and the AsyncHTTPClient project authors
7+
// Licensed under Apache License v2.0
8+
//
9+
// See LICENSE.txt for license information
10+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
11+
//
12+
// SPDX-License-Identifier: Apache-2.0
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
import PackageDescription
17+
18+
let package = Package(
19+
name: "async-http-client-examples",
20+
platforms: [
21+
.macOS(.v10_15),
22+
.iOS(.v13),
23+
.tvOS(.v13),
24+
.watchOS(.v6),
25+
],
26+
products: [
27+
.executable(name: "GetHTML", targets: ["GetHTML"]),
28+
.executable(name: "GetJSON", targets: ["GetJSON"]),
29+
.executable(name: "StreamingByteCounter", targets: ["StreamingByteCounter"]),
30+
],
31+
dependencies: [
32+
.package(url: "https://github.com/apple/swift-nio.git", .branch("main")),
33+
34+
// in real-world projects this would be
35+
// .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0")
36+
.package(name: "async-http-client", path: "../"),
37+
],
38+
targets: [
39+
// MARK: - Examples
40+
41+
.executableTarget(
42+
name: "GetHTML",
43+
dependencies: [
44+
.product(name: "AsyncHTTPClient", package: "async-http-client"),
45+
.product(name: "NIOCore", package: "swift-nio"),
46+
], path: "GetHTML"
47+
),
48+
.executableTarget(
49+
name: "GetJSON",
50+
dependencies: [
51+
.product(name: "AsyncHTTPClient", package: "async-http-client"),
52+
.product(name: "NIOCore", package: "swift-nio"),
53+
.product(name: "NIOFoundationCompat", package: "swift-nio"),
54+
], path: "GetJSON"
55+
),
56+
.executableTarget(
57+
name: "StreamingByteCounter",
58+
dependencies: [
59+
.product(name: "AsyncHTTPClient", package: "async-http-client"),
60+
.product(name: "NIOCore", package: "swift-nio"),
61+
], path: "StreamingByteCounter"
62+
),
63+
]
64+
)

Examples/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Examples
2+
This folder includes a couple of Examples for `AsyncHTTPClient`.
3+
You can run them by opening the `Package.swift` in this folder through Xcode.
4+
In Xcode you can then select the scheme for the example you want run e.g. `GetHTML`.
5+
6+
You can also run the examples from the command line by executing the follow command in this folder:
7+
```
8+
swift run GetHTML
9+
```
10+
To run other examples you can just replace `GetHTML` with the name of the example you want to run.
11+
12+
## [GetHTML](./GetHTML/GetHTML.swift)
13+
14+
This examples sends a HTTP GET request to `https://apple.com/` and first `await`s and `print`s the HTTP Response Head.
15+
Afterwards it buffers the full response body in memory and prints the response as a `String`.
16+
17+
## [GetJSON](./GetJSON/GetJSON.swift)
18+
19+
This examples sends a HTTP GET request to `https://xkcd.com/info.0.json` and first `await`s and `print`s the HTTP Response Head.
20+
Afterwards it buffers the full response body in memory, decodes the buffer using a `JSONDecoder` and `dump`s the decoded response.
21+
22+
## [StreamingByteCounter](./StreamingByteCounter/StreamingByteCounter.swift)
23+
24+
This examples sends a HTTP GET request to `https://apple.com/` and first `await`s and `print`s the HTTP Response Head.
25+
Afterwards it asynchronously iterates over all body fragments, counts the received bytes and prints a progress indicator (if the server send a content-length header).
26+
At the end the total received bytes are printed.
27+
Note that we drop all received fragment and therefore do **not** buffer the whole response body in-memory.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import AsyncHTTPClient
16+
import NIOCore
17+
18+
@main
19+
struct StreamingByteCounter {
20+
static func main() async throws {
21+
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
22+
do {
23+
let request = HTTPClientRequest(url: "https://apple.com")
24+
let response = try await httpClient.execute(request, timeout: .seconds(30))
25+
print("HTTP head", response)
26+
27+
// if defined, the content-length headers announces the size of the body
28+
let expectedBytes = response.headers.first(name: "content-length").flatMap(Int.init)
29+
30+
var receivedBytes = 0
31+
// asynchronously iterates over all body fragments
32+
// this loop will automatically propagate backpressure correctly
33+
for try await buffer in response.body {
34+
// For this example, we are just interested in the size of the fragment
35+
receivedBytes += buffer.readableBytes
36+
37+
if let expectedBytes = expectedBytes {
38+
// if the body size is known, we calculate a progress indicator
39+
let progress = Double(receivedBytes) / Double(expectedBytes)
40+
print("progress: \(Int(progress * 100))%")
41+
}
42+
}
43+
print("did receive \(receivedBytes) bytes")
44+
} catch {
45+
print("request failed:", error)
46+
}
47+
// it is important to shutdown the httpClient after all requests are done, even if one failed
48+
try await httpClient.shutdown()
49+
}
50+
}

0 commit comments

Comments
 (0)