Skip to content

Commit 4a40389

Browse files
committed
Add a couple more convenience APIs and rework encode method
1 parent f15c918 commit 4a40389

File tree

3 files changed

+68
-46
lines changed

3 files changed

+68
-46
lines changed

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A customizable Swift `Encoder` that encodes instances of data types as URL query
88

99
```swift
1010
let encoder = URLQueryEncoder()
11-
encoder.encode(["id": id])
11+
encoder.encode(id, forKey: "id")
1212

1313
print(encoder.queryItems)
1414
// [URLQueryItem(name: "id", value: "5")]
@@ -19,7 +19,7 @@ print(encoder.queryItems)
1919
```swift
2020
let ids = [3, 4, 5]
2121
let encoder = URLQueryEncoder()
22-
encoder.encode(["id": ids])
22+
encoder.encode(ids, forKey: "id")
2323

2424
// Query: "id=3&id=4&id=5"
2525
```
@@ -29,7 +29,7 @@ With an `explode` option disabled:
2929
```swift
3030
let ids = [3, 4, 5]
3131
let encoder = URLQueryEncoder()
32-
encoder.encode(["id": ids], explode: false)
32+
encoder.encode(ids, forKey: "id", explode: false)
3333

3434
// Query: "id=3,4,5"
3535
```
@@ -39,7 +39,7 @@ With an `explode` option disabled and a custom delimiter:
3939
```swift
4040
let ids = [3, 4, 5]
4141
let encoder = URLQueryEncoder()
42-
encoder.encode(["id": ids], explode: false, delimiter: "|")
42+
encoder.encode(ids, forKey: "id", explode: false, delimeter: "|")
4343

4444
// Query: "id=3|4|5"
4545
```
@@ -50,7 +50,7 @@ encoder.encode(["id": ids], explode: false, delimiter: "|")
5050
let user = User(role: "admin", name: "kean")
5151

5252
let encoder = URLQueryEncoder()
53-
encoder.encode(user)
53+
encoder.encode(user, forKey: "id")
5454

5555
// Query: "role=admin&name=kean"
5656
```
@@ -61,7 +61,7 @@ With an `explode` option disabled:
6161
let user = User(role: "admin", name: "kean")
6262

6363
let encoder = URLQueryEncoder()
64-
encoder.encode(user, explode: false)
64+
encoder.encode(user, forKey: "id", explode: false)
6565

6666
// Query: "id=role,admin,name,kean"
6767
```
@@ -72,11 +72,13 @@ As a "deep" object:
7272
let user = User(role: "admin", name: "kean")
7373

7474
let encoder = URLQueryEncoder()
75-
encoder.encode(user, isDeepObject: true)
75+
encoder.encode(user, forKey: "id", isDeepObject: true)
7676

7777
// Query: "id[role]=admin&id[name]=kean")"
7878
```
7979

80+
> If you are encoding a request body using URL-form encoding, you can use a convenience `URLQueryEncoder(encoding: body` initializer.
81+
8082
## Encoding Options
8183

8284
There are two ways to change the encoding options: settings them directly on `URLQueryEncoder` instance, or passing options in each individual `encode` call. The reason it's designed this way is that in OpenAPI, each parameter can have different serialization options.
@@ -95,11 +97,12 @@ You can use `URLQueryEncoder` to encode more that one parameter are a time:
9597
let user = User(role: "admin", name: "kean")
9698
let ids = [3, 4, 5]
9799

98-
let encoder = URLQueryEncoder()
99-
encoder.encode(["ids": ids], explode: false)
100-
encoder.encode(["ids2": ids], explode: true)
101-
encoder.encode(["user": user], isDeepObject: true)
102-
encoder.encode(["id": 2])
100+
let query = URLQueryEncoder()
101+
.encode(ids, forKey: "ids", explode: false)
102+
.encode(ids, forKey: "ids2", explode: true)
103+
.encode(user, forKey: "user", isDeepObject: true)
104+
.encode(2, forKey: "id")
105+
.query
103106

