Skip to content

Commit 10fa1d8

Browse files
committed
fix: URL appending + tests
1 parent 58c68e9 commit 10fa1d8

3 files changed

Lines changed: 139 additions & 1 deletion

File tree

Sources/GoodNetworking/Models/Endpoint.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ public extension Endpoint {
5050
let path = await path.resolveUrl()
5151

5252
guard let baseUrl, let path else { return nil }
53-
return baseUrl.appendingPathComponent(path.absoluteString)
53+
54+
// merge URLs as strings to avoid URL escaping
55+
return URL(baseUrl.absoluteString + path.absoluteString)
5456
}
5557

5658
}

Sources/GoodNetworking/Models/EndpointBuilder.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ public extension EndpointBuilder {
6868
return self
6969
}
7070

71+
func query(_ items: URLQueryItem...) -> Self {
72+
assertBothQueryAndBodyUsage()
73+
self.parameters = .query(items)
74+
return self
75+
}
76+
7177
func query(_ items: [URLQueryItem]) -> Self {
7278
assertBothQueryAndBodyUsage()
7379
self.parameters = .query(items)

Tests/GoodNetworkingTests/NetworkSessionTests.swift

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,134 @@
66
//
77

88
@testable import GoodNetworking
9+
import Testing
10+
import Foundation
11+
import Sextant
12+
import Hitch
913

14+
let session = NetworkSession(baseUrl: "https://dummyjson.com")
15+
16+
// MARK: - Decoding
17+
18+
@Test func decodeDynamicPosts() async throws {
19+
let responseData = try await session.get("/products?limit=1000") as Data
20+
21+
print(responseData.count)
22+
23+
measure {
24+
let jsonResponse = JSON(responseData)
25+
print(jsonResponse.products[100].title.string as Any)
26+
print(jsonResponse.products[100]["description"].string as Any)
27+
print(jsonResponse.products[100].price.double as Any)
28+
print(jsonResponse.products[100].reviews.array?.first?.comment.string as Any)
29+
print(jsonResponse.products[100].images.array?.first?.string as Any)
30+
}
31+
32+
measure {
33+
let structResponse = try? JSONDecoder().decode(ProductsResponse.self, from: responseData)
34+
print(structResponse?.products[100].title as Any)
35+
print(structResponse?.products[100].description as Any)
36+
print(structResponse?.products[100].price as Any)
37+
print(structResponse?.products[100].reviews?.first?.comment as Any)
38+
print(structResponse?.products[100].images?.first as Any)
39+
}
40+
41+
// measure {
42+
// let results = Sextant.shared.query(responseData, values: Hitch(string: "$.products..[?(@.price>10)]..['title', 'description', 'price']")) as [String]?
43+
// print(results as Any)
44+
// }
45+
46+
}
47+
48+
func measure(_ block: () -> ()) {
49+
var duration: UInt64 = 0
50+
for _ in 0..<50 {
51+
let startTime: UInt64 = mach_absolute_time()
52+
block()
53+
let finishTime: UInt64 = mach_absolute_time()
54+
let timeDelta = (finishTime - startTime) / 1000
55+
duration += timeDelta
56+
}
57+
58+
let averageDuration = duration / 50
59+
print(averageDuration, "us")
60+
}
61+
62+
struct ProductsResponse: Decodable {
63+
64+
struct Product: Decodable {
65+
let id: Int
66+
let title: String?
67+
let description: String?
68+
let category: String?
69+
let price: Double?
70+
let discountPercentage: Double?
71+
let rating: Double?
72+
let stock: Int?
73+
let tags: [String]?
74+
let brand: String?
75+
let sku: String?
76+
let weight: Double?
77+
let dimensions: Dimensions?
78+
let warrantyInformation: String?
79+
let shippingInformation: String?
80+
let availabilityStatus: String?
81+
let reviews: [Review]?
82+
let returnPolicy: String?
83+
let minimumOrderQuantity: Int?
84+
let meta: Meta?
85+
let images: [String]?
86+
let thumbnail: String?
87+
}
88+
89+
struct Dimensions: Decodable {
90+
let width: Double?
91+
let height: Double?
92+
let depth: Double?
93+
}
94+
95+
struct Review: Decodable {
96+
let rating: Int?
97+
let comment: String?
98+
let date: String?
99+
let reviewerName: String?
100+
let reviewerEmail: String?
101+
}
102+
103+
struct Meta: Decodable {
104+
let createdAt: String?
105+
let updatedAt: String?
106+
let barcode: String?
107+
let qrCode: String?
108+
}
109+
110+
let products: [Product]
111+
112+
}
113+
114+
// MARK: - Encoding
115+
116+
@Test func encodeDynamicJSON() async throws {
117+
let newUser = NewUserRequest(
118+
name: "Alice",
119+
email: "alice@example.com",
120+
age: 30
121+
)
122+
123+
let newUserJson = [
124+
"name": "Alice",
125+
"email": "alice@example.com",
126+
"age": 30
127+
] as JSON
128+
129+
_ = try await session.post("/users", newUser) as JSON
130+
_ = try await session.post("/users", newUserJson) as JSON
131+
}
132+
133+
struct NewUserRequest: Encodable {
134+
135+
let name: String
136+
let email: String
137+
let age: Int
138+
139+
}

0 commit comments

Comments
 (0)