Skip to content

Commit f392789

Browse files
committed
Document JSON coder extensions in related article
1 parent 49dc8d5 commit f392789

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

Sources/HandySwift/Extensions/JSONDecoderExt.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extension JSONDecoder {
1818
/// let user = try JSONDecoder.snakeCase.decode(User.self, from: jsonData)
1919
/// // Results in: User(firstName: "John", lastName: "Doe")
2020
/// ```
21-
static var snakeCase: JSONDecoder {
21+
public static var snakeCase: JSONDecoder {
2222
let decoder = JSONDecoder()
2323
decoder.keyDecodingStrategy = .convertFromSnakeCase
2424
return decoder

Sources/HandySwift/Extensions/JSONEncoderExt.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extension JSONEncoder {
1313
/// let jsonData = try JSONEncoder.snakeCase.encode(user)
1414
/// // Results in: {"first_name": "John", "last_name": "Doe"}
1515
/// ```
16-
static var snakeCase: JSONEncoder {
16+
public static var snakeCase: JSONEncoder {
1717
let encoder = JSONEncoder()
1818
encoder.keyEncodingStrategy = .convertToSnakeCase
1919
return encoder

Sources/HandySwift/HandySwift.docc/Essentials/Extensions.md

+32
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,33 @@ Text(fractionCompleted.rounded(fractionDigits: 2).formatted(.percent))
113113

114114
> Note: There's also a mutating ``Swift/Double/round(fractionDigits:rule:)`` functions if you want to change a variable in-place.
115115
116+
#### JSON Snake Case Conversion
117+
118+
Many APIs return responses using snake_case naming (e.g., `first_name`, `date_of_birth`), while Swift uses camelCase by convention (e.g., `firstName`, `dateOfBirth`). Converting between these naming conventions is a very common need when working with JSON APIs:
119+
120+
```swift
121+
struct User: Codable {
122+
let firstName: String
123+
let lastName: String
124+
let dateOfBirth: Date
125+
let profileImageUrl: String?
126+
}
127+
128+
func fetchUser(id: String) async throws -> User {
129+
let (data, _) = try await URLSession.shared.data(from: apiURL)
130+
131+
// Automatically converts snake_case JSON to camelCase Swift properties
132+
return try JSONDecoder.snakeCase.decode(User.self, from: data)
133+
134+
// Without this extension we'd need this every time:
135+
// let decoder = JSONDecoder()
136+
// decoder.keyDecodingStrategy = .convertFromSnakeCase
137+
// return try decoder.decode(User.self, from: data)
138+
}
139+
```
140+
141+
Just use ``JSONDecoder.snakeCase`` to decode and ``JSONEncoder.snakeCase`` to encode instead of configuring a new instance each time!
142+
116143
#### Symmetric Data Cryptography
117144

118145
![](SharePuzzle)
@@ -215,6 +242,11 @@ func downloadPuzzle(from url: URL) async throws -> Puzzle {
215242
- ``Swift/Int/times(_:)``
216243
- ``Swift/Int/timesMake(_:)``
217244

245+
### JSON Coding
246+
247+
- ``Foundation/JSONDecoder/snakeCase``
248+
- ``Foundation/JSONEncoder/snakeCase``
249+
218250
### RandomAccessCollection
219251

220252
- ``Swift/RandomAccessCollection/randomElements(count:)``

0 commit comments

Comments
 (0)