104107
// Query: "ids=3,4,5&ids2=3&ids2=4&ids2=5&user[role]=admin&user[name]=kean&id=2"
105108
```

Sources/URLQueryEncoder/URLQueryEncoder.swift

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,39 @@ public final class URLQueryEncoder {
5959
}
6060

6161
public init() {}
62-
63-
public func encode(_ value: Encodable, explode: Bool? = nil, delimiter: String? = nil, isDeepObject: Bool? = nil) {
62+
63+
/// Encodes value for the given key.
64+
@discardableResult
65+
public func encode<T: Encodable>(_ value: T, forKey key: String) -> Self {
66+
encode(value, forKey: key, explode: nil, delimiter: nil, isDeepObject: nil)
67+
}
68+
69+
/// Encodes value for the given key.
70+
@discardableResult
71+
public func encode<T: Encodable>(_ value: T, forKey key: String, explode: Bool? = nil, delimiter: String? = nil, isDeepObject: Bool? = nil) -> Self {
6472
// Temporary override the settings to the duration of the call
6573
_explode = explode ?? self.explode
6674
_delimiter = delimiter ?? self.delimiter
6775
_isDeepObject = isDeepObject ?? self.isDeepObject
6876

6977
let encoder = _URLQueryEncoder(encoder: self)
7078
do {
71-
try value.encode(to: encoder)
79+
try [key: value].encode(to: encoder)
7280
} catch {
73-
// Assume that conversion to String never fails
81+
// Assume that encoding to String never fails
7482
assertionFailure("URL encoding failed with an error: \(error)")
7583
}
84+
return self
85+
}
86+
87+
public init<T: Encodable>(encoding body: T) {
88+
encode(body, forKey: "value")
89+
}
90+
91+
public static func encode<T: Encodable>(_ body: T) -> URLQueryEncoder {
92+
let encoder = URLQueryEncoder()
93+
encoder.encode(body, forKey: "value")
94+
return encoder
7695
}
7796
}
7897

Tests/URLQueryEncoderTests/URLQueryEncoderTests.swift

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class QueryEncoderTests: XCTestCase {
1414

1515
// THEN
1616
let encoder = URLQueryEncoder()
17-
encoder.encode(["id": id])
17+
encoder.encode(id, forKey: "id")
1818

1919
// THEN
2020
XCTAssertEqual(encoder.query, "id=5")
@@ -26,7 +26,7 @@ final class QueryEncoderTests: XCTestCase {
2626

2727
// WHEN
2828
let encoder = URLQueryEncoder()
29-
encoder.encode(["id": ids])
29+
encoder.encode(ids, forKey: "id")
3030

3131
// THEN
3232
XCTAssertEqual(encoder.query, "id=3&id=4&id=5")
@@ -38,24 +38,12 @@ final class QueryEncoderTests: XCTestCase {
3838

3939
// WHEN
4040
let encoder = URLQueryEncoder()
41-
encoder.encode(["id": user])
41+
encoder.encode(user, forKey: "id")
4242

4343
// THEN
4444
XCTAssertEqual(encoder.query, "role=admin&name=kean")
4545
}
46-
47-
func testStyleFormExplodeTrueObjectPassedDirectly() throws {
48-
// GIVEN
49-
let user = User(role: "admin", name: "kean")
5046

51-
// WHEN
52-
let encoder = URLQueryEncoder()
53-
encoder.encode(user)
54-
55-
// THEN
56-
XCTAssertEqual(encoder.query, "role=admin&name=kean")
57-
}
58-
5947
// MARK: Style: Form, Explode: False
6048

6149
func testStyleFormExplodeFalsePrimitive() throws {
@@ -64,7 +52,7 @@ final class QueryEncoderTests: XCTestCase {
6452

6553
// THEN
6654
let encoder = URLQueryEncoder()
67-
encoder.encode(["id": id])
55+
encoder.encode(id, forKey: "id")
6856

6957
// THEN
7058
XCTAssertEqual(encoder.query, "id=5")
@@ -77,7 +65,7 @@ final class QueryEncoderTests: XCTestCase {
7765
// WHEN
7866
let encoder = URLQueryEncoder()
7967
encoder.explode = false
80-
encoder.encode(["id": ids])
68+
encoder.encode(ids, forKey: "id")
8169

8270
// THEN
8371
XCTAssertEqual(encoder.query, "id=3,4,5")
@@ -89,7 +77,7 @@ final class QueryEncoderTests: XCTestCase {
8977

9078
// WHEN
9179
let encoder = URLQueryEncoder()
92-
encoder.encode(["id": ids], explode: false)
80+
encoder.encode(ids, forKey: "id", explode: false)
9381

9482
// THEN
9583
XCTAssertEqual(encoder.query, "id=3,4,5")
@@ -101,7 +89,7 @@ final class QueryEncoderTests: XCTestCase {
10189

10290
// WHEN
10391
let encoder = URLQueryEncoder()
104-
encoder.encode(["id": user], explode: false)
92+
encoder.encode(user, forKey: "id", explode: false)
10593

10694
// THEN
10795
XCTAssertEqual(encoder.query, "id=role,admin,name,kean")
@@ -120,7 +108,7 @@ final class QueryEncoderTests: XCTestCase {
120108
let encoder = URLQueryEncoder()
121109
encoder.explode = true
122110
encoder.delimiter = " "
123-
encoder.encode(["id": ids])
111+
encoder.encode(ids, forKey: "id")
124112

125113
// THEN
126114
XCTAssertEqual(encoder.query, "id=3&id=4&id=5")
@@ -134,7 +122,7 @@ final class QueryEncoderTests: XCTestCase {
134122
let encoder = URLQueryEncoder()
135123
encoder.explode = false
136124
encoder.delimiter = " "
137-
encoder.encode(["id": ids])
125+
encoder.encode(ids, forKey: "id")
138126

139127
// THEN
140128
XCTAssertEqual(encoder.query, "id=3 4 5")
@@ -147,7 +135,7 @@ final class QueryEncoderTests: XCTestCase {
147135

148136
// WHEN
149137
let encoder = URLQueryEncoder()
150-
encoder.encode(["id": ids], explode: false, delimiter: " ")
138+
encoder.encode(ids, forKey: "id", explode: false, delimiter: " ")
151139

152140
// THEN
153141
XCTAssertEqual(encoder.query, "id=3 4 5")
@@ -167,7 +155,7 @@ final class QueryEncoderTests: XCTestCase {
167155
let encoder = URLQueryEncoder()
168156
encoder.explode = true
169157
encoder.delimiter = "|"
170-
encoder.encode(["id": ids])
158+
encoder.encode(ids, forKey: "id")
171159

172160
// THEN
173161
XCTAssertEqual(encoder.query, "id=3&id=4&id=5")
@@ -181,7 +169,7 @@ final class QueryEncoderTests: XCTestCase {
181169
let encoder = URLQueryEncoder()
182170
encoder.explode = false
183171
encoder.delimiter = "|"
184-
encoder.encode(["id": ids])
172+
encoder.encode(ids, forKey: "id")
185173

186174
// THEN
187175
XCTAssertEqual(encoder.query, "id=3|4|5")
@@ -198,7 +186,7 @@ final class QueryEncoderTests: XCTestCase {
198186
let encoder = URLQueryEncoder()
199187
encoder.explode = true
200188
encoder.isDeepObject = true
201-
encoder.encode(["id": user])
189+
encoder.encode(user, forKey: "id")
202190

203191
// THEN
204192
XCTAssertEqual(encoder.query, "id[role]=admin&id[name]=kean")
@@ -214,10 +202,10 @@ final class QueryEncoderTests: XCTestCase {
214202

215203
// WHEN
216204
let encoder = URLQueryEncoder()
217-
encoder.encode(["ids": ids], explode: false)
218-
encoder.encode(["ids2": ids], explode: true)
219-
encoder.encode(["user": user], isDeepObject: true)
220-
encoder.encode(["id": 2])
205+
encoder.encode(ids, forKey: "ids", explode: false)
206+
encoder.encode(ids, forKey: "ids2")
207+
encoder.encode(user, forKey: "user", isDeepObject: true)
208+
encoder.encode(2, forKey: "id", explode: false)
221209

222210
// THEN
223211
XCTAssertEqual(encoder.query, "ids=3,4,5&ids2=3&ids2=4&ids2=5&user[role]=admin&user[name]=kean&id=2")
@@ -231,11 +219,23 @@ final class QueryEncoderTests: XCTestCase {
231219

232220
// THEN
233221
let encoder = URLQueryEncoder()
234-
encoder.encode(["id": id])
222+
encoder.encode(id, forKey: "id")
235223

236224
// THEN
237225
XCTAssertTrue(encoder.queryItems.isEmpty)
238226
}
227+
228+
// MARK: Encoding Objects (Body)
229+
230+
func testEncodingBody() {
231+
// GIVEN
232+
let user = User(role: "admin", name: "kean")
233+
234+
// THEN
235+
let query = URLQueryEncoder(encoding: user).percentEncodedQuery
236+
237+
XCTAssertEqual(query, "role=admin&name=kean")
238+
}
239239
}
240240

241241
private struct User: Encodable {

0 commit comments

Comments
 (0)