I have a generic REST request:
struct Request<T> {…}
The T
is the return type of the request, for example:
struct Animal {…}
let animalRequest = Request<Animal>
let animal: Animal = sendRequest(animalRequest)
Now I would like to express that the generic type has to conform to Decodable
so that I can decode the JSON response from the server:
struct Request<T> where T: Decodable {…}
struct Animal: Decodable {…}
This makes sense and works – until I arrive at a request that has no response, a Request<Void>
. The compiler is not happy about that one:
Type 'Void' does not conform to protocol 'Decodable'
My mischevious attempt to solve this by adding the Decodable
conformance to Void
was quickly found out by the compiler:
extension Void: Decodable {…} // Error: Non-nominal type 'Void' cannot be extended
It feels right to have the request generic over the return type. Is there a way to make it work with Void
return types? (For example the requests that just create something on the server and don’t return anything.)
A simple workaround is to introduce a custom “no-reply” type that would replace Void
:
struct NoReply: Decodable {}
Conforming Void
to Decodable
is not possible. Void
is just a type alias for an empty tuple, ()
, and tuples cannot conform to protocols at this moment, but they will, eventually.
I found that sometimes other encoded objects of another types can be decoded to NoReply.self. For example custom Error type (enum) can be.
Playground example of this case:
enum MyError: String, Codable {
case general
}
let voidInstance = VoidResult()
let errorInstance = MyError.general
let data1 = try! JSONEncoder().encode(voidInstance)
let data2 = try! JSONEncoder().encode(errorInstance)
let voidInstanceDecoded = try! JSONDecoder().decode(VoidResult.self, from: data1)
//VoidResult as expected
let errorInstanceDecoded = try! JSONDecoder().decode(MyError.self, from: data2)
//MyError.general as expected
let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//VoidResult - NOT EXPECTED
let errorInstanceDecodedFromVoid = try! JSONDecoder().decode(ScreenError.self, from: data1)
//DecodingError.typeMismatch - Expected
So my suggestion is to add "uniqueness to NoReply (zoul's answer)):
struct VoidResult: Codable {
var id = UUID()
}
let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//DecodingError.typeMismatch - Now its fine - as expected
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With