Skip to content

Commit 24d8832

Browse files
committed
GH-40488: [Swift] Add simple get swift example
1 parent e006c3c commit 24d8832

4 files changed

Lines changed: 177 additions & 0 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// swift-tools-version: 6.0
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "ArrowGet",
8+
platforms: [
9+
.macOS(.v14)
10+
],
11+
dependencies: [
12+
.package(name: "Arrow", path: "vendor/Arrow"),
13+
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.3.0"),
14+
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.10.0")
15+
],
16+
targets: [
17+
// Targets are the basic building blocks of a package, defining a module or a test suite.
18+
// Targets can depend on other targets in this package and products from dependencies.
19+
.executableTarget(
20+
name: "ArrowGet",
21+
dependencies: [
22+
.product(name: "Arrow", package: "Arrow"),
23+
.product(name: "Hummingbird", package: "hummingbird"),
24+
.product(name: "Alamofire", package: "Alamofire")
25+
]
26+
),
27+
]
28+
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!---
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
20+
# HTTP GET Arrow Data: Simple Swift Client Example
21+
22+
This directory contains a minimal example of an HTTP client implemented in Swift. The client:
23+
1. Sends an HTTP GET request to a server.
24+
2. Receives an HTTP 200 response from the server, with the response body containing an Arrow IPC stream record batch.
25+
3. Prints some of the record batches attributes and data to the terminal
26+
27+
To run this example:
28+
1. download and copy Apache Arrow Swift's Arrow folder into the vendor/Arrow folder. (the dependency and location are already defined in Package.swift)
29+
2. run:
30+
31+
```sh
32+
swift run
33+
```
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
3+
4+
import Foundation
5+
import Arrow
6+
import Hummingbird
7+
import Alamofire
8+
9+
10+
func makeRecordBatch() throws -> RecordBatch {
11+
let doubleBuilder: NumberArrayBuilder<Double> = try ArrowArrayBuilders.loadNumberArrayBuilder()
12+
doubleBuilder.append(11.11)
13+
doubleBuilder.append(22.22)
14+
doubleBuilder.append(33.33)
15+
doubleBuilder.append(44.44)
16+
let stringBuilder = try ArrowArrayBuilders.loadStringArrayBuilder()
17+
stringBuilder.append("test10")
18+
stringBuilder.append("test22")
19+
stringBuilder.append("test33")
20+
stringBuilder.append("test44")
21+
let date32Builder = try ArrowArrayBuilders.loadDate32ArrayBuilder()
22+
let date2 = Date(timeIntervalSinceReferenceDate: 86400 * 1)
23+
let date1 = Date(timeIntervalSinceReferenceDate: 86400 * 5000 + 352)
24+
date32Builder.append(date1)
25+
date32Builder.append(date2)
26+
date32Builder.append(date1)
27+
date32Builder.append(date2)
28+
let doubleHolder = ArrowArrayHolderImpl(try doubleBuilder.finish())
29+
let stringHolder = ArrowArrayHolderImpl(try stringBuilder.finish())
30+
let date32Holder = ArrowArrayHolderImpl(try date32Builder.finish())
31+
let result = RecordBatch.Builder()
32+
.addColumn("col1", arrowArray: doubleHolder)
33+
.addColumn("col2", arrowArray: stringHolder)
34+
.addColumn("col3", arrowArray: date32Holder)
35+
.finish()
36+
switch result {
37+
case .success(let recordBatch):
38+
return recordBatch
39+
case .failure(let error):
40+
throw error
41+
}
42+
}
43+
44+
final class HttpTest {
45+
var appStarted = false
46+
var done = false
47+
var stopFunc: (() -> Void)?
48+
49+
func run() throws {
50+
_ = Task {
51+
let router = Router()
52+
router.get("/") { request, _ -> ByteBuffer in
53+
let recordBatch = try makeRecordBatch()
54+
let arrowWriter = ArrowWriter()
55+
let writerInfo = ArrowWriter.Info(.recordbatch, schema: recordBatch.schema, batches: [recordBatch])
56+
switch arrowWriter.toStream(writerInfo) {
57+
case .success(let writeData):
58+
return ByteBuffer(data: writeData)
59+
case.failure(let error):
60+
throw error
61+
}
62+
}
63+
64+
// create application using router
65+
let app = Application(
66+
router: router,
67+
configuration: .init(address: .hostname("127.0.0.1", port: 8081))
68+
)
69+
70+
try await app.runService()
71+
return ByteBuffer()
72+
}
73+
74+
let sem = DispatchSemaphore(value: 0)
75+
let url = URL(string: "http://127.0.0.1:8081")!
76+
let task = URLSession.shared.dataTask(with: url) { data, response, error in
77+
defer {sem.signal()}
78+
if let writeData = data {
79+
let arrowReader = ArrowReader()
80+
switch arrowReader.fromStream(writeData) {
81+
case .success(let result):
82+
let recordBatches = result.batches
83+
print("recordBatch columns: \(recordBatches.count)")
84+
let rb = recordBatches[0]
85+
print("recordBatch columns: \(rb.columnCount)")
86+
for (idx, column) in rb.columns.enumerated() {
87+
print("col \(idx)")
88+
let array = column.array
89+
for idx in 0..<array.length {
90+
print("data col \(idx): \(String(describing:array.asAny(idx)))")
91+
}
92+
}
93+
case.failure(let error):
94+
print("error: \(error)")
95+
}
96+
} else if let error = error {
97+
print("HTTP Request Failed \(error)")
98+
}
99+
}
100+
101+
task.resume()
102+
_ = sem.wait(timeout: .distantFuture)
103+
print("done running http server")
104+
}
105+
}
106+
107+
var httpTest = HttpTest()
108+
try httpTest.run()

0 commit comments

Comments
 (0)