From 4a7e4521319031f6065e7d2568bee7fc07f2fd36 Mon Sep 17 00:00:00 2001 From: iwa Date: Fri, 25 Jul 2025 23:34:50 +0200 Subject: [PATCH 1/4] feat: add http examples for POST PUT DELETE --- Examples/DeleteJSON/DeleteJSON.swift | 23 +++++++++++++++++++ Examples/Package.swift | 30 ++++++++++++++++++++++++ Examples/PostJSON/PostJSON.swift | 34 ++++++++++++++++++++++++++++ Examples/PutJSON/PutJSON.swift | 34 ++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 Examples/DeleteJSON/DeleteJSON.swift create mode 100644 Examples/PostJSON/PostJSON.swift create mode 100644 Examples/PutJSON/PutJSON.swift diff --git a/Examples/DeleteJSON/DeleteJSON.swift b/Examples/DeleteJSON/DeleteJSON.swift new file mode 100644 index 000000000..fa36b7c51 --- /dev/null +++ b/Examples/DeleteJSON/DeleteJSON.swift @@ -0,0 +1,23 @@ +import AsyncHTTPClient +import Foundation +import NIOCore +import NIOFoundationCompat + +@main +struct PostJSON { + static func main() async throws { + let httpClient = HTTPClient(eventLoopGroupProvider: .singleton) + + do { + var request = HTTPClientRequest(url: "http://localhost:8080/todos/1)") + request.method = .DELETE + + let response = try await httpClient.execute(request, timeout: .seconds(30)) + print("HTTP head", response) + } catch { + print("request failed:", error) + } + // it is important to shutdown the httpClient after all requests are done, even if one failed + try await httpClient.shutdown() + } +} diff --git a/Examples/Package.swift b/Examples/Package.swift index 9986b17b5..7c7a3a937 100644 --- a/Examples/Package.swift +++ b/Examples/Package.swift @@ -26,6 +26,9 @@ let package = Package( products: [ .executable(name: "GetHTML", targets: ["GetHTML"]), .executable(name: "GetJSON", targets: ["GetJSON"]), + .executable(name: "PostJSON", targets: ["PostJSON"]), + .executable(name: "PutJSON", targets: ["PutJSON"]), + .executable(name: "DeleteJSON", targets: ["DeleteJSON"]), .executable(name: "StreamingByteCounter", targets: ["StreamingByteCounter"]), ], dependencies: [ @@ -55,6 +58,33 @@ let package = Package( ], path: "GetJSON" ), + .executableTarget( + name: "PostJSON", + dependencies: [ + .product(name: "AsyncHTTPClient", package: "async-http-client"), + .product(name: "NIOCore", package: "swift-nio"), + .product(name: "NIOFoundationCompat", package: "swift-nio"), + ], + path: "PostJSON" + ), + .executableTarget( + name: "PutJSON", + dependencies: [ + .product(name: "AsyncHTTPClient", package: "async-http-client"), + .product(name: "NIOCore", package: "swift-nio"), + .product(name: "NIOFoundationCompat", package: "swift-nio"), + ], + path: "PutJSON" + ), + .executableTarget( + name: "DeleteJSON", + dependencies: [ + .product(name: "AsyncHTTPClient", package: "async-http-client"), + .product(name: "NIOCore", package: "swift-nio"), + .product(name: "NIOFoundationCompat", package: "swift-nio"), + ], + path: "DeleteJSON" + ), .executableTarget( name: "StreamingByteCounter", dependencies: [ diff --git a/Examples/PostJSON/PostJSON.swift b/Examples/PostJSON/PostJSON.swift new file mode 100644 index 000000000..77e892f28 --- /dev/null +++ b/Examples/PostJSON/PostJSON.swift @@ -0,0 +1,34 @@ +import AsyncHTTPClient +import Foundation +import NIOCore +import NIOFoundationCompat + +struct Todo: Codable { + var id: Int + var name: String + var completed: Bool +} + +@main +struct PostJSON { + static func main() async throws { + let httpClient = HTTPClient(eventLoopGroupProvider: .singleton) + let payload = Todo(id: 1, name: "Test Todo", completed: false) + + do { + let jsonData = try JSONEncoder().encode(payload) + + var request = HTTPClientRequest(url: "http://localhost:8080/todos") + request.method = .POST + request.headers.add(name: "Content-Type", value: "application/json") + request.body = .bytes(jsonData) + + let response = try await httpClient.execute(request, timeout: .seconds(30)) + print("HTTP head", response) + } catch { + print("request failed:", error) + } + // it is important to shutdown the httpClient after all requests are done, even if one failed + try await httpClient.shutdown() + } +} diff --git a/Examples/PutJSON/PutJSON.swift b/Examples/PutJSON/PutJSON.swift new file mode 100644 index 000000000..8fbaaf255 --- /dev/null +++ b/Examples/PutJSON/PutJSON.swift @@ -0,0 +1,34 @@ +import AsyncHTTPClient +import Foundation +import NIOCore +import NIOFoundationCompat + +struct Todo: Codable { + var id: Int + var name: String + var completed: Bool +} + +@main +struct PostJSON { + static func main() async throws { + let httpClient = HTTPClient(eventLoopGroupProvider: .singleton) + let payload = Todo(id: 1, name: "Test Todo", completed: true) + + do { + let jsonData = try JSONEncoder().encode(payload) + + var request = HTTPClientRequest(url: "http://localhost:8080/todos/\(payload.id)") + request.method = .PUT + request.headers.add(name: "Content-Type", value: "application/json") + request.body = .bytes(jsonData) + + let response = try await httpClient.execute(request, timeout: .seconds(30)) + print("HTTP head", response) + } catch { + print("request failed:", error) + } + // it is important to shutdown the httpClient after all requests are done, even if one failed + try await httpClient.shutdown() + } +} From fe3f0f625dd0b60b76475f338941dfccd21b7cc0 Mon Sep 17 00:00:00 2001 From: iwa Date: Mon, 28 Jul 2025 23:50:19 +0200 Subject: [PATCH 2/4] refactor: fix bad struct class name for delete json example --- Examples/DeleteJSON/DeleteJSON.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/DeleteJSON/DeleteJSON.swift b/Examples/DeleteJSON/DeleteJSON.swift index fa36b7c51..9bdb0b4bd 100644 --- a/Examples/DeleteJSON/DeleteJSON.swift +++ b/Examples/DeleteJSON/DeleteJSON.swift @@ -4,7 +4,7 @@ import NIOCore import NIOFoundationCompat @main -struct PostJSON { +struct DeleteJSON { static func main() async throws { let httpClient = HTTPClient(eventLoopGroupProvider: .singleton) From a55b4d92244a572b508f678afc6194c00f999dee Mon Sep 17 00:00:00 2001 From: iwa Date: Tue, 29 Jul 2025 00:10:05 +0200 Subject: [PATCH 3/4] refactor: use shared http client for delete req --- Examples/DeleteJSON/DeleteJSON.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Examples/DeleteJSON/DeleteJSON.swift b/Examples/DeleteJSON/DeleteJSON.swift index 9bdb0b4bd..33587809f 100644 --- a/Examples/DeleteJSON/DeleteJSON.swift +++ b/Examples/DeleteJSON/DeleteJSON.swift @@ -6,7 +6,7 @@ import NIOFoundationCompat @main struct DeleteJSON { static func main() async throws { - let httpClient = HTTPClient(eventLoopGroupProvider: .singleton) + let httpClient = HTTPClient.shared do { var request = HTTPClientRequest(url: "http://localhost:8080/todos/1)") @@ -17,7 +17,5 @@ struct DeleteJSON { } catch { print("request failed:", error) } - // it is important to shutdown the httpClient after all requests are done, even if one failed - try await httpClient.shutdown() } } From 387bc3eaee2237f3637ea7da4b20f4c8c224c903 Mon Sep 17 00:00:00 2001 From: iwa Date: Tue, 29 Jul 2025 00:38:46 +0200 Subject: [PATCH 4/4] feat: use jsonplaceholder api instead of local api --- Examples/DeleteJSON/DeleteJSON.swift | 2 +- Examples/PostJSON/PostJSON.swift | 9 +++++---- Examples/PutJSON/PutJSON.swift | 7 ++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Examples/DeleteJSON/DeleteJSON.swift b/Examples/DeleteJSON/DeleteJSON.swift index 33587809f..1b92b4ba5 100644 --- a/Examples/DeleteJSON/DeleteJSON.swift +++ b/Examples/DeleteJSON/DeleteJSON.swift @@ -9,7 +9,7 @@ struct DeleteJSON { let httpClient = HTTPClient.shared do { - var request = HTTPClientRequest(url: "http://localhost:8080/todos/1)") + var request = HTTPClientRequest(url: "https://jsonplaceholder.typicode.com/todos/1") request.method = .DELETE let response = try await httpClient.execute(request, timeout: .seconds(30)) diff --git a/Examples/PostJSON/PostJSON.swift b/Examples/PostJSON/PostJSON.swift index 77e892f28..3fc652222 100644 --- a/Examples/PostJSON/PostJSON.swift +++ b/Examples/PostJSON/PostJSON.swift @@ -4,8 +4,9 @@ import NIOCore import NIOFoundationCompat struct Todo: Codable { - var id: Int - var name: String + var id: Int? + var userId: Int + var title: String var completed: Bool } @@ -13,12 +14,12 @@ struct Todo: Codable { struct PostJSON { static func main() async throws { let httpClient = HTTPClient(eventLoopGroupProvider: .singleton) - let payload = Todo(id: 1, name: "Test Todo", completed: false) + let payload = Todo(userId: 1, title: "Test Todo", completed: false) do { let jsonData = try JSONEncoder().encode(payload) - var request = HTTPClientRequest(url: "http://localhost:8080/todos") + var request = HTTPClientRequest(url: "https://jsonplaceholder.typicode.com/todos") request.method = .POST request.headers.add(name: "Content-Type", value: "application/json") request.body = .bytes(jsonData) diff --git a/Examples/PutJSON/PutJSON.swift b/Examples/PutJSON/PutJSON.swift index 8fbaaf255..86234d5c2 100644 --- a/Examples/PutJSON/PutJSON.swift +++ b/Examples/PutJSON/PutJSON.swift @@ -5,7 +5,8 @@ import NIOFoundationCompat struct Todo: Codable { var id: Int - var name: String + var userId: Int + var title: String var completed: Bool } @@ -13,12 +14,12 @@ struct Todo: Codable { struct PostJSON { static func main() async throws { let httpClient = HTTPClient(eventLoopGroupProvider: .singleton) - let payload = Todo(id: 1, name: "Test Todo", completed: true) + let payload = Todo(id: 1, userId: 1, title: "Test Todo", completed: false) do { let jsonData = try JSONEncoder().encode(payload) - var request = HTTPClientRequest(url: "http://localhost:8080/todos/\(payload.id)") + var request = HTTPClientRequest(url: "https://jsonplaceholder.typicode.com/todos/\(payload.id)") request.method = .PUT request.headers.add(name: "Content-Type", value: "application/json") request.body = .bytes(jsonData)