Skip to content

Commit e2523de

Browse files
Merge pull request #1317 from apollographql/fix/json-encoding
Add workaround for Optional JSONEncoding errors
2 parents 06c357b + 52da8bf commit e2523de

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

Sources/Apollo/JSONStandardTypeConversions.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ extension Optional: JSONEncodable {
105105
return NSNull()
106106
case .some(let wrapped as JSONEncodable):
107107
return wrapped.jsonValue
108+
109+
// WORKAROUND: For reasons I don't totally understand, when the underlying type is `Any`,
110+
// even though all of these conform to `JSONEncodable`, the `as JSONEncodable` above
111+
// fails, and we need to handle them individually.
112+
case .some(let wrapped as String):
113+
return wrapped.jsonValue
114+
case .some(let wrapped as Int):
115+
return wrapped.jsonValue
116+
case .some(let wrapped as Double):
117+
return wrapped.jsonValue
118+
case .some(let wrapped as Bool):
119+
return wrapped.jsonValue
120+
case .some(let wrapped as [String: Any?]):
121+
return wrapped.jsonValue
122+
case .some(let wrapped as [Any?]):
123+
return wrapped.jsonValue
108124
default:
109125
fatalError("Optional is only JSONEncodable if Wrapped is")
110126
}
@@ -129,6 +145,16 @@ extension Dictionary: JSONEncodable {
129145
}
130146
}
131147

148+
extension Dictionary: JSONDecodable {
149+
public init(jsonValue value: JSONValue) throws {
150+
guard let dictionary = value as? Dictionary else {
151+
throw JSONDecodingError.couldNotConvert(value: value, to: Dictionary.self)
152+
}
153+
154+
self = dictionary
155+
}
156+
}
157+
132158
extension Array: JSONEncodable {
133159
public var jsonValue: JSONValue {
134160
return map() { element -> (JSONValue) in

Tests/ApolloTests/JSONTests.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,39 @@ class JSONTests: XCTestCase {
3838
XCTAssertFalse(value ~= JSONDecodingError.nullValue)
3939
XCTAssertFalse(value ~= JSONDecodingError.missingValue)
4040
}
41+
42+
func testJSONDictionaryEncodingAndDecoding() throws {
43+
let jsonString = """
44+
{
45+
"a_dict": {
46+
"a_bool": true,
47+
"another_dict" : {
48+
"a_double": 23.1,
49+
"an_int": 8,
50+
"a_string": "LOL wat"
51+
},
52+
"an_array": [
53+
"one",
54+
"two",
55+
"three"
56+
],
57+
"a_null": null
58+
}
59+
}
60+
"""
61+
let data = try XCTUnwrap(jsonString.data(using: .utf8))
62+
let json = try JSONSerializationFormat.deserialize(data: data)
63+
XCTAssertNotNil(json)
64+
65+
let dict = try Dictionary<String, Any?>(jsonValue: json)
66+
XCTAssertNotNil(dict)
67+
68+
let reserialized = try JSONSerializationFormat.serialize(value: dict)
69+
XCTAssertNotNil(reserialized)
70+
71+
let stringFromReserialized = try XCTUnwrap(String(bytes: reserialized, encoding: .utf8))
72+
XCTAssertEqual(stringFromReserialized, """
73+
{"a_dict":{"a_bool":1,"a_null":null,"an_array":["one","two","three"],"another_dict":{"a_double":23.100000000000001,"a_string":"LOL wat","an_int":8}}}
74+
""")
75+
}
4176
}

0 commit comments

Comments
 (0)