Skip to content

Commit 2ec7957

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

File tree

4 files changed

+174
-0
lines changed

4 files changed

+174
-0
lines changed
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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
],
15+
targets: [
16+
// Targets are the basic building blocks of a package, defining a module or a test suite.
17+
// Targets can depend on other targets in this package and products from dependencies.
18+
.executableTarget(
19+
name: "ArrowGet",
20+
dependencies: [
21+
.product(name: "Arrow", package: "Arrow"),
22+
.product(name: "Hummingbird", package: "hummingbird"),
23+
]
24+
),
25+
]
26+
)
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: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
3+
4+
import Foundation
5+
import Arrow
6+
import Hummingbird
7+
8+
9+
func makeRecordBatch() throws -> RecordBatch {
10+
let doubleBuilder: NumberArrayBuilder<Double> = try ArrowArrayBuilders.loadNumberArrayBuilder()
11+
doubleBuilder.append(11.11)
12+
doubleBuilder.append(22.22)
13+
doubleBuilder.append(33.33)
14+
doubleBuilder.append(44.44)
15+
let stringBuilder = try ArrowArrayBuilders.loadStringArrayBuilder()
16+
stringBuilder.append("test10")
17+
stringBuilder.append("test22")
18+
stringBuilder.append("test33")
19+
stringBuilder.append("test44")
20+
let date32Builder = try ArrowArrayBuilders.loadDate32ArrayBuilder()
21+
let date2 = Date(timeIntervalSinceReferenceDate: 86400 * 1)
22+
let date1 = Date(timeIntervalSinceReferenceDate: 86400 * 5000 + 352)
23+
date32Builder.append(date1)
24+
date32Builder.append(date2)
25+
date32Builder.append(date1)
26+
date32Builder.append(date2)
27+
let doubleHolder = ArrowArrayHolderImpl(try doubleBuilder.finish())
28+
let stringHolder = ArrowArrayHolderImpl(try stringBuilder.finish())
29+
let date32Holder = ArrowArrayHolderImpl(try date32Builder.finish())
30+
let result = RecordBatch.Builder()
31+
.addColumn("col1", arrowArray: doubleHolder)
32+
.addColumn("col2", arrowArray: stringHolder)
33+
.addColumn("col3", arrowArray: date32Holder)
34+
.finish()
35+
switch result {
36+
case .success(let recordBatch):
37+
return recordBatch
38+
case .failure(let error):
39+
throw error
40+
}
41+
}
42+
43+
final class HttpTest {
44+
var appStarted = false
45+
var done = false
46+
var stopFunc: (() -> Void)?
47+
48+
func run() throws {
49+
_ = Task {
50+
let router = Router()
51+
router.get("/") { request, _ -> ByteBuffer in
52+
let recordBatch = try makeRecordBatch()
53+
let arrowWriter = ArrowWriter()
54+
let writerInfo = ArrowWriter.Info(.recordbatch, schema: recordBatch.schema, batches: [recordBatch])
55+
switch arrowWriter.toStream(writerInfo) {
56+
case .success(let writeData):
57+
return ByteBuffer(data: writeData)
58+
case.failure(let error):
59+
throw error
60+
}
61+
}
62+
63+
// create application using router
64+
let app = Application(
65+
router: router,
66+
configuration: .init(address: .hostname("127.0.0.1", port: 8081))
67+
)
68+
69+
try await app.runService()
70+
return ByteBuffer()
71+
}
72+
73+
let sem = DispatchSemaphore(value: 0)
74+
let url = URL(string: "http://127.0.0.1:8081")!
75+
let task = URLSession.shared.dataTask(with: url) { data, response, error in
76+
defer {sem.signal()}
77+
if let writeData = data {
78+
let arrowReader = ArrowReader()
79+
switch arrowReader.fromStream(writeData) {
80+
case .success(let result):
81+
let recordBatches = result.batches
82+
print("recordBatch columns: \(recordBatches.count)")
83+
let rb = recordBatches[0]
84+
print("recordBatch columns: \(rb.columnCount)")
85+
for (idx, column) in rb.columns.enumerated() {
86+
print("col \(idx)")
87+
let array = column.array
88+
for idx in 0..<array.length {
89+
print("data col \(idx): \(String(describing:array.asAny(idx)))")
90+
}
91+
}
92+
case.failure(let error):
93+
print("error: \(error)")
94+
}
95+
} else if let error = error {
96+
print("HTTP Request Failed \(error)")
97+
}
98+
}
99+
100+
task.resume()
101+
_ = sem.wait(timeout: .distantFuture)
102+
print("done running http server")
103+
}
104+
}
105+
106+
var httpTest = HttpTest()
107+
try httpTest.run()

0 commit comments

Comments
 (0